🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 13 Min Lesezeit
0

Tutorial: Create Your Own AI Study Buddy

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Ever feel overwhelmed while learning something new? Like you're drowning in information but not actually absorbing anything? We've all been there. Wouldn't it be awesome to have a personalized study companion that understands your level and explains things in a way that clicks? That's exactly what we're going to build together.



This tutorial will show you how to combine the ). It also sets up a UserSession to keep track of the interaction. The generate_prompt method takes the user's request and transforms it into a prompt the API can understand. Finally, generate_text_response sends the prompt to the API and retrieves the AI-generated answer.






Smooth and Responsive: GenerateResponseThread



To avoid making the user wait while the AI is thinking, we'll use a separate thread for API calls:




CODE
class GenerateResponseThread(QThread):
finished = pyqtSignal(str)


def __init__(self, assistant, request):
super().__init__()
self.assistant = assistant
self.request = request


def run(self):
response = self.assistant.generate_text_response(self.request)
self.finished.emit(response)






This GenerateResponseThread, based on PyQt5's QThread, runs the API request in the background, ensuring that the user interface remains responsive.






Personalizing the Experience



Everyone learns differently. To cater to individual preferences, we'll create a PreferencesDialog:




CODE
class PreferencesDialog(QDialog):
def __init__(self, parent=None, preferences=None):
super().__init__(parent)
self.setWindowTitle("Preferences")
self.preferences = preferences or {}


layout = QVBoxLayout()
form_layout = QFormLayout()


self.tone_combo = QComboBox()
self.tone_combo.addItems(["Formal", "Informal"])
form_layout.addRow("Tone of Voice:", self.tone_combo)


self.length_spin = QSpinBox()
self.length_spin.setMinimum(50)
self.length_spin.setMaximum(1000)
self.length_spin.setSingleStep(50)
form_layout.addRow("Response Length (words):", self.length_spin)


self.examples_check = QCheckBox("Include Examples")
form_layout.addRow(self.examples_check)


layout.addLayout(form_layout)


button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
layout.addWidget(button_box)


self.setLayout(layout)
self.set_initial_values()


def set_initial_values(self):
if self.preferences:
self.tone_combo.setCurrentText(self.preferences.get("tone_of_voice", "Formal"))
self.length_spin.setValue(self.preferences.get("response_length", 200))
self.examples_check.setChecked(self.preferences.get("include_examples", True))


def get_preferences(self):
return {
"tone_of_voice": self.tone_combo.currentText(),
"response_length": self.length_spin.value(),
"include_examples": self.examples_check.isChecked(),
"learning_style": self.preferences.get("learning_style", "Visual"),
"topics_of_interest": self.preferences.get("topics_of_interest", [])
}






This dialog allows users to customize settings like the AI's tone of voice, the desired response length, and whether to include examples. This level of customization ensures a more engaging and effective learning experience.






Building the Interface



Finally, let's create the user interface with the EducationalAssistantGUI class:




CODE
class EducationalAssistantGUI(QWidget):
def __init__(self):
super().__init__()
self.assistant = EducationalAssistant()
self.loading_movie = QMovie("path/to/loading.gif")
self.initUI()
self.history = []
self.history_file = "chat_history.json"
self.load_history()
self.assistant.session.preferences = self.load_preferences()
def initUI(self):
self.setWindowTitle("Educational Assistant")
layout = QVBoxLayout()
tabs = QTabWidget()
chat_tab = QWidget()
history_tab = QWidget()
tabs.addTab(chat_tab, "Chat")
tabs.addTab(history_tab, "History")
chat_layout = QVBoxLayout()


query_group = QGroupBox("Query")
query_layout = QVBoxLayout()
self.query_text = QTextEdit()
query_layout.addWidget(self.query_text)
query_group.setLayout(query_layout)
layout.addWidget(query_group)


level_group = QGroupBox("User Level")
level_layout = QHBoxLayout()
self.level_selection = QButtonGroup()


beginner_button = QRadioButton("Beginner")
beginner_button.setChecked(True)
intermediate_button = QRadioButton("Intermediate")
advanced_button = QRadioButton("Advanced")


self.level_selection.addButton(beginner_button)
self.level_selection.addButton(intermediate_button)
self.level_selection.addButton(advanced_button)


level_layout.addWidget(beginner_button)
level_layout.addWidget(intermediate_button)
level_layout.addWidget(advanced_button)
level_group.setLayout(level_layout)
layout.addWidget(level_group)


self.generate_button = QPushButton("Generate Response")
self.generate_button.clicked.connect(self.generate_response)
layout.addWidget(self.generate_button)


response_group = QGroupBox("Response")
response_layout = QVBoxLayout()
self.response_text = QTextEdit()
self.response_text.setReadOnly(True)
response_layout.addWidget(self.response_text)


