| | """ |
| | modules/memory.py - Gesprächsgedächtnis-Modul für den Dr. Franz Psychochatbot |
| | |
| | Dieses Modul verwaltet die Konversationshistorie und extrahiert wichtige Informationen: |
| | - Speichern und Abrufen der Gesprächshistorie |
| | - Extraktion wichtiger Informationen |
| | - Bereitstellung von Kontext für neue Antworten |
| | """ |
| |
|
| | from typing import List, Dict, Any, Optional |
| | import re |
| | import random |
| |
|
| | class Memory: |
| | """Klasse zur Verwaltung des Gesprächsgedächtnisses""" |
| | |
| | def _extract_information(self, exchange: Dict[str, Any]) -> None: |
| | """ |
| | Extrahiert wichtige Informationen aus einem Gesprächsaustausch |
| | |
| | Args: |
| | exchange: Dictionary mit User-Input und Bot-Response |
| | |
| | Raises: |
| | ValueError: Wenn der Exchange ungültig ist |
| | """ |
| | if not isinstance(exchange, dict): |
| | raise ValueError("exchange must be a dictionary") |
| | if "user_input" not in exchange or not isinstance(exchange["user_input"], str): |
| | raise ValueError("exchange must contain valid user_input") |
| | |
| | user_input = exchange["user_input"].lower() |
| | analysis = exchange["analysis"] |
| | |
| | try: |
| | |
| | self._analyze_defense_mechanisms(user_input) |
| | self._analyze_transference_patterns(user_input) |
| | self._analyze_symbolic_patterns(user_input) |
| | self._update_association_network(user_input) |
| | self._update_escalation_levels(analysis) |
| | |
| | |
| | for word in user_input.split(): |
| | if word not in ["ich", "du", "wir", "sie", "er", "es"]: |
| | self.extracted_info["mentioned_people"].add(word) |
| | |
| | except Exception as e: |
| | raise ValueError(f"Failed to extract information: {str(e)}") |
| | |
| | def add_exchange(self, user_input: str, bot_response: str, analysis: Optional[Dict[str, Any]] = None) -> None: |
| | """ |
| | Fügt einen Gesprächsaustausch zum Gedächtnis hinzu |
| | |
| | Args: |
| | user_input: Die Eingabe des Nutzers |
| | bot_response: Die Antwort des Chatbots |
| | analysis: Optional, Analyseergebnisse des Analyzers |
| | """ |
| | exchange = { |
| | "user_input": user_input, |
| | "bot_response": bot_response, |
| | "analysis": analysis or {} |
| | } |
| | |
| | self.conversation_history.append(exchange) |
| | |
| | |
| | if len(self.conversation_history) > self.max_history_length: |
| | self.conversation_history = self.conversation_history[-self.max_history_length:] |
| | |
| | |
| | self._extract_information(exchange) |
| | |
| | def get_history(self, limit: Optional[int] = None) -> List[Dict[str, Any]]: |
| | """ |
| | Gibt die Konversationshistorie zurück |
| | |
| | Args: |
| | limit: Optional, maximale Anzahl der zurückzugebenden Einträge |
| | |
| | Returns: |
| | Liste der Gesprächsaustausche |
| | """ |
| | if limit is None or limit >= len(self.conversation_history): |
| | return self.conversation_history |
| | else: |
| | return self.conversation_history[-limit:] |
| | |
| | def format_for_prompt(self, limit: Optional[int] = None) -> str: |
| | """ |
| | Formatiert die Historie für den Prompt |
| | |
| | Args: |
| | limit: Optional, maximale Anzahl der zu formatierenden Einträge |
| | |
| | Returns: |
| | Formatierte Historie als String |
| | """ |
| | history = self.get_history(limit) |
| | formatted = "" |
| | |
| | for exchange in history: |
| | formatted += f"User: {exchange['user_input']}\n" |
| | formatted += f"Dr. Franz: {exchange['bot_response']}\n" |
| | |
| | return formatted |
| | |
| | def get_relevant_context(self) -> str: |
| | """ |
| | Generiert erweiterten psychoanalytischen Kontext für die nächste Antwort |
| | |
| | Returns: |
| | Detaillierte Kontextinformationen als String |
| | """ |
| | context_parts = [] |
| | |
| | |
| | if self.extracted_info["recurring_themes"]: |
| | top_themes = sorted( |
| | self.extracted_info["recurring_themes"].items(), |
| | key=lambda x: x[1], |
| | reverse=True |
| | )[:2] |
| | context_parts.append(f"Wiederkehrende Themen: {', '.join(theme for theme, _ in top_themes)}") |
| | |
| | |
| | if self.extracted_info["defense_mechanisms"]: |
| | active_defenses = [k for k, v in self.extracted_info["defense_mechanisms"].items() if v > 0] |
| | if active_defenses: |
| | context_parts.append(f"Aktive Abwehrmechanismen: {', '.join(active_defenses)}") |
| | context_parts.append("Der Patient zeigt überwiegend negative Emotionen.") |
| | elif recent_emotions.count("positive") >= 2: |
| | context_parts.append("Der Patient zeigt ungewöhnlich positive Emotionen, was auf Verdrängung hindeuten könnte.") |
| | |
| | |
| | if self.extracted_info["mentioned_people"]: |
| | people = list(self.extracted_info["mentioned_people"]) |
| | if people: |
| | person = random.choice(people) |
| | context_parts.append(f"Der Patient hat {person} erwähnt. Beziehe dich darauf, wenn passend.") |
| | |
| | |
| | if len(self.conversation_history) > 2: |
| | old_exchange = random.choice(self.conversation_history[:-2]) |
| | if "analysis" in old_exchange and "themes" in old_exchange["analysis"]: |
| | old_theme = random.choice(old_exchange["analysis"]["themes"]) |
| | context_parts.append(f"Greife bei Gelegenheit das frühere Thema '{old_theme}' wieder auf.") |
| | |
| | return " ".join(context_parts) |
| | |
| | def _analyze_defense_mechanisms(self, text: str) -> None: |
| | """Analysiert aktive Abwehrmechanismen im Text""" |
| | for mechanism, pattern in self.analysis_patterns["defense"].items(): |
| | if re.search(pattern, text): |
| | self.extracted_info["defense_mechanisms"][mechanism] = self.extracted_info["defense_mechanisms"].get(mechanism, 0) + 1 |
| | |
| | def _analyze_transference_patterns(self, text: str) -> None: |
| | """Analysiert Transfersituationen im Text""" |
| | for category, pattern in self.analysis_patterns["transference"].items(): |
| | if re.search(pattern, text): |
| | self.extracted_info["transference_patterns"].append(category) |
| | |
| | def _analyze_symbolic_patterns(self, text: str) -> None: |
| | """Analysiert symbolische Muster im Text""" |
| | for symbol, pattern in self.analysis_patterns["symbolic"].items(): |
| | if re.search(pattern, text): |
| | self.extracted_info["symbolic_patterns"][symbol] = self.extracted_info["symbolic_patterns"].get(symbol, 0) + 1 |
| | |
| | def _update_association_network(self, text: str) -> None: |
| | """Aktualisiert das Assoziationsnetzwerk""" |
| | words = text.split() |
| | for i, word in enumerate(words): |
| | if word not in self.extracted_info["association_network"]: |
| | self.extracted_info["association_network"][word] = {} |
| | |
| | |
| | if i > 0: |
| | prev_word = words[i-1] |
| | self.extracted_info["association_network"][word][prev_word] = self.extracted_info["association_network"][word].get(prev_word, 0) + 1 |
| | if i < len(words) - 1: |
| | next_word = words[i+1] |
| | self.extracted_info["association_network"][word][next_word] = self.extracted_info["association_network"][word].get(next_word, 0) + 1 |
| | |
| | def _update_escalation_levels(self, analysis: Dict[str, Any]) -> None: |
| | """Aktualisiert die Escalation Levels basierend auf der Analyse""" |
| | intensity = analysis.get("intensity", 0) |
| | |
| | |
| | if analysis.get("emotion") == "negative": |
| | self.extracted_info["escalation_levels"]["emotional"] = min(5, self.extracted_info["escalation_levels"]["emotional"] + intensity) |
| | else: |
| | self.extracted_info["escalation_levels"]["emotional"] = max(0, self.extracted_info["escalation_levels"]["emotional"] - 1) |
| | |
| | |
| | if "defense_mechanisms" in analysis: |
| | self.extracted_info["escalation_levels"]["cognitive"] = min(5, self.extracted_info["escalation_levels"]["cognitive"] + len(analysis["defense_mechanisms"])) |
| | else: |
| | self.extracted_info["escalation_levels"]["cognitive"] = max(0, self.extracted_info["escalation_levels"]["cognitive"] - 1) |
| | |
| | |
| | if "behavioral_patterns" in analysis: |
| | self.extracted_info["escalation_levels"]["behavioral"] = min(5, self.extracted_info["escalation_levels"]["behavioral"] + len(analysis["behavioral_patterns"])) |
| | else: |
| | self.extracted_info["escalation_levels"]["behavioral"] = max(0, self.extracted_info["escalation_levels"]["behavioral"] - 1) |
| | |
| | def _extract_information(self, exchange: Dict[str, Any]) -> None: |
| | """Extrahiert wichtige Informationen aus einem Gesprächsaustausch""" |
| | user_input = exchange["user_input"].lower() |
| | analysis = exchange["analysis"] |
| | |
| | |
| | self._analyze_defense_mechanisms(user_input) |
| | self._analyze_transference_patterns(user_input) |
| | self._analyze_symbolic_patterns(user_input) |
| | self._update_association_network(user_input) |
| | self._update_escalation_levels(analysis) |
| | |
| | |
| | for word in user_input.split(): |
| | if word not in ["ich", "du", "wir", "sie", "er", "es"]: |
| | self.extracted_info["mentioned_people"].add(word) |
| | |
| | |
| | for theme in analysis.get("themes", []): |
| | self.extracted_info["recurring_themes"][theme] = self.extracted_info["recurring_themes"].get(theme, 0) + 1 |
| | |
| | |
| | emotion = analysis.get("emotion", "neutral") |
| | self.extracted_info["emotional_patterns"].append({ |
| | "emotion": emotion, |
| | "timestamp": time.time(), |
| | "intensity": analysis.get("intensity", 0) |
| | }) |
| | |
| | |
| | self.extracted_info["last_exchange"] = { |
| | "time": time.time(), |
| | "intensity": analysis.get("intensity", 0), |
| | "patterns": analysis.get("patterns", []) |
| | } |