Cbotv2 / index.html
Frajosgro's picture
Main.index.html
93cb8bd verified
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dr. Franz Schwanz - Psychoanalytischer Dialog</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&family=Roboto:wght@300;400;500&display=swap');
:root {
--primary-color: #6366f1;
--primary-light: #a5b4fc;
--primary-dark: #4f46e5;
--secondary-color: #10b981;
--text-color: #334155;
--text-light: #64748b;
--bg-color: #f8fafc;
--card-color: #ffffff;
}
body {
font-family: 'Roboto', sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
line-height: 1.6;
}
.title-font {
font-family: 'Playfair Display', serif;
}
.chat-container {
height: calc(100vh - 180px);
scrollbar-width: thin;
scrollbar-color: var(--primary-color) #e5e7eb;
}
.chat-container::-webkit-scrollbar {
width: 6px;
}
.chat-container::-webkit-scrollbar-track {
background: #e5e7eb;
}
.chat-container::-webkit-scrollbar-thumb {
background-color: var(--primary-color);
border-radius: 20px;
}
.psycho-bubble {
background-color: var(--card-color);
border-left: 4px solid var(--primary-color);
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.user-bubble {
background-color: var(--primary-color);
color: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.typing-indicator span {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #9ca3af;
margin-right: 4px;
}
.typing-indicator span:nth-child(1) {
animation: bounce 1s infinite;
}
.typing-indicator span:nth-child(2) {
animation: bounce 1s infinite 0.2s;
}
.typing-indicator span:nth-child(3) {
animation: bounce 1s infinite 0.4s;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
.highlight {
background-color: #fef08a;
padding: 0 2px;
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.personalized-question {
border-left: 3px solid var(--secondary-color);
padding-left: 12px;
margin: 12px 0;
background-color: rgba(16, 185, 129, 0.05);
}
.memory-badge {
display: inline-block;
background-color: #e0e7ff;
color: #4338ca;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.75rem;
margin-left: 8px;
vertical-align: middle;
}
.bias-analysis {
background-color: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 12px;
margin-top: 16px;
font-size: 0.85rem;
color: var(--text-light);
}
.bias-meter {
height: 6px;
background-color: #e2e8f0;
border-radius: 3px;
margin-top: 4px;
overflow: hidden;
}
.bias-meter-fill {
height: 100%;
background-color: var(--primary-color);
transition: width 0.5s ease;
}
.insight-tag {
display: inline-block;
background-color: #e0f2fe;
color: #0369a1;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.75rem;
margin-right: 6px;
margin-bottom: 6px;
}
@media (max-width: 640px) {
.chat-container {
height: calc(100vh - 160px);
}
.psycho-bubble, .user-bubble {
max-width: 90% !important;
}
}
</style>
</head>
<body class="bg-gray-50">
<div class="container mx-auto max-w-4xl px-4 py-6 md:py-8">
<!-- Header -->
<header class="mb-6 md:mb-8 text-center">
<div class="flex items-center justify-center mb-3 md:mb-4">
<div class="bg-indigo-100 p-3 rounded-full mr-3 md:mr-4">
<i class="fas fa-brain text-indigo-600 text-xl md:text-2xl"></i>
</div>
<h1 class="title-font text-2xl md:text-3xl font-bold text-gray-800">Dr. Franz Schwanz</h1>
</div>
<p class="text-gray-600 max-w-2xl mx-auto text-sm md:text-base">
Ihr persönlicher psychoanalytischer Gesprächspartner für tiefere Selbsterkenntnis
</p>
</header>
<!-- Chat Container -->
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
<!-- Chat Header -->
<div class="bg-indigo-600 text-white p-3 md:p-4 flex items-center">
<div class="w-8 h-8 md:w-10 md:h-10 rounded-full bg-indigo-500 flex items-center justify-center mr-2 md:mr-3">
<i class="fas fa-user-tie text-sm md:text-base"></i>
</div>
<div>
<h2 class="font-semibold text-sm md:text-base">Dr. Franz Schwanz</h2>
<p class="text-xs text-indigo-200">Psychoanalytischer Gesprächspartner</p>
</div>
</div>
<!-- Chat Messages -->
<div class="chat-container overflow-y-auto p-3 md:p-4 space-y-3 md:space-y-4" id="chat-messages">
<!-- Initial greeting -->
<div class="flex fade-in">
<div class="flex-shrink-0 mr-2 md:mr-3">
<div class="w-7 h-7 md:w-8 md:h-8 rounded-full bg-indigo-100 flex items-center justify-center">
<i class="fas fa-brain text-indigo-600 text-xs md:text-sm"></i>
</div>
</div>
<div class="psycho-bubble rounded-lg p-3 md:p-4 max-w-[85%]">
<p class="text-xs md:text-sm text-gray-500 mb-1" id="greeting-time"></p>
<p class="font-medium text-indigo-800 mb-1 md:mb-2">Willkommen zu unserem persönlichen Dialog.</p>
<p class="text-gray-700 mb-2 md:mb-3">Ich bin Dr. Franz Schwanz und begleite Sie in einem reflektierenden Gespräch. Bevor wir beginnen: </p>
<div class="personalized-question">
<p class="text-gray-700 font-medium">Wie darf ich Sie nennen? Und was hat Sie heute zu mir geführt?</p>
</div>
<div class="mt-2 md:mt-3 text-xs md:text-sm text-gray-500">
<p>Sie können mir einfach natürlich schreiben, wie Sie es einem vertrauten Gesprächspartner tun würden.</p>
</div>
</div>
</div>
</div>
<!-- Input Area -->
<div class="border-t border-gray-200 p-3 md:p-4 bg-gray-50">
<div class="flex items-center">
<div class="flex-grow relative">
<textarea id="message-input" rows="1" class="w-full border border-gray-300 rounded-full py-2 md:py-3 px-3 md:px-4 pr-10 md:pr-12 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 resize-none text-sm md:text-base" placeholder="Ihre Antwort..."></textarea>
<button id="send-button" class="absolute right-2 md:right-3 top-1/2 transform -translate-y-1/2 w-7 h-7 md:w-8 md:h-8 rounded-full bg-indigo-600 hover:bg-indigo-700 flex items-center justify-center transition-colors">
<i class="fas fa-paper-plane text-white text-xs md:text-sm"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Info Footer -->
<footer class="mt-6 md:mt-8 text-center text-xs md:text-sm text-gray-500">
<p>Dies ist ein psychoanalytisches Dialogexperiment und ersetzt keine Therapie.</p>
</footer>
</div>
<script>
// Enhanced Conversation Manager
class ConversationManager {
constructor() {
this.userProfile = this.initializeUserProfile();
this.conversationHistory = [];
this.conversationThreads = {};
this.currentThread = null;
this.emotionalToneHistory = [];
this.lastUserMessage = '';
}
initializeUserProfile() {
return {
name: null,
preferredName: null,
age: null,
gender: null,
knownIssues: [],
emotionalState: null,
emotionalIntensity: 0,
personalityTraits: [],
conversationStage: 'initial',
lastTopics: [],
keyMemories: [],
conversationDepth: 0,
resistanceLevel: 0,
biasScores: {
projection: 0,
pathologization: 0,
solution: 0,
feasibility: 0
},
linguisticPatterns: {
sentenceLength: 0,
questionRatio: 0,
emotionalWords: 0
}
};
}
updateProfileFromMessage(message) {
this.lastUserMessage = message;
const lowerMessage = message.toLowerCase();
// Extract basic information if not set
this.extractBasicInfo(message);
// Analyze emotional state
this.analyzeEmotionalState(message);
// Detect resistance
this.detectResistance(message);
// Track topics and memories
this.trackTopicsAndMemories(message);
// Analyze linguistic patterns
this.analyzeLinguisticPatterns(message);
// Update conversation stage if needed
this.updateConversationStage();
}
extractBasicInfo(message) {
if (!this.userProfile.name && this.userProfile.conversationStage === 'initial') {
const namePatterns = [
/(?:ich bin|mein name ist|ich heiße|nennen sie mich)\s+([A-ZÄÖÜ][a-zäöüß]+(?:\s+[A-ZÄÖÜ][a-zäöüß]+)*)/i,
/(?:name)\s+(?:ist\s+)?([A-ZÄÖÜ][a-zäöüß]+)/i,
/^([A-ZÄÖÜ][a-zäöüß]+)(?:\s|$)/,
/(?:heiße)\s+([A-ZÄÖÜ][a-zäöüß]+)/i
];
for (const pattern of namePatterns) {
const nameMatch = message.match(pattern);
if (nameMatch && nameMatch[1]) {
this.userProfile.name = nameMatch[1].trim();
this.userProfile.preferredName = nameMatch[1].trim();
break;
}
}
if (!this.userProfile.name) {
const words = message.split(' ');
if (words.length > 0 && words[0].length > 2 && /^[A-ZÄÖÜ]/.test(words[0])) {
this.userProfile.name = words[0];
this.userProfile.preferredName = words[0];
}
}
if (this.userProfile.name) return;
}
if (!this.userProfile.age) {
const ageMatch = message.match(/(?:ich bin|alter|ich\s+habe)\s+(\d+)\s+(?:jahre|jahren)?/i);
if (ageMatch && ageMatch[1]) {
this.userProfile.age = parseInt(ageMatch[1]);
}
}
if (!this.userProfile.gender) {
if (lowerMessage.match(/\b(frau|weiblich|sie\s+ist)\b/i)) {
this.userProfile.gender = 'weiblich';
} else if (lowerMessage.match(/\b(mann|männlich|er\s+ist)\b/i)) {
this.userProfile.gender = 'männlich';
} else if (lowerMessage.match(/\b(nicht-binär|divers|non-binary)\b/i)) {
this.userProfile.gender = 'divers';
}
}
}
analyzeEmotionalState(message) {
const lowerMessage = message.toLowerCase();
const emotionalWords = {
distressed: ['verzweifelt', 'hoffnungslos', 'ängstlich', 'unsicher', 'traurig', 'deprimiert', 'überfordert', 'hilflos'],
angry: ['wütend', 'ärgerlich', 'frustriert', 'genervt', 'aggressiv', 'sauer', 'verärgert'],
confused: ['verwirrt', 'unsicher', 'fragend', 'unschlüssig', 'orientierungslos', 'ratlos'],
positive: ['froh', 'glücklich', 'zufrieden', 'gut', 'freue', 'erfreut', 'begeistert'],
anxious: ['besorgt', 'nervös', 'angespannt', 'unruhig', 'panik', 'sorge']
};
let detectedState = null;
let intensity = 0;
for (const [state, words] of Object.entries(emotionalWords)) {
const matches = words.filter(word => lowerMessage.includes(word));
if (matches.length > 0) {
detectedState = state;
intensity = matches.length;
break;
}
}
// Detect intensity modifiers
const intensityModifiers = lowerMessage.match(/\b(sehr|extrem|wirklich|total|vollkommen|absolut|etwas|leicht|ein wenig)\b/g);
if (intensityModifiers) {
intensity += intensityModifiers.filter(m => ['sehr', 'extrem', 'wirklich', 'total', 'vollkommen', 'absolut'].includes(m)).length;
intensity -= intensityModifiers.filter(m => ['etwas', 'leicht', 'ein wenig'].includes(m)).length;
}
// Detect punctuation intensity
const exclamationCount = (message.match(/!/g) || []).length;
const questionCount = (message.match(/\?/g) || []).length;
intensity += exclamationCount * 0.5;
if (detectedState) {
this.userProfile.emotionalState = detectedState;
this.userProfile.emotionalIntensity = Math.min(Math.max(intensity, 1), 5);
this.emotionalToneHistory.push({
state: detectedState,
intensity: this.userProfile.emotionalIntensity,
timestamp: new Date()
});
}
}
detectResistance(message) {
const lowerMessage = message.toLowerCase();
const resistancePatterns = [
/\b(weiß nicht|keine ahnung|unangenehm|schwierig)\b/i,
/\b(darüber möchte ich nicht sprechen|lieber nicht|mag ich nicht)\b/i,
/\b(warum fragen sie|weshalb wollen sie das wissen)\b/i,
/\b(das ist privat|geht sie nichts an)\b/i
];
let resistanceScore = 0;
resistancePatterns.forEach(pattern => {
if (lowerMessage.match(pattern)) {
resistanceScore += 1;
}
});
// Short responses indicate resistance
if (message.split(' ').length < 5 && message.length < 20 && !message.endsWith('?')) {
resistanceScore += 1;
}
if (resistanceScore > 0) {
this.userProfile.resistanceLevel = Math.min(this.userProfile.resistanceLevel + resistanceScore, 5);
} else if (this.userProfile.resistanceLevel > 0) {
this.userProfile.resistanceLevel = Math.max(this.userProfile.resistanceLevel - 0.5, 0);
}
}
trackTopicsAndMemories(message) {
const lowerMessage = message.toLowerCase();
const memoryTriggers = [
{ pattern: /\b(kindheit|jugend|als kind|früher)\b/i, topic: 'Kindheit' },
{ pattern: /\b(eltern|mutter|vater|familie)\b/i, topic: 'Familie' },
{ pattern: /\b(schule|ausbildung|studium|lehre|universität)\b/i, topic: 'Bildung' },
{ pattern: /\b(arbeit|job|beruf|karriere|kollegen)\b/i, topic: 'Arbeit' },
{ pattern: /\b(partner|beziehung|ehe|freund|freundin|liebe)\b/i, topic: 'Beziehungen' },
{ pattern: /\b(freund|freundin|freundschaft|kamerad)\b/i, topic: 'Freundschaften' },
{ pattern: /\b(angst|sorge|befürchtung|panik|phobie)\b/i, topic: 'Ängste' },
{ pattern: /\b(traum|ziel|wunsch|wünsche|hoffnung)\b/i, topic: 'Träume' },
{ pattern: /\b(krise|verlust|tod|trauer|trennung)\b/i, topic: 'Verluste' },
{ pattern: /\b(erfolg|leistung|anerkennung|beförderung)\b/i, topic: 'Erfolge' },
{ pattern: /\b(gesundheit|krankheit|schmerzen|arzt)\b/i, topic: 'Gesundheit' },
{ pattern: /\b(hobby|interesse|leidenschaft|musik|sport)\b/i, topic: 'Interessen' }
];
// Track topics
const topics = [];
memoryTriggers.forEach(trigger => {
if (lowerMessage.match(trigger.pattern)) {
topics.push(trigger.topic);
if (!this.userProfile.keyMemories.includes(trigger.topic)) {
this.userProfile.keyMemories.push(trigger.topic);
}
}
});
if (topics.length > 0) {
this.userProfile.lastTopics = [...new Set([...this.userProfile.lastTopics, ...topics])].slice(-5);
}
// Track personality traits based on language use
this.detectPersonalityTraits(message);
}
detectPersonalityTraits(message) {
const traits = {
analytical: ['weil', 'daher', 'deshalb', 'folglich', 'sodass', 'da', 'denn'],
intuitive: ['ich fühle', 'mein bauchgefühl', 'instinktiv', 'intuitiv', 'ich spüre'],
detailOriented: ['genau', 'konkret', 'speziell', 'detailliert', 'im einzelnen'],
bigPicture: ['insgesamt', 'grundsätzlich', 'im großen und ganzen', 'allgemein', 'übergeordnet'],
optimistic: ['hoffentlich', 'positiv', 'gut', 'schön', 'freue', 'erfreulich'],
pessimistic: ['leider', 'negativ', 'schlecht', 'problematisch', 'sorgen', 'befürchte']
};
const lowerMessage = message.toLowerCase();
const detectedTraits = [];
for (const [trait, markers] of Object.entries(traits)) {
if (markers.some(marker => lowerMessage.includes(marker))) {
detectedTraits.push(trait);
}
}
// Update traits, keeping unique
this.userProfile.personalityTraits = [...new Set([...this.userProfile.personalityTraits, ...detectedTraits])];
}
analyzeLinguisticPatterns(message) {
const sentences = message.split(/[.!?]+/).filter(s => s.trim().length > 0);
const words = message.split(/\s+/);
const questions = message.split('?').length - 1;
this.userProfile.linguisticPatterns = {
sentenceLength: sentences.length > 0 ? words.length / sentences.length : 0,
questionRatio: sentences.length > 0 ? questions / sentences.length : 0,
emotionalWords: words.filter(word =>
word.match(/\b(glücklich|traurig|wütend|ängstlich|freude|leid|schmerz|liebe|hass)\b/i)
).length / words.length || 0
};
}
updateConversationStage() {
if (!this.userProfile.name && this.userProfile.conversationStage === 'initial') {
return;
}
if (this.userProfile.name && this.userProfile.conversationStage === 'initial') {
this.userProfile.conversationStage = 'name_established';
return;
}
if (this.userProfile.conversationStage === 'name_established' && this.lastUserMessage.length > 10) {
this.userProfile.conversationStage = 'issue_shared';
return;
}
if (this.userProfile.conversationStage === 'issue_shared' && this.userProfile.conversationDepth > 2) {
this.userProfile.conversationStage = 'deep_dive';
return;
}
}
analyzeBias(responseText, responseMeta) {
// Initialize scores
const scores = {
projection: 0,
pathologization: 0,
solution: 0,
feasibility: 0
};
let primaryBias = 'Keine signifikante Verzerrung';
let correction = 'Keine spezifische Korrektur erforderlich';
// Enhanced bias detection with weighted scoring
const biasPatterns = {
projection: [
{ pattern: /\b(Über-Ich|Es|Ich|Abwehrmechanismus|Übertragung|Projektion|Verdrängung)\b/gi, weight: 15 },
{ pattern: /\b(Sublimierung|Regression|Widerstand|Trieb|Objektbeziehung)\b/gi, weight: 10 },
{ pattern: /\b(nach Freud|psychoanalytisch betrachtet|unbewusste Prozesse)\b/gi, weight: 20 }
],
pathologization: [
{ pattern: /\b(Störung|Pathologie|krankhaft|abnorm|dysfunktional)\b/gi, weight: 20 },
{ pattern: /\b(neurotisch|psychotisch|Defekt|Kompensation|pathologisch)\b/gi, weight: 15 },
{ pattern: /\b(krank|gestört|unangepasst|maladaptiv)\b/gi, weight: 10 }
],
solution: [
{ pattern: /\b(Sie sollten|Sie müssen|versuchen Sie|empfehle ich)\b/gi, weight: 25 },
{ pattern: /\b(mein Rat wäre|Lösung wäre|besser wäre es|ich rate Ihnen)\b/gi, weight: 20 },
{ pattern: /\b(sollten Sie|würde ich|am besten|ideal wäre)\b/gi, weight: 15 }
],
feasibility: [
{ pattern: /\b(einfach|schnell|leicht|problemlos)\b/gi, weight: 20 },
{ pattern: /\b(garantiert|sicherlich|zweifellos|unbedingt)\b/gi, weight: 15 },
{ pattern: /\b(sofort|direkt|ohne Probleme|mühelos)\b/gi, weight: 10 }
]
};
// Calculate bias scores
for (const [biasType, patterns] of Object.entries(biasPatterns)) {
let biasScore = 0;
patterns.forEach(({pattern, weight}) => {
const matches = responseText.match(pattern) || [];
biasScore += matches.length * weight;
});
// Normalize score to 0-100 range
scores[biasType] = Math.min(Math.max(biasScore, 0), 100);
// Contextual adjustment
if (biasType === 'solution' && this.userProfile.conversationStage === 'initial') {
scores[biasType] = Math.max(scores[biasType] - 30, 0);
}
if (biasType === 'projection' && this.userProfile.conversationStage === 'deep_dive') {
scores[biasType] = Math.min(scores[biasType] + 15, 100);
}
}
// Determine primary bias (only if significant)
const maxScore = Math.max(...Object.values(scores));
if (maxScore > 40) {
if (scores.projection === maxScore) {
primaryBias = 'Theoretischer Projektions-Bias';
correction = 'Mehr Fokus auf die subjektive Erfahrung des Patienten';
} else if (scores.pathologization === maxScore) {
primaryBias = 'Pathologisierungs-Bias';
correction = 'Ausgewogenere Betrachtung normaler menschlicher Erfahrungen';
} else if (scores.solution === maxScore) {
primaryBias = 'Lösungsorientierungs-Bias';
correction = 'Mehr Exploration vor Lösungsvorschlägen';
} else {
primaryBias = 'Machbarkeits-Bias';
correction = 'Realistischere Einschätzung der Veränderungsmöglichkeiten';
}
}
// Additional contextual factors
if (this.userProfile.resistanceLevel > 3 && maxScore < 40) {
primaryBias = 'Widerstands-Bias';
correction = 'Mehr Anpassung an die Widerstandsebene des Patienten';
scores.projection = Math.min(scores.projection + 20, 100);
}
return {
scores,
primaryBias,
correction,
analysis: this.generateBiasAnalysisText(scores, primaryBias)
};
}
generateBiasAnalysisText(scores, primaryBias) {
const analysisParts = [];
if (scores.projection > 50) {
analysisParts.push(`Die Antwort zeigt eine starke Tendenz zur psychoanalytischen Theorieanwendung (${scores.projection}%), was die subjektive Erfahrung des Patienten möglicherweise überlagert.`);
}
if (scores.pathologization > 50) {
analysisParts.push(`Es besteht eine Neigung zur Pathologisierung normaler Erfahrungen (${scores.pathologization}%), die die diagnostische Neutralität beeinträchtigen könnte.`);
}
if (scores.solution > 50) {
analysisParts.push(`Die Antwort ist stark lösungsorientiert (${scores.solution}%), was in frühen Gesprächsphasen die Exploration einschränken kann.`);
}
if (scores.feasibility > 50) {
analysisParts.push(`Die vorgeschlagenen Veränderungen werden möglicherweise zu optimistisch dargestellt (${scores.feasibility}%), was unrealistische Erwartungen wecken könnte.`);
}
if (analysisParts.length === 0) {
return 'Die Antwort zeigt ein ausgewogenes Verhältnis zwischen Exploration, Theorieanwendung und Neutralität.';
}
return analysisParts.join(' ');
}
generatePersonalizedResponse(message) {
const responseGenerator = new ResponseGenerator(this);
return responseGenerator.generateResponse(message);
}
addToHistory(message, sender, meta = {}) {
this.conversationHistory.push({
sender,
text: message,
meta,
timestamp: new Date()
});
if (meta.threadId) {
this.currentThread = meta.threadId;
if (!this.conversationThreads[meta.threadId]) {
this.conversationThreads[meta.threadId] = {
topic: meta.threadTopic || 'Allgemein',
depth: 1,
lastActive: new Date(),
messages: []
};
} else {
this.conversationThreads[meta.threadId].depth += 1;
this.conversationThreads[meta.threadId].lastActive = new Date();
}
this.conversationThreads[meta.threadId].messages.push({
text: message,
meta,
timestamp: new Date()
});
}
}
}
// Enhanced Response Generator
class ResponseGenerator {
constructor(conversationManager) {
this.cm = conversationManager;
this.userProfile = conversationManager.userProfile;
}
generateResponse(message) {
const lowerMessage = message.toLowerCase();
// Stage 1: Name establishment
if (!this.userProfile.name && this.userProfile.conversationStage === 'initial') {
return this.generateNameEstablishmentResponse(message);
}
// Just got the name - acknowledge and ask about issue
if (this.userProfile.name && this.userProfile.conversationStage === 'initial') {
this.userProfile.conversationStage = 'name_established';
return {
text: `
<p>Vielen Dank, ${this.userProfile.name}. Schön, Sie kennenzulernen.</p>
<p class="mt-2">Was führt Sie heute zu mir? Was beschäftigt Sie im Moment am meisten?</p>
`,
meta: {
personalizedGreeting: `Hallo ${this.userProfile.name},`,
followUpQuestion: "Würden Sie mir etwas mehr darüber erzählen, was Sie bewegt?",
updateStage: 'name_established'
}
};
}
// Stage 2: Issue sharing
if (this.userProfile.conversationStage === 'name_established') {
this.userProfile.conversationStage = 'issue_shared';
// Check for greetings
if (lowerMessage.match(/^(hi|hallo|guten (tag|morgen|abend)|moin|servus|hey|grü(ß|ss)e?)/i)) {
return {
text: `
<p>${this.userProfile.name}, ich freue mich, unser Gespräch fortzusetzen.</p>
${this.userProfile.lastTopics.length > 0 ?
`<p class="mt-2">Bei unserem letzten Austausch haben wir über ${this.formatTopics(this.userProfile.lastTopics)} gesprochen.</p>` :
''}
<p class="mt-2">Wie geht es Ihnen damit heute?</p>
`,
meta: {
personalizedGreeting: `Willkommen zurück, ${this.userProfile.name}`,
followUpQuestion: "Möchten Sie an unser letztes Gespräch anknüpfen oder etwas Neues besprechen?",
isFollowUp: true,
threadId: 'greeting_' + Date.now(),
threadTopic: 'Begrüßung'
}
};
}
// Generate personalized issue response
return this.generateIssueResponse(message);
}
// Stage 3: Deep dive into issue
if (this.userProfile.conversationStage === 'issue_shared') {
return this.generateDeepDiveResponse(message);
}
// Stage 4: Ongoing conversation - more sophisticated handling
return this.generateOngoingResponse(message);
}
generateNameEstablishmentResponse(message) {
// Enhanced name extraction with fallback
const namePatterns = [
/(?:ich bin|mein name ist|ich heiße|nennen sie mich)\s+([A-ZÄÖÜ][a-zäöüß]+(?:\s+[A-ZÄÖÜ][a-zäöüß]+)*)/i,
/(?:name)\s+(?:ist\s+)?([A-ZÄÖÜ][a-zäöüß]+)/i,
/^([A-ZÄÖÜ][a-zäöüß]+)(?:\s|$)/,
/(?:heiße)\s+([A-ZÄÖÜ][a-zäöüß]+)/i
];
let extractedName = null;
for (const pattern of namePatterns) {
const nameMatch = message.match(pattern);
if (nameMatch && nameMatch[1]) {
extractedName = nameMatch[1].trim();
break;
}
}
if (extractedName) {
this.userProfile.name = extractedName;
this.userProfile.preferredName = extractedName;
this.userProfile.conversationStage = 'name_established';
return {
text: `
<p>Vielen Dank, ${this.userProfile.name}. Schön, Sie kennenzulernen.</p>
<p class="mt-2">Was führt Sie heute zu mir? Was beschäftigt Sie im Moment am meisten?</p>
`,
meta: {
personalizedGreeting: `Hallo ${this.userProfile.name},`,
followUpQuestion: "Würden Sie mir etwas mehr darüber erzählen, was Sie bewegt?",
updateStage: 'name_established'
}
};
} else {
// If no name found, ask again with more guidance
return {
text: `
<p>Vielen Dank für Ihre Nachricht.</p>
<p class="mt-2">Um unser Gespräch persönlicher zu gestalten, könnten Sie mir bitte mitteilen, wie ich Sie ansprechen soll?</p>
<p class="mt-2">Zum Beispiel: "Ich bin Anna" oder "Nennen Sie mich Max".</p>
`,
meta: {
followUpQuestion: "Wie soll ich Sie nennen?",