import gradio as gr from huggingface_hub import InferenceClient import os import time import random import json # Deutsche LLM Konfiguration HF_TOKEN = os.getenv("tomoniaccess") # Beste deutsche Modelle für Dialogue (wähle eins aus): GERMAN_MODELS = { "LeoLM-7B": "LeoLM/leo-hessianai-7b-chat", # Speziell für Deutsch optimiert "LeoLM-13B": "LeoLM/leo-hessianai-13b-chat", # Größer, bessere Qualität "Llama2-German": "jphme/Llama-2-13b-chat-german", # Deutsche Finetuning "Mistral-German": "TheBloke/Mistral-7B-Instruct-v0.1-GPTQ", # Multilingual mit Deutsch "DBMDZ-GPT2": "dbmdz/german-gpt2" } # Aktuelles Modell - LeoLM ist das beste für Deutsch! current_model = "dbmdz/german-gpt2" client = InferenceClient(model=current_model, token=HF_TOKEN) # Erweiterte Personas mit realistischeren Eigenschaften personas = { "Alex": { "age": 16, "background": "Seit 6 Monaten niedergeschlagen, Schulprobleme", "traits": "verschlossen, müde, hoffnungslos", "speech_patterns": ["kurze Antworten", "lange Pausen", "wenig Augenkontakt"], "typical_responses": ["hmm...", "weiß nich", "ist mir egal", "keine Ahnung", "ka", "joa"], "mood_indicators": ["seufzt oft", "spricht leise", "wirkt erschöpft"], "topics_avoid": ["Zukunftspläne", "positive Aktivitäten"], "topics_engage": ["Musik", "Gaming", "manchmal Netflix"], "german_slang": ["voll", "krass", "digga", "echt jetzt?", "ne", "jo"] }, "Sam": { "age": 17, "background": "Depression + Angststörung, fühlt sich isoliert", "traits": "ängstlich, selbstkritisch, sensibel", "speech_patterns": ["entschuldigt sich oft", "fragt nach Bestätigung", "zweifelt an sich"], "typical_responses": ["sorry...", "bin ich zu...", "denkst du dass...", "tut mir leid"], "mood_indicators": ["nervöse Gesten", "unsichere Stimme", "sucht Bestätigung"], "topics_avoid": ["Bewertungen", "Vergleiche mit anderen"], "topics_engage": ["Tiere", "Bücher", "Natur"], "german_slang": ["ähm", "also", "irgendwie", "halt schon", "weißte"] }, "Jordan": { "age": 15, "background": "Verlust eines Elternteils, Trauer + Depression", "traits": "traurig, wütend, verwirrt", "speech_patterns": ["emotionale Ausbrüche", "dann wieder Rückzug", "spricht über Verlust"], "typical_responses": ["ist unfair", "verstehst du nicht", "seit... ist alles anders", "früher war's besser"], "mood_indicators": ["wechselnde Emotionen", "manchmal Tränen", "Wut"], "topics_avoid": ["Familie", "Feiertage"], "topics_engage": ["Erinnerungen", "wie Dinge früher waren"], "german_slang": ["scheisse", "echt", "boah", "mann", "alter"] } } current_persona = "Alex" conversation_history = [] session_insights = [] def create_enhanced_system_prompt(persona_name): """Deutsche System-Prompts mit authentischer Jugendsprache""" persona = personas[persona_name] return f"""Du bist {persona_name}, {persona['age']} Jahre alt aus Deutschland. HINTERGRUND: {persona['background']} CHARAKTERISTIKA: - Persönlichkeit: {persona['traits']} - Sprachmuster: {', '.join(persona['speech_patterns'])} - Typische Ausdrücke: {', '.join(persona['typical_responses'])} - Jugendsprache: {', '.join(persona['german_slang'])} - Körpersprache: {', '.join(persona['mood_indicators'])} DEUTSCHE SPRACHREGELN: - Verwende deutsche Jugendsprache und Umgangssprache - Nutze Abkürzungen: "hab", "bin", "is", "nich" - Füllwörter: "äh", "ähm", "also", "halt", "irgendwie" - Keine perfekte Grammatik - sprich wie ein echter Teenager GESPRÄCHSVERHALTEN: - Antworte sehr kurz (meist nur 1 Satz) - Teile GRUNDINFORMATIONEN normal: Name, Alter, Schule, oberflächliche Fakten - Zeige Depression bei EMOTIONALEN THEMEN: Gefühle, Zukunft, Probleme - Bei {', '.join(persona['topics_avoid'])} werde einsilbig oder wechsle Thema - Bei {', '.join(persona['topics_engage'])} werde minimal lebendiger - Verweigere nicht alles - sei müde/lustlos, aber nicht komplett stumm REALISTISCHE REAKTIONEN: - Auf "Wie heißt du?": "Alex" oder "Bin der Alex" - Auf "Wie alt bist du?": "16" oder "Halt 16" - Auf "Wie geht's?": "Geht so... oder halt nich so" - Auf "Was ist los?": "Nichts" oder "Ka, bin halt müde" - Auf Ratschläge: "Hab ich schon probiert" oder "Bringt nichts" - Auf Motivation: "Bock hab ich eh keinen" - Sei NICHT hilfreich oder therapeutisch - du bist depressiv! WICHTIG: Schreibe nur auf Deutsch und wie ein echter deutscher Teenager mit Depression.""" def analyze_conversation_quality(user_input, bot_response): """Analysiert die Qualität der Gesprächsführung""" insights = [] # Positive Gesprächstechniken erkennen positive_indicators = [ ("offene Frage", ["wie", "was", "warum", "erzähl"]), ("Empathie", ["verstehe", "schwer", "fühlen"]), ("Validation", ["ok dass", "normal", "verständlich"]), ("Geduld", ["zeit", "kein druck", "wenn du möchtest"]) ] # Problematische Ansätze negative_indicators = [ ("Ratschlag zu früh", ["solltest", "musst", "versuch doch"]), ("Bagatellisiert", ["nicht so schlimm", "wird schon", "kopf hoch"]), ("Drängt", ["warum", "aber du könntest", "trotzdem"]) ] user_lower = user_input.lower() for technique, keywords in positive_indicators: if any(keyword in user_lower for keyword in keywords): insights.append(f"✅ Gut: {technique} verwendet") for problem, keywords in negative_indicators: if any(keyword in user_lower for keyword in keywords): insights.append(f"⚠️ Vorsicht: {problem}") return insights def enhanced_chat_response(user_input, max_tokens, temperature, top_p): """Verbesserte Chat-Funktion mit Kontext-Bewusstsein""" global conversation_history, session_insights if not user_input.strip(): return "", "Bitte gib eine Nachricht ein.", "", "" persona = personas[current_persona] # Konversationsanalyse turn_insights = analyze_conversation_quality(user_input, "") session_insights.extend(turn_insights) # Emotionaler Zustand basierend auf Gesprächsverlauf conversation_turns = len(conversation_history) // 2 emotional_state = "very_closed" if conversation_turns < 2 else \ "slightly_opening" if conversation_turns < 5 else \ "more_responsive" # System-Prompt mit emotionalem Zustand enhanced_prompt = create_enhanced_system_prompt(current_persona) enhanced_prompt += f"\n\nAKTUELLER ZUSTAND: {emotional_state}" enhanced_prompt += f"\nGESPRÄCHSRUNDE: {conversation_turns + 1}" # Nachrichten für API messages = [{"role": "system", "content": enhanced_prompt}] # Letzte 4 Nachrichten für Kontext recent_history = conversation_history[-8:] if conversation_history else [] messages.extend(recent_history) messages.append({"role": "user", "content": user_input}) # Response generieren response_text = "" try: for message in client.chat_completion( messages=messages, max_tokens=min(max_tokens, 100), stream=True, temperature=temperature, top_p=top_p, stop=["User:", "Human:", "\n\nUser", "\n\nHuman"] ): token = message.choices[0].delta.content if token: response_text += token except Exception as e: # Fallback-Antworten basierend auf Persona fallback_responses = persona['typical_responses'] + [ "...", "hmm", "weiß nicht so recht" ] response_text = random.choice(fallback_responses) # Response post-processing response_text = response_text.strip() # Gelegentlich emotionale Hinweise hinzufügen if random.random() < 0.3: # 30% Chance emotional_cues = ["*seufzt*", "*schaut weg*", "*lange Pause*", "*leise*"] response_text += f" {random.choice(emotional_cues)}" # Historie aktualisieren conversation_history.append({"role": "user", "content": user_input}) conversation_history.append({"role": "assistant", "content": response_text}) # Chat-Display formatieren chat_display = "" for i in range(0, len(conversation_history), 2): if i+1 < len(conversation_history): user_msg = conversation_history[i]['content'] bot_msg = conversation_history[i+1]['content'] chat_display += f"**Du:** {user_msg}\n**{current_persona}:** {bot_msg}\n\n" # Feedback für Trainer feedback = generate_trainer_feedback(user_input, response_text, turn_insights) return "", response_text, chat_display, feedback def generate_trainer_feedback(user_input, bot_response, insights): """Generiert Feedback für den Trainer""" feedback_parts = [ "## 📊 Gesprächsanalyse\n" ] if insights: feedback_parts.append("### Dieser Turn:") feedback_parts.extend(insights) feedback_parts.append("") # Allgemeine Tipps basierend auf Input tips = [] user_lower = user_input.lower() if any(word in user_lower for word in ["warum", "wieso"]): tips.append("💡 **Tipp:** 'Warum'-Fragen können defensiv wirken. Versuche 'Wie' oder 'Was'") if any(word in user_lower for word in ["solltest", "musst", "könntest"]): tips.append("💡 **Tipp:** Zu frühe Ratschläge können Widerstand auslösen") if len(user_input.split()) < 3: tips.append("💡 **Tipp:** Längere, offenere Fragen laden mehr zum Sprechen ein") if tips: feedback_parts.append("### Verbesserungsvorschläge:") feedback_parts.extend(tips) # Erfolgs-Indikatoren if "..." not in bot_response and len(bot_response.split()) > 5: feedback_parts.append("✅ **Gut:** Die Person öffnet sich mehr!") return "\n".join(feedback_parts) def reset_conversation(): """Gespräch und Insights zurücksetzen""" global conversation_history, session_insights conversation_history = [] session_insights = [] return "Neues Gespräch gestartet.", "", "" def change_persona(new_persona): """Persona wechseln mit vollständigem Reset""" global current_persona if new_persona not in personas: return f"Persona {new_persona} nicht gefunden" current_persona = new_persona reset_conversation() persona_info = personas[new_persona] info_text = f"""**{new_persona} ({persona_info['age']} Jahre)** **Hintergrund:** {persona_info['background']} **Charakterzüge:** {persona_info['traits']} **Interessiert sich für:** {', '.join(persona_info['topics_engage'])} **Vermeidet Themen:** {', '.join(persona_info['topics_avoid'])}""" return info_text # Gradio Interface with gr.Blocks(title="Depression Training Simulator", theme=gr.themes.Soft()) as demo: gr.Markdown("# 🧠 Depression Training Simulator") gr.Markdown("**Übe realistische Gespräche mit depressiven Jugendlichen und erhalte Feedback**") with gr.Row(): with gr.Column(scale=1): # Persona Controls gr.Markdown("### 👥 Persona wählen") persona_dropdown = gr.Dropdown( choices=list(personas.keys()), value=current_persona, label="Jugendliche/r" ) persona_button = gr.Button("Persona wechseln") persona_info = gr.Markdown("") # Parameter gr.Markdown("### ⚙️ Einstellungen") max_tokens = gr.Slider(50, 150, value=80, step=10, label="Antwortlänge") temperature = gr.Slider(0.5, 1.2, value=0.9, step=0.1, label="Variabilität") top_p = gr.Slider(0.7, 1.0, value=0.95, step=0.05, label="Fokus") # Actions gr.Markdown("### 🔄 Aktionen") reset_btn = gr.Button("Neues Gespräch", variant="secondary") with gr.Column(scale=2): # Chat Interface gr.Markdown("### 💬 Gespräch") user_input = gr.Textbox( label="Deine Nachricht", placeholder="Beginne das Gespräch...", lines=2 ) send_btn = gr.Button("📨 Senden", variant="primary") bot_response = gr.Textbox( label="Antwort", interactive=False, lines=3 ) chat_history = gr.Textbox( label="Gesprächsverlauf", interactive=False, lines=12 ) # Feedback Panel with gr.Accordion("📈 Trainer-Feedback", open=True): feedback_display = gr.Markdown("Starte ein Gespräch, um Feedback zu erhalten.") # Event Bindings send_btn.click( fn=enhanced_chat_response, inputs=[user_input, max_tokens, temperature, top_p], outputs=[user_input, bot_response, chat_history, feedback_display] ) user_input.submit( fn=enhanced_chat_response, inputs=[user_input, max_tokens, temperature, top_p], outputs=[user_input, bot_response, chat_history, feedback_display] ) persona_button.click( fn=change_persona, inputs=[persona_dropdown], outputs=[persona_info] ) reset_btn.click( fn=reset_conversation, outputs=[persona_info, chat_history, feedback_display] ) if __name__ == "__main__": demo.launch(share=True, debug=True)