self.loading_label = QLabel()
self.loading_label.setMovie(self.loading_movie)
self.loading_label.setAlignment(Qt.AlignCenter)
self.loading_label.hide()
response_layout.addWidget(self.loading_label)


response_group.setLayout(response_layout)
layout.addWidget(response_group)


preferences_group = QGroupBox("Preferences")
preferences_layout = QVBoxLayout()


learning_style_label = QLabel("Learning Style:")
self.learning_style_combo = QComboBox()
self.learning_style_combo.addItems(
["Visual", "Auditory", "Kinesthetic", "Reading/Writing"])
preferences_layout.addWidget(learning_style_label)
preferences_layout.addWidget(self.learning_style_combo)
self.learning_style_combo.currentIndexChanged.connect(self.update_preferences)


topics_label = QLabel("Topics of Interest:")
self.topics_checkboxes = {}
topics = ["Mathematics", "Science", "History", "Programming", "Art"]


for topic in topics:
checkbox = QCheckBox(topic)
self.topics_checkboxes[topic] = checkbox
checkbox.stateChanged.connect(self.update_preferences)
preferences_layout.addWidget(checkbox)


preferences_group.setLayout(preferences_layout)
chat_layout.addWidget(preferences_group)
preferences_button = QPushButton("Preferences")
preferences_button.clicked.connect(self.open_preferences_dialog)
chat_layout.addWidget(preferences_button)


chat_tab.setLayout(chat_layout)


history_layout = QVBoxLayout()
search_group = QGroupBox("Search/Filter")
search_layout = QHBoxLayout()
self.search_text = QLineEdit()
self.search_text.setPlaceholderText("Search...")
self.search_text.textChanged.connect(self.filter_history)


self.date_from = QDateEdit(calendarPopup=True)
self.date_from.setDate(datetime.date(2023, 1, 1))
self.date_to = QDateEdit(calendarPopup=True)
self.date_to.setDate(datetime.date.today())


self.date_from.dateChanged.connect(self.filter_history)
self.date_to.dateChanged.connect(self.filter_history)


search_layout.addWidget(QLabel("Keyword:"))
search_layout.addWidget(self.search_text)
search_layout.addWidget(QLabel("From:"))
search_layout.addWidget(self.date_from)
search_layout.addWidget(QLabel("To:"))
search_layout.addWidget(self.date_to)


search_group.setLayout(search_layout)
history_layout.addWidget(search_group)


self.history_list = QListWidget()
history_layout.addWidget(self.history_list)
history_tab.setLayout(history_layout)


self.history_list.itemDoubleClicked.connect(self.load_history_item)


save_button = QPushButton("Save History")
save_button.clicked.connect(self.save_history)
load_button = QPushButton("Load History")
load_button.clicked.connect(self.load_history_from_file)


history_layout.addWidget(save_button)
history_layout.addWidget(load_button)


export_button = QPushButton("Export History")
export_button.clicked.connect(self.export_history)
history_layout.addWidget(export_button)


history_tab.setLayout(history_layout)


self.loading_label = QLabel()
self.loading_label.setMovie(self.loading_movie)
self.loading_label.setAlignment(Qt.AlignCenter)
self.loading_label.hide()
response_layout.addWidget(self.loading_label)


layout.addWidget(tabs)
self.setLayout(layout)
def generate_response(self):
query = self.query_text.toPlainText()
if not query.strip():
QMessageBox.warning(self, "Error", "Please enter a query.")
return
level = 'beginner' if self.level_selection.buttons()[0].isChecked() else \
'intermediate' if self.level_selection.buttons()[1].isChecked() else "advanced"


preferences = self.assistant.session.preferences
request = UserRequest(query=query, user_level=level, preferences=preferences)


self.generate_button.setEnabled(False)
self.loading_label.show()
self.loading_movie.start()


self.thread = GenerateResponseThread(self.assistant, request)
self.thread.finished.connect(self.display_response)
self.thread.start()
self.response_text.setText("Loading...")
def display_response(self, response):
self.generate_button.setEnabled(True)
self.loading_label.hide()
self.loading_movie.stop()


if "Error generating text response:" in response:
QMessageBox.critical(self, "Error", response.replace("Error generating text response:", ""))
self.response_text.clear()
else:
self.response_text.setText(response)
self.update_history(self.query_text.toPlainText(), response)
self.query_text.clear()
def update_preferences(self):
preferences = {}


preferences["learning_style"] = self.learning_style_combo.currentText()


