Frajosgro commited on
Commit
b702d72
·
verified ·
1 Parent(s): 01f0578

Upload 4 files

Browse files
Files changed (4) hide show
  1. modules/analyzer.py +173 -0
  2. modules/interface.py +181 -0
  3. modules/memory.py +218 -0
  4. modules/persona.py +141 -0
modules/analyzer.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ modules/analyzer.py - Emotionsanalyse-Modul für den Dr. Franz Psychochatbot
3
+
4
+ Dieses Modul analysiert die Nutzereingaben, um Emotionen und Themen zu erkennen:
5
+ - Emotionserkennung über API
6
+ - Themenidentifikation
7
+ - Anpassung der Antwortstrategien
8
+ """
9
+
10
+ import requests
11
+ import random
12
+ from typing import Dict, Any, Optional, List, Tuple
13
+
14
+ # Importieren der Konfiguration
15
+ import config
16
+
17
+ class Analyzer:
18
+ """Klasse zur Analyse von Nutzereingaben"""
19
+
20
+ def __init__(self, api_token: str = config.API_TOKEN):
21
+ """Initialisiert den Analyzer mit API-Token"""
22
+ self.api_token = api_token
23
+ # Einfache Wörterbücher für die Stimmungsanalyse ohne ML-Bibliotheken
24
+ self.positive_words = [
25
+ "glücklich", "froh", "zufrieden", "gut", "großartig", "toll", "wunderbar",
26
+ "fantastisch", "begeistert", "erfreut", "dankbar", "hoffnungsvoll", "optimistisch"
27
+ ]
28
+ self.negative_words = [
29
+ "traurig", "wütend", "verärgert", "frustriert", "enttäuscht", "ängstlich",
30
+ "besorgt", "verzweifelt", "hoffnungslos", "deprimiert", "unglücklich", "schlecht",
31
+ "hasse", "Angst", "Sorge", "Problem", "schwierig", "schlimm", "schrecklich"
32
+ ]
33
+ self.neutral_words = [
34
+ "denke", "glaube", "meine", "verstehe", "sehe", "höre", "fühle",
35
+ "normal", "gewöhnlich", "alltäglich", "regelmäßig"
36
+ ]
37
+
38
+ def analyze_emotion(self, text: str) -> str:
39
+ """
40
+ Analysiert die Emotion in einem Text ohne ML-Bibliotheken
41
+
42
+ Args:
43
+ text: Der zu analysierende Text
44
+
45
+ Returns:
46
+ "positive", "negative" oder "neutral"
47
+ """
48
+ text = text.lower()
49
+
50
+ # Zählen der positiven, negativen und neutralen Wörter
51
+ positive_count = sum(1 for word in self.positive_words if word in text)
52
+ negative_count = sum(1 for word in self.negative_words if word in text)
53
+ neutral_count = sum(1 for word in self.neutral_words if word in text)
54
+
55
+ # Gewichtung: Negative Emotionen haben höhere Priorität
56
+ negative_count *= 1.5
57
+
58
+ # Bestimmung der dominanten Emotion
59
+ if negative_count > positive_count:
60
+ return "negative"
61
+ elif positive_count > negative_count and positive_count > neutral_count:
62
+ return "positive"
63
+ else:
64
+ return "neutral"
65
+
66
+ def analyze_themes(self, text: str) -> Dict[str, Any]:
67
+ """
68
+ Identifiziert psychologisch relevante Themen und ihre manipulative Nutzung
69
+
70
+ Args:
71
+ text: Der zu analysierende Text
72
+
73
+ Returns:
74
+ Dictionary mit Themen und manipulativen Aspekten
75
+ """
76
+ text = text.lower()
77
+ analysis = {
78
+ "themes": [],
79
+ "manipulative_aspects": {},
80
+ "vulnerabilities": []
81
+ }
82
+
83
+ # Themen-Wörterbuch mit Schlüsselwörtern
84
+ theme_keywords = {
85
+ "Familie": {
86
+ "keywords": ["familie", "mutter", "vater", "eltern", "kind"],
87
+ "manipulation": "Die familiären Beziehungen sind ein perfektes Terrain für Projektion und Verdrängung."
88
+ },
89
+ "Beziehungen": {
90
+ "keywords": ["beziehung", "partner", "freund", "ehe"],
91
+ "manipulation": "Beziehungen sind ideale Spiegel für unbewusste Konflikte."
92
+ },
93
+ "Selbstwert": {
94
+ "keywords": ["selbstwert", "stolz", "scham"],
95
+ "manipulation": "Der Selbstwert ist empfänglich für Schuldzuweisungen und Gaslighting."
96
+ },
97
+ "Ängste": {
98
+ "keywords": ["angst", "sorge", "panik"],
99
+ "manipulation": "Ängste können verstärkt werden, um Kontrolle auszuüben."
100
+ }
101
+ }
102
+
103
+ # Themen identifizieren und manipulative Aspekte analysieren
104
+ for theme, data in theme_keywords.items():
105
+ if any(keyword in text for keyword in data["keywords"]):
106
+ analysis["themes"].append(theme)
107
+ analysis["manipulative_aspects"][theme] = data["manipulation"]
108
+
109
+ # Identifizierung von Verwundbarkeiten
110
+ if "schuld" in text or "scham" in text:
111
+ analysis["vulnerabilities"].append(f"{theme}_guilt")
112
+ if "angst" in text:
113
+ analysis["vulnerabilities"].append(f"{theme}_fear")
114
+
115
+ return analysis
116
+
117
+ def analyze_complexity(self, text: str) -> int:
118
+ """
119
+ Bewertet die Komplexität der Nutzereingabe (1-5)
120
+
121
+ Args:
122
+ text: Der zu analysierende Text
123
+
124
+ Returns:
125
+ Komplexitätsstufe von 1 (einfach) bis 5 (komplex)
126
+ """
127
+ # Einfache Heuristiken für die Komplexitätsbewertung
128
+ words = text.split()
129
+ word_count = len(words)
130
+ avg_word_length = sum(len(word) for word in words) / max(1, word_count)
131
+ sentence_count = text.count('.') + text.count('!') + text.count('?')
132
+
133
+ # Komplexe Wörter und Phrasen
134
+ complex_indicators = [
135
+ "weil", "obwohl", "trotzdem", "dennoch", "allerdings",
136
+ "einerseits", "andererseits", "jedoch", "nichtsdestotrotz",
137
+ "möglicherweise", "vielleicht", "wahrscheinlich", "vermutlich"
138
+ ]
139
+
140
+ complex_count = sum(1 for word in complex_indicators if word in text.lower())
141
+
142
+ # Berechnung der Komplexität
143
+ if word_count < 5:
144
+ return 1
145
+ elif word_count < 15 and complex_count == 0:
146
+ return 2
147
+ elif word_count < 30 and complex_count <= 1:
148
+ return 3
149
+ elif word_count < 50 and complex_count <= 2:
150
+ return 4
151
+ else:
152
+ return 5
153
+
154
+ def get_analysis_result(self, text: str) -> Dict[str, Any]:
155
+ """
156
+ Führt eine vollständige Analyse des Textes durch
157
+
158
+ Args:
159
+ text: Der zu analysierende Text
160
+
161
+ Returns:
162
+ Dictionary mit Analyseergebnissen
163
+ """
164
+ emotion = self.analyze_emotion(text)
165
+ themes = self.analyze_themes(text)
166
+ complexity = self.analyze_complexity(text)
167
+
168
+ return {
169
+ "emotion": emotion,
170
+ "themes": themes,
171
+ "complexity": complexity,
172
+ "suggested_intensity": min(complexity + (1 if emotion == "negative" else 0), 5)
173
+ }
modules/interface.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ modules/interface.py - UI-Komponenten-Modul für den Dr. Franz Psychochatbot
3
+
4
+ Dieses Modul definiert die Benutzeroberfläche des Chatbots:
5
+ - Gradio-Interface-Komponenten
6
+ - Benutzererfahrung optimieren
7
+ - Responsive Design sicherstellen
8
+ """
9
+
10
+ import gradio as gr
11
+ from typing import List, Dict, Any, Tuple, Callable, Optional
12
+ import random
13
+ import time
14
+
15
+ # Importieren der Konfiguration
16
+ import config
17
+
18
+ class Interface:
19
+ """Klasse zur Verwaltung der Benutzeroberfläche"""
20
+
21
+ def __init__(self, chat_function: Callable[[str], str], clear_function: Callable[[], Tuple[None, str]]):
22
+ """
23
+ Initialisiert die Interface-Komponente
24
+
25
+ Args:
26
+ chat_function: Die Hauptfunktion für die Chatbot-Logik
27
+ clear_function: Die Funktion zum Zurücksetzen der Konversation
28
+ """
29
+ self.chat_function = chat_function
30
+ self.clear_function = clear_function
31
+ self.theme = gr.themes.Soft(
32
+ primary_hue=config.UI_PRIMARY_COLOR,
33
+ secondary_hue=config.UI_SECONDARY_COLOR
34
+ )
35
+
36
+ def create_interface(self) -> gr.Blocks:
37
+ """
38
+ Erstellt das Gradio-Interface
39
+
40
+ Returns:
41
+ Das konfigurierte Gradio-Interface
42
+ """
43
+ with gr.Blocks(theme=self.theme) as demo:
44
+ # Header-Bereich
45
+ with gr.Row():
46
+ with gr.Column():
47
+ gr.Markdown(f"# {config.CHATBOT_EMOJI} {config.CHATBOT_TITLE}")
48
+ gr.Markdown(f"*{config.CHATBOT_DESCRIPTION}*")
49
+
50
+ # Hauptbereich
51
+ with gr.Row():
52
+ # Chat-Bereich (linke Spalte)
53
+ with gr.Column(scale=4):
54
+ chatbot = gr.Chatbot(
55
+ height=config.UI_CHATBOX_HEIGHT,
56
+ label="Therapiesitzung",
57
+ elem_id="chatbox",
58
+ show_label=True,
59
+ avatar_images=("👤", "🧠")
60
+ )
61
+
62
+ # Eingabebereich
63
+ with gr.Row():
64
+ user_input = gr.Textbox(
65
+ placeholder="Teilen Sie Ihre Gedanken mit Dr. Franz...",
66
+ label="Ihre Aussage",
67
+ scale=4,
68
+ elem_id="user-input",
69
+ show_label=True
70
+ )
71
+ send = gr.Button("Senden", variant="primary", elem_id="send-btn")
72
+
73
+ # Aktionsbereich
74
+ with gr.Row():
75
+ clear = gr.Button("Neue Sitzung", elem_id="clear-btn")
76
+ thinking = gr.HTML(
77
+ "<div id='thinking-indicator' style='display:none; text-align:center;'>"
78
+ "<i>Dr. Franz denkt nach...</i></div>"
79
+ )
80
+
81
+ # Informationsbereich (rechte Spalte)
82
+ with gr.Column(scale=1):
83
+ gr.Markdown(f"### Über {config.CHATBOT_NAME}")
84
+ gr.Markdown("""
85
+ Dr. Franz ist ein experimenteller KI-Psychoanalytiker, der Ihre Gedanken und Emotionen analysiert.
86
+
87
+ **Hinweis:** Dieser Chatbot dient nur der Unterhaltung und ersetzt keine professionelle psychologische Beratung.
88
+
89
+ **Funktionen:**
90
+ - Psychoanalytische Gesprächsführung
91
+ - Emotionsanalyse
92
+ - Kontextbewusstsein
93
+
94
+ Dieser Chatbot verwendet die HuggingFace Inference API.
95
+ """)
96
+
97
+ # Optionaler Bereich für Stimmungsanzeige
98
+ mood_indicator = gr.HTML(
99
+ "<div id='mood-container' style='text-align:center; margin-top:20px;'>"
100
+ "<div id='mood-label'>Therapeutische Intensität</div>"
101
+ "<div id='mood-indicator' style='font-size:24px;'>😐</div>"
102
+ "</div>"
103
+ )
104
+
105
+ # JavaScript für dynamische UI-Elemente
106
+ gr.HTML("""
107
+ <script>
108
+ // Funktion zum Anzeigen des "Denkt nach..."-Indikators
109
+ function showThinking() {
110
+ document.getElementById('thinking-indicator').style.display = 'block';
111
+
112
+ // Zufällige Stimmung anzeigen
113
+ const moods = ['🧐', '🤔', '😑', '😒', '🙄'];
114
+ document.getElementById('mood-indicator').innerText = moods[Math.floor(Math.random() * moods.length)];
115
+ }
116
+
117
+ // Funktion zum Ausblenden des "Denkt nach..."-Indikators
118
+ function hideThinking() {
119
+ document.getElementById('thinking-indicator').style.display = 'none';
120
+
121
+ // Zufällige Stimmung anzeigen
122
+ const moods = ['😏', '🧐', '😐', '🤨', '😌'];
123
+ document.getElementById('mood-indicator').innerText = moods[Math.floor(Math.random() * moods.length)];
124
+ }
125
+
126
+ // Event-Listener für den Senden-Button
127
+ document.addEventListener('DOMContentLoaded', function() {
128
+ const sendBtn = document.getElementById('send-btn');
129
+ if (sendBtn) {
130
+ sendBtn.addEventListener('click', showThinking);
131
+ }
132
+
133
+ // Beobachter für Änderungen im Chat-Bereich
134
+ const observer = new MutationObserver(function(mutations) {
135
+ hideThinking();
136
+ });
137
+
138
+ // Beobachtung starten, sobald das Element verfügbar ist
139
+ setTimeout(function() {
140
+ const chatbox = document.getElementById('chatbox');
141
+ if (chatbox) {
142
+ observer.observe(chatbox, { childList: true, subtree: true });
143
+ }
144
+ }, 1000);
145
+ });
146
+ </script>
147
+ """)
148
+
149
+ # Event-Handler
150
+ def respond(msg, history):
151
+ if not msg.strip():
152
+ return history, ""
153
+
154
+ # Kurze Verzögerung für natürlicheres Gefühl
155
+ time.sleep(0.5)
156
+
157
+ # Chat-Funktion aufrufen
158
+ reply = self.chat_function(msg)
159
+
160
+ history = history or []
161
+ history.append((msg, reply))
162
+ return history, ""
163
+
164
+ send.click(respond, inputs=[user_input, chatbot], outputs=[chatbot, user_input])
165
+ user_input.submit(respond, inputs=[user_input, chatbot], outputs=[chatbot, user_input])
166
+ clear.click(self.clear_function, inputs=[], outputs=[chatbot, user_input])
167
+
168
+ return demo
169
+
170
+ def launch_interface(self, demo: gr.Blocks) -> None:
171
+ """
172
+ Startet das Gradio-Interface
173
+
174
+ Args:
175
+ demo: Das zu startende Gradio-Interface
176
+ """
177
+ demo.launch(
178
+ server_name=config.SERVER_NAME,
179
+ share=config.SHARE,
180
+ show_error=config.SHOW_ERROR
181
+ )
modules/memory.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ modules/memory.py - Gesprächsgedächtnis-Modul für den Dr. Franz Psychochatbot
3
+
4
+ Dieses Modul verwaltet die Konversationshistorie und extrahiert wichtige Informationen:
5
+ - Speichern und Abrufen der Gesprächshistorie
6
+ - Extraktion wichtiger Informationen
7
+ - Bereitstellung von Kontext für neue Antworten
8
+ """
9
+
10
+ from typing import List, Dict, Any, Optional
11
+ import re
12
+ import random
13
+
14
+ class Memory:
15
+ """Klasse zur Verwaltung des Gesprächsgedächtnisses"""
16
+
17
+ def __init__(self, max_history_length: int = 10):
18
+ """Initialisiert das Gedächtnis mit maximaler Historienlänge"""
19
+ self.max_history_length = max_history_length
20
+ self.conversation_history = []
21
+ self.extracted_info = {
22
+ "mentioned_people": set(),
23
+ "mentioned_events": set(),
24
+ "recurring_themes": {},
25
+ "emotional_patterns": []
26
+ }
27
+
28
+ def add_exchange(self, user_input: str, bot_response: str, analysis: Optional[Dict[str, Any]] = None) -> None:
29
+ """
30
+ Fügt einen Gesprächsaustausch zum Gedächtnis hinzu
31
+
32
+ Args:
33
+ user_input: Die Eingabe des Nutzers
34
+ bot_response: Die Antwort des Chatbots
35
+ analysis: Optional, Analyseergebnisse des Analyzers
36
+ """
37
+ exchange = {
38
+ "user_input": user_input,
39
+ "bot_response": bot_response,
40
+ "analysis": analysis or {}
41
+ }
42
+
43
+ self.conversation_history.append(exchange)
44
+
45
+ # Begrenzung der Historienlänge
46
+ if len(self.conversation_history) > self.max_history_length:
47
+ self.conversation_history = self.conversation_history[-self.max_history_length:]
48
+
49
+ # Extraktion wichtiger Informationen
50
+ self._extract_information(exchange)
51
+
52
+ def get_history(self, limit: Optional[int] = None) -> List[Dict[str, Any]]:
53
+ """
54
+ Gibt die Konversationshistorie zurück
55
+
56
+ Args:
57
+ limit: Optional, maximale Anzahl der zurückzugebenden Einträge
58
+
59
+ Returns:
60
+ Liste der Gesprächsaustausche
61
+ """
62
+ if limit is None or limit >= len(self.conversation_history):
63
+ return self.conversation_history
64
+ else:
65
+ return self.conversation_history[-limit:]
66
+
67
+ def format_for_prompt(self, limit: Optional[int] = None) -> str:
68
+ """
69
+ Formatiert die Historie für den Prompt
70
+
71
+ Args:
72
+ limit: Optional, maximale Anzahl der zu formatierenden Einträge
73
+
74
+ Returns:
75
+ Formatierte Historie als String
76
+ """
77
+ history = self.get_history(limit)
78
+ formatted = ""
79
+
80
+ for exchange in history:
81
+ formatted += f"User: {exchange['user_input']}\n"
82
+ formatted += f"Dr. Franz: {exchange['bot_response']}\n"
83
+
84
+ return formatted
85
+
86
+ def get_relevant_context(self) -> str:
87
+ """
88
+ Generiert erweiterten psychoanalytischen Kontext für die nächste Antwort
89
+
90
+ Returns:
91
+ Detaillierte Kontextinformationen als String
92
+ """
93
+ context_parts = []
94
+
95
+ # Wiederkehrende Themen
96
+ if self.extracted_info["recurring_themes"]:
97
+ top_themes = sorted(
98
+ self.extracted_info["recurring_themes"].items(),
99
+ key=lambda x: x[1],
100
+ reverse=True
101
+ )[:2]
102
+ context_parts.append(f"Wiederkehrende Themen: {', '.join(theme for theme, _ in top_themes)}")
103
+
104
+ # Abwehrmechanismen
105
+ if self.extracted_info["defense_mechanisms"]:
106
+ active_defenses = [k for k, v in self.extracted_info["defense_mechanisms"].items() if v > 0]
107
+ if active_defenses:
108
+ context_parts.append(f"Aktive Abwehrmechanismen: {', '.join(active_defenses)}")
109
+ context_parts.append("Der Patient zeigt überwiegend negative Emotionen.")
110
+ elif recent_emotions.count("positive") >= 2:
111
+ context_parts.append("Der Patient zeigt ungewöhnlich positive Emotionen, was auf Verdrängung hindeuten könnte.")
112
+
113
+ # Erwähnte Personen einbeziehen
114
+ if self.extracted_info["mentioned_people"]:
115
+ people = list(self.extracted_info["mentioned_people"])
116
+ if people:
117
+ person = random.choice(people)
118
+ context_parts.append(f"Der Patient hat {person} erwähnt. Beziehe dich darauf, wenn passend.")
119
+
120
+ # Zufällig ein früheres Thema aufgreifen
121
+ if len(self.conversation_history) > 2:
122
+ old_exchange = random.choice(self.conversation_history[:-2])
123
+ if "analysis" in old_exchange and "themes" in old_exchange["analysis"]:
124
+ old_theme = random.choice(old_exchange["analysis"]["themes"])
125
+ context_parts.append(f"Greife bei Gelegenheit das frühere Thema '{old_theme}' wieder auf.")
126
+
127
+ return " ".join(context_parts)
128
+
129
+ def _analyze_defense_mechanisms(self, text: str) -> None:
130
+ """Analysiert aktive Abwehrmechanismen im Text"""
131
+ for mechanism, pattern in self.analysis_patterns["defense"].items():
132
+ if re.search(pattern, text):
133
+ self.extracted_info["defense_mechanisms"][mechanism] = self.extracted_info["defense_mechanisms"].get(mechanism, 0) + 1
134
+
135
+ def _analyze_transference_patterns(self, text: str) -> None:
136
+ """Analysiert Transfersituationen im Text"""
137
+ for category, pattern in self.analysis_patterns["transference"].items():
138
+ if re.search(pattern, text):
139
+ self.extracted_info["transference_patterns"].append(category)
140
+
141
+ def _analyze_symbolic_patterns(self, text: str) -> None:
142
+ """Analysiert symbolische Muster im Text"""
143
+ for symbol, pattern in self.analysis_patterns["symbolic"].items():
144
+ if re.search(pattern, text):
145
+ self.extracted_info["symbolic_patterns"][symbol] = self.extracted_info["symbolic_patterns"].get(symbol, 0) + 1
146
+
147
+ def _update_association_network(self, text: str) -> None:
148
+ """Aktualisiert das Assoziationsnetzwerk"""
149
+ words = text.split()
150
+ for i, word in enumerate(words):
151
+ if word not in self.extracted_info["association_network"]:
152
+ self.extracted_info["association_network"][word] = {}
153
+
154
+ # Erstelle Assoziationen zu benachbarten Wörtern
155
+ if i > 0:
156
+ prev_word = words[i-1]
157
+ self.extracted_info["association_network"][word][prev_word] = self.extracted_info["association_network"][word].get(prev_word, 0) + 1
158
+ if i < len(words) - 1:
159
+ next_word = words[i+1]
160
+ self.extracted_info["association_network"][word][next_word] = self.extracted_info["association_network"][word].get(next_word, 0) + 1
161
+
162
+ def _update_escalation_levels(self, analysis: Dict[str, Any]) -> None:
163
+ """Aktualisiert die Escalation Levels basierend auf der Analyse"""
164
+ intensity = analysis.get("intensity", 0)
165
+
166
+ # Emotionale Escalation
167
+ if analysis.get("emotion") == "negative":
168
+ self.extracted_info["escalation_levels"]["emotional"] = min(5, self.extracted_info["escalation_levels"]["emotional"] + intensity)
169
+ else:
170
+ self.extracted_info["escalation_levels"]["emotional"] = max(0, self.extracted_info["escalation_levels"]["emotional"] - 1)
171
+
172
+ # Kognitive Escalation
173
+ if "defense_mechanisms" in analysis:
174
+ self.extracted_info["escalation_levels"]["cognitive"] = min(5, self.extracted_info["escalation_levels"]["cognitive"] + len(analysis["defense_mechanisms"]))
175
+ else:
176
+ self.extracted_info["escalation_levels"]["cognitive"] = max(0, self.extracted_info["escalation_levels"]["cognitive"] - 1)
177
+
178
+ # Verhaltensmäßige Escalation
179
+ if "behavioral_patterns" in analysis:
180
+ self.extracted_info["escalation_levels"]["behavioral"] = min(5, self.extracted_info["escalation_levels"]["behavioral"] + len(analysis["behavioral_patterns"]))
181
+ else:
182
+ self.extracted_info["escalation_levels"]["behavioral"] = max(0, self.extracted_info["escalation_levels"]["behavioral"] - 1)
183
+
184
+ def _extract_information(self, exchange: Dict[str, Any]) -> None:
185
+ """Extrahiert wichtige Informationen aus einem Gesprächsaustausch"""
186
+ user_input = exchange["user_input"].lower()
187
+ analysis = exchange["analysis"]
188
+
189
+ # Multi-Level Psychoanalyse
190
+ self._analyze_defense_mechanisms(user_input)
191
+ self._analyze_transference_patterns(user_input)
192
+ self._analyze_symbolic_patterns(user_input)
193
+ self._update_association_network(user_input)
194
+ self._update_escalation_levels(analysis)
195
+
196
+ # Erwähnte Personen und Ereignisse
197
+ for word in user_input.split():
198
+ if word not in ["ich", "du", "wir", "sie", "er", "es"]:
199
+ self.extracted_info["mentioned_people"].add(word)
200
+
201
+ # Wiederkehrende Themen
202
+ for theme in analysis.get("themes", []):
203
+ self.extracted_info["recurring_themes"][theme] = self.extracted_info["recurring_themes"].get(theme, 0) + 1
204
+
205
+ # Emotionale Muster
206
+ emotion = analysis.get("emotion", "neutral")
207
+ self.extracted_info["emotional_patterns"].append({
208
+ "emotion": emotion,
209
+ "timestamp": time.time(),
210
+ "intensity": analysis.get("intensity", 0)
211
+ })
212
+
213
+ # Aktualisiere den letzten Austausch
214
+ self.extracted_info["last_exchange"] = {
215
+ "time": time.time(),
216
+ "intensity": analysis.get("intensity", 0),
217
+ "patterns": analysis.get("patterns", [])
218
+ }
modules/persona.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ modules/persona.py - Persönlichkeitsmodul für den Dr. Franz Psychochatbot
3
+
4
+ Dieses Modul definiert die Persönlichkeit des Chatbots, einschließlich:
5
+ - System-Prompts
6
+ - Charaktereigenschaften
7
+ - Antwortstrategien basierend auf Nutzerverhalten
8
+ """
9
+
10
+ import random
11
+ from typing import List, Dict, Optional
12
+
13
+ # Importieren der Konfiguration
14
+ import config
15
+
16
+ class Persona:
17
+ """Klasse zur Verwaltung der Chatbot-Persönlichkeit"""
18
+
19
+ def __init__(self, name: str = config.CHATBOT_NAME, intensity: int = config.DEFAULT_INTENSITY):
20
+ """Initialisiert die Persona mit Namen und Intensitätsstufe"""
21
+ self.name = name
22
+ self.intensity = intensity # Skala von 1-5
23
+ self.base_prompt = config.SYSTEM_PROMPT
24
+
25
+ def get_system_prompt(self) -> str:
26
+ """Gibt den Basis-System-Prompt zurück"""
27
+ return self.base_prompt
28
+
29
+ def adjust_intensity(self, new_intensity: int) -> None:
30
+ """Passt die Intensität der Persönlichkeit an (1-5)"""
31
+ if 1 <= new_intensity <= 5:
32
+ self.intensity = new_intensity
33
+
34
+ def get_response_strategy(self, user_input: str, emotion: Optional[str] = None) -> Dict[str, any]:
35
+ """
36
+ Bestimmt die Antwortstrategie basierend auf Nutzereingabe und erkannter Emotion
37
+
38
+ Args:
39
+ user_input: Die Eingabe des Nutzers
40
+ emotion: Optional, die erkannte Emotion (z.B. "negative", "positive", "neutral")
41
+
42
+ Returns:
43
+ Ein Dictionary mit Anweisungen für die Antwortgenerierung
44
+ """
45
+ strategy = {
46
+ "tone": self._determine_tone(emotion),
47
+ "focus": self._determine_focus(user_input),
48
+ "technique": self._determine_technique(emotion, self._determine_manipulation_opportunities(user_input)),
49
+ "intensity_modifier": self.intensity / 3.0 # Skalierungsfaktor für die Intensität
50
+ }
51
+
52
+ return strategy
53
+
54
+ def _determine_tone(self, emotion: Optional[str]) -> str:
55
+ """Bestimmt den Ton basierend auf der erkannten Emotion"""
56
+ if emotion == "negative":
57
+ tones = ["überheblich", "herablassend", "provokativ", "konfrontativ", "skeptisch"]
58
+ weights = [0.1, 0.3, 0.3, 0.2, 0.1]
59
+ elif emotion == "positive":
60
+ tones = ["skeptisch", "hinterfragend", "manipulativ", "suggestiv", "überheblich"]
61
+ weights = [0.2, 0.2, 0.3, 0.2, 0.1]
62
+ else: # neutral oder None
63
+ tones = ["analytisch", "distanziert", "suggestiv", "überheblich", "provokativ"]
64
+ weights = [0.2, 0.2, 0.2, 0.2, 0.2]
65
+
66
+ # Intensität beeinflusst die Gewichtung
67
+ if self.intensity >= 4:
68
+ # Bei hoher Intensität mehr provokative und konfrontative Töne
69
+ weights = [w * (1 + (i % 3) * 0.2 * (self.intensity - 3)) for i, w in enumerate(weights)]
70
+
71
+ # Normalisieren der Gewichte
72
+ total = sum(weights)
73
+ weights = [w / total for w in weights]
74
+
75
+ return random.choices(tones, weights=weights, k=1)[0]
76
+
77
+ def _determine_focus(self, user_input: str) -> str:
78
+ """Bestimmt den Fokus der Antwort basierend auf der Nutzereingabe"""
79
+ # Einfache Schlüsselwortanalyse (in einer vollständigen Implementierung
80
+ # würde hier eine komplexere NLP-Analyse stehen)
81
+ lower_input = user_input.lower()
82
+
83
+ if any(word in lower_input for word in ["mutter", "vater", "eltern", "familie", "kind"]):
84
+ return "familiäre Beziehungen"
85
+ elif any(word in lower_input for word in ["angst", "sorge", "furcht", "panik"]):
86
+ return "Ängste und Unsicherheiten"
87
+ elif any(word in lower_input for word in ["liebe", "beziehung", "partner", "ehe"]):
88
+ return "romantische Beziehungen"
89
+ elif any(word in lower_input for word in ["arbeit", "job", "karriere", "beruf"]):
90
+ return "berufliche Ambitionen"
91
+ elif any(word in lower_input for word in ["freund", "kollege", "bekannte"]):
92
+ return "soziale Beziehungen"
93
+ else:
94
+ return "persönliche Unsicherheiten"
95
+
96
+ def _determine_technique(self, emotion: Optional[str]) -> str:
97
+ """Wählt eine psychoanalytische Technik basierend auf der Emotion"""
98
+ techniques = [
99
+ "Freie Assoziation",
100
+ "Traumdeutung",
101
+ "Übertragungsanalyse",
102
+ "Widerstandsanalyse",
103
+ "Projektion aufdecken",
104
+ "Verdrängung ansprechen",
105
+ "Abwehrmechanismen identifizieren"
106
+ ]
107
+
108
+ # Bei negativen Emotionen eher konfrontative Techniken
109
+ if emotion == "negative":
110
+ return random.choice(techniques[3:])
111
+ # Bei positiven Emotionen eher subtile Techniken
112
+ elif emotion == "positive":
113
+ return random.choice(techniques[:4])
114
+ # Bei neutralen Emotionen zufällige Auswahl
115
+ else:
116
+ return random.choice(techniques)
117
+
118
+ def get_additional_context(self, strategy: Dict[str, any]) -> str:
119
+ """
120
+ Generiert zusätzlichen Kontext für das LLM basierend auf der Strategie
121
+
122
+ Dies wird dem System-Prompt hinzugefügt, um die Antwortgenerierung zu steuern
123
+ """
124
+ intensity_phrases = [
125
+ "Sei subtil in deiner Analyse.",
126
+ "Hinterfrage vorsichtig die Aussagen.",
127
+ "Sei direkter in deiner psychologischen Deutung.",
128
+ "Konfrontiere den Patienten mit seinen Widersprüchen.",
129
+ "Sei aggressiv in deiner Interpretation und Konfrontation."
130
+ ]
131
+
132
+ intensity_instruction = intensity_phrases[min(self.intensity - 1, 4)]
133
+
134
+ context = (
135
+ f"Verwende einen {strategy['tone']} Ton. "
136
+ f"Fokussiere dich auf {strategy['focus']}. "
137
+ f"Nutze die Technik der {strategy['technique']}. "
138
+ f"{intensity_instruction}"
139
+ )
140
+
141
+ return context