selected_topics = [topic for topic, checkbox in self.topics_checkboxes.items() if checkbox.isChecked()]
preferences["topics_of_interest"] = selected_topics
self.assistant.session.preferences = preferences
self.save_preferences()
def save_preferences(self):
try:
with open("user_preferences.json", "w") as f:
json.dump(self.assistant.session.preferences, f, indent=4)
except Exception as e:
print(f"Error saving preferences: {e}")
def load_preferences(self):
try:
with open("user_preferences.json", "r") as f:
return json.load(f)
except FileNotFoundError:
return {}
except json.JSONDecodeError as e:
print(f"Error loading preferences: {e}")
return {}
def open_preferences_dialog(self):
dialog = PreferencesDialog(self, self.assistant.session.preferences)
if dialog.exec_() == QDialog.Accepted:
self.assistant.session.preferences = dialog.get_preferences()
self.save_preferences()
def update_history(self, query, response):
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
item = QListWidgetItem(f"{timestamp} - {query[:20]}...")
item.setData(Qt.UserRole, {"query": query, "response": response})
self.history_list.addItem(item)
self.history.append({"query": query, "response": response, "timestamp": timestamp})
def load_history_item(self, item):
data = item.data(Qt.UserRole)
self.query_text.setText(data["query"])
self.response_text.setText(data["response"])
def save_history(self):
try:
with open(self.history_file, "w") as f:
json.dump(self.history, f, indent=4)
except Exception as e:
print(f"Error saving history: {e}")
def load_history(self):
try:
with open(self.history_file, "r") as f:
self.history = json.load(f)
self.update_history_list()
except FileNotFoundError:
pass
except json.JSONDecodeError as e:
print(f"Error loading history: Invalid JSON format: {e}")
def load_history_from_file(self):
options = QFileDialog.Options()
filename, _ = QFileDialog.getOpenFileName(self, "Load Chat History", "", "JSON Files (*.json);;All Files (*)",
options=options)
if filename:
try:
with open(filename, "r") as f:
self.history = json.load(f)
self.update_history_list()
except json.JSONDecodeError as e:
print(f"Error loading history from file: Invalid JSON format: {e}")
def filter_history(self):
self.update_history_list(filter_text=self.search_text.text(),
date_from=self.date_from.date().toPyDate(),
date_to=self.date_to.date().toPyDate())
def export_history(self):
options = QFileDialog.Options()
filename, _ = QFileDialog.getSaveFileName(self, "Export Chat History", "",
"Text Files (*.txt);;CSV Files (*.csv)", options=options)
if filename:
try:
with open(filename, "w", encoding="utf-8") as f:
if filename.endswith(".csv"):
f.write("Timestamp,Query,Response\n")
for item in self.history:
timestamp = item.get("timestamp", "")
query = item.get("query", "").replace(",", "\",\"")
response = item.get("response", "").replace(",", "\",\"")
f.write(f'"{timestamp}","{query}","{response}"\n')
else:
for item in self.history:
f.write(
f"{item.get('timestamp', '')}\nQuery: {item.get('query', '')}\nResponse: {item.get('response', '')}\n\n")
QMessageBox.information(self, "Success", "History exported successfully!")


except Exception as e:
QMessageBox.critical(self, "Error", f"Error exporting history: {str(e)}")
def update_history_list(self, filter_text="", date_from=None, date_to=None):
self.history_list.clear()
for item_data in self.history:
timestamp_str = item_data.get("timestamp", "")
query = item_data.get("query", "")


try:
timestamp = datetime.datetime.fromisoformat(timestamp_str).date()


if date_from and timestamp < date_from:
continue
if date_to and timestamp > date_to:
continue


except ValueError:
pass


if filter_text.lower() not in query.lower():
continue


item = QListWidgetItem(f"{timestamp_str} - {query[:20]}...")
item.setData(Qt.UserRole, item_data)
self.history_list.addItem(item)






This class builds the main window, which includes two tabs: "Chat" and "History." The "Chat" tab allows users to enter their queries, select their level, and see the AI's responses. The "History" tab displays past conversations, offering search and export functionalities.






Launching Your AI Study Buddy



Now, let's bring our creation to life:




CODE
if __name__ == "__main__":
app = QApplication([])
window = EducationalAssistantGUI()
window.show()
app.exec_()






Congratulations! You've built your own personalized AI learning assistant.






Now that you have a working app, think about how you could make it even better! The BotHub API offers a lot of flexibility. Instead of just text responses, you could integrate image generation or speech transcription. BotHub also gives you access to multiple AI models, allowing you to choose the best one for different tasks. Imagine your assistant being able to summarize complex topics, translate languages, or even generate practice quizzes! The possibilities are vast. You've built a solid foundation; now go forth and explore!

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Tutorial: Create Your Own AI Study Buddy

Thematisch verwandte Begriffe: Tutorial, Create, Your, Study · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...