Files
kidsai/html/kidsai/script-new.js
root 8d794b6318 CRITICAL FIX: Add missing repeated 'don't know' detection to chat mode
ROOT CAUSE FOUND:
- Chat mode was missing repeated 'don't know' detection logic entirely
- Only step-by-step mode had this functionality
- Server had undefined variable error when checking instructions
- This caused infinite questioning loops in chat conversations

FIXES APPLIED:
1. Added complete repeated 'don't know' detection to chat mode:
   - Conversation history tracking (last 4 messages)
   - German phrase detection variants
   - Threshold-based triggering (2+ occurrences)
   - Proper context passing to server

2. Fixed server-side undefined variable error:
   - Added null check for instructions parameter
   - Prevents TypeError when checking for repeated scenarios

3. Enhanced context handling:
   - Chat mode now sends 'repeated_dont_know' context
   - Proper instruction differentiation for different scenarios
   - Better debugging logs for both modes

RESULT:
- Both chat AND step-by-step modes now detect repeated frustration
- Children get explanations instead of endless questioning
- Eliminated infinite loop scenarios completely
- Better educational experience with adaptive responses
2025-06-30 16:13:06 +02:00

1439 lines
72 KiB
JavaScript

// KidsAI Explorer - Interactive Learning Assistant
console.log('🚀 KidsAI script-new.js is loading...');
// Test that AIResponses is available
console.log('🔍 Testing AIResponses availability:', typeof AIResponses);
if (typeof AIResponses !== 'undefined') {
console.log('✅ AIResponses loaded successfully:', Object.keys(AIResponses));
} else {
console.error('❌ AIResponses not loaded! Check ai-responses.js');
}
class KidsAIExplorer {
constructor() {
console.log('🏗️ KidsAI constructor started');
this.currentLanguage = localStorage.getItem('kidsai-language') || 'en';
// Get DOM elements
this.questionInput = document.getElementById('question-input');
this.askButton = document.getElementById('ask-button');
this.thinkingSection = document.getElementById('thinking-section');
this.thinkingSteps = document.getElementById('thinking-steps');
this.loadingOverlay = document.getElementById('loading');
this.suggestionCards = document.querySelectorAll('.suggestion-card');
this.langButtons = document.querySelectorAll('.lang-btn');
console.log('🔍 Elements found:', {
questionInput: !!this.questionInput,
askButton: !!this.askButton,
suggestionCards: this.suggestionCards.length,
langButtons: this.langButtons.length
});
// Hide loading overlay
if (this.loadingOverlay) {
this.loadingOverlay.classList.add('hidden');
}
// Initialize
this.initializeEventListeners();
this.initializeLanguage();
console.log('✅ KidsAI constructor completed');
}
// Detect mobile device
isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|| window.innerWidth <= 768;
}
initializeEventListeners() {
console.log('🔗 Setting up event listeners');
// Main question submission
if (this.askButton) {
console.log('📝 Adding click listener to ask button');
this.askButton.addEventListener('click', () => {
console.log('🖱️ Ask button clicked!');
this.handleQuestion();
});
}
if (this.questionInput) {
console.log('⌨️ Adding keypress listener to input');
this.questionInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
console.log('⏎ Enter key pressed!');
e.preventDefault();
this.handleQuestion();
}
});
// Add mobile-friendly input event for better responsiveness
if (this.isMobileDevice()) {
this.questionInput.addEventListener('input', () => {
// Auto-resize textarea on mobile for better UX
this.questionInput.style.height = 'auto';
this.questionInput.style.height = Math.min(this.questionInput.scrollHeight, 120) + 'px';
});
}
}
// Suggestion cards
console.log('🎯 Adding listeners to', this.suggestionCards.length, 'suggestion cards');
this.suggestionCards.forEach((card, index) => {
card.addEventListener('click', () => {
console.log('🎴 Suggestion card', index, 'clicked!');
const questionKey = `data-question-${this.currentLanguage}`;
const question = card.getAttribute(questionKey);
console.log('📝 Setting question:', question);
if (this.questionInput) {
this.questionInput.value = question;
}
this.handleQuestion();
});
});
// Language switching
this.langButtons.forEach(btn => {
btn.addEventListener('click', () => {
console.log('🌐 Language button clicked:', btn.dataset.lang);
this.switchLanguage(btn.dataset.lang);
});
});
console.log('✅ Event listeners setup complete');
}
initializeLanguage() {
console.log('🌐 Initializing language:', this.currentLanguage);
// Set active language button
this.langButtons.forEach(btn => {
btn.classList.toggle('active', btn.dataset.lang === this.currentLanguage);
});
// Apply translations if available
if (typeof translations !== 'undefined') {
this.applyTranslations();
} else {
console.warn('⚠️ Translations not loaded');
}
}
applyTranslations() {
try {
const t = translations[this.currentLanguage];
if (!t) {
console.warn('⚠️ Translations not available for language:', this.currentLanguage);
return;
}
// Update all elements with data-translate attribute
document.querySelectorAll('[data-translate]').forEach(element => {
const key = element.getAttribute('data-translate');
if (t[key]) {
element.textContent = t[key];
}
});
} catch (error) {
console.error('❌ Error applying translations:', error);
}
}
// Helper method to get translation for a key
getTranslation(key) {
try {
if (typeof translations !== 'undefined' && translations[this.currentLanguage] && translations[this.currentLanguage][key]) {
return translations[this.currentLanguage][key];
}
} catch (error) {
console.warn('⚠️ Could not get translation for key:', key, error);
}
return null;
}
// Safe translation method for use in template strings
t(key, fallback = '') {
try {
const translation = this.getTranslation(key);
return translation || fallback;
} catch (error) {
console.warn('⚠️ Translation error for key:', key, error);
return fallback;
}
}
switchLanguage(lang) {
console.log('🔄 Switching language to:', lang);
this.currentLanguage = lang;
localStorage.setItem('kidsai-language', lang);
this.initializeLanguage();
}
async handleQuestion() {
console.log('🤔 handleQuestion called');
const question = this.questionInput ? this.questionInput.value.trim() : '';
console.log('❓ Question:', question);
if (!question) {
console.log('⚠️ No question provided');
const message = this.getTranslation('ask-something-first') || 'Please ask me something first! 🤔';
this.showMessage(message, 'warning');
return;
}
this.showLoading();
console.log('🔄 Sending question to API...');
try {
const response = await fetch('/api/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
question: question,
language: this.currentLanguage
})
});
console.log('📡 API response status:', response.status);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('📦 API response data:', data);
if (data.success) {
this.displayGuidance(data.guidance);
} else {
throw new Error(data.error || 'Unknown error');
}
} catch (error) {
console.error('❌ Error getting AI guidance:', error);
const message = this.getTranslation('processing-trouble') || 'Sorry, I had trouble processing your question. Let me give you some thinking guidance instead!';
this.showMessage(message, 'info');
this.displayLocalGuidance(question);
} finally {
this.hideLoading();
}
}
displayGuidance(guidance) {
console.log('💭 Displaying AI guidance');
if (!this.thinkingSection || !this.thinkingSteps) {
console.error('❌ Thinking section elements not found');
return;
}
// Show thinking section
this.thinkingSection.classList.remove('hidden');
// Clear previous content completely
this.thinkingSteps.innerHTML = '';
// Reset conversation state
this.currentStep = 0;
this.userAnswers = [];
this.currentQuestionIndex = 0;
// Create conversation container
const conversationContainer = document.createElement('div');
conversationContainer.className = 'conversation-container';
this.thinkingSteps.appendChild(conversationContainer);
// Show initial encouragement
const welcomeStep = document.createElement('div');
welcomeStep.className = 'conversation-step visible';
// Get translations before creating HTML to avoid context issues
const encouragementText = guidance.encouragement || this.getTranslation('default-encouragement') || (this.currentLanguage === 'de' ? "Fantastische Frage! Lass uns das gemeinsam Schritt für Schritt erforschen! 🚀" : "Great question! Let's explore this together step by step! 🚀");
const detectiveHelpText = this.getTranslation('detective-help') || (this.currentLanguage === 'de' ? "Anstatt dir die Antwort gleich zu geben, helfe ich dir dabei, wie ein Detektiv zu denken! 🕵️" : "Instead of giving you the answer right away, I'll help you think through this like a detective! 🕵️");
const aiTeacherText = this.getTranslation('ai-teacher') || (this.currentLanguage === 'de' ? "KI-Lehrer" : "AI Teacher");
welcomeStep.innerHTML = `
<div class="ai-message">
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${aiTeacherText}</span>
</div>
<div class="message-content">
<p>${encouragementText}</p>
<p>${detectiveHelpText}</p>
</div>
</div>
`;
conversationContainer.appendChild(welcomeStep);
// Add thinking questions as interactive steps
const questions = guidance.steps ? guidance.steps.map(step => step.text) : guidance.questions || [
this.currentLanguage === 'de' ? "Was weißt du bereits über dieses Thema?" : "What do you already know about this topic?",
this.currentLanguage === 'de' ? "Was denkst du, könnte der Grund dafür sein?" : "What do you think might be the reason for this?",
this.currentLanguage === 'de' ? "Kannst du dir Beispiele oder ähnliche Situationen vorstellen?" : "Can you think of any examples or similar situations?"
];
// Create chat interface
this.conversationContainer = conversationContainer;
this.questions = questions;
// Start the conversation with the first question
this.askNextQuestion();
// Scroll to thinking section
this.thinkingSection.scrollIntoView({ behavior: 'smooth' });
}
displayLocalGuidance(question) {
console.log('📚 Displaying local guidance for:', question);
// Get translated encouragements or use fallback
const encouragements = this.getTranslation('encouragements') || [
"Great question! You're thinking like a real scientist! 🔬",
"Wow, that's a fantastic thing to wonder about! 🌟",
"I love how curious you are! That's how great discoveries happen! 🚀"
];
const randomEncouragement = encouragements[Math.floor(Math.random() * encouragements.length)];
// Get translated fallback questions
const fallbackQuestions = [
this.getTranslation('fallback-question-1') || "What do you already know about this topic?",
this.getTranslation('fallback-question-2') || "What do you think might be the reason for this?",
this.getTranslation('fallback-question-3') || "Where could you look to find more information?",
this.getTranslation('fallback-question-4') || "Can you think of any examples or similar situations?"
];
this.displayGuidance({
questions: fallbackQuestions,
encouragement: randomEncouragement
});
}
showLoading() {
console.log('⏳ Showing loading...');
if (this.loadingOverlay) {
this.loadingOverlay.classList.remove('hidden');
}
}
hideLoading() {
console.log('✅ Hiding loading...');
if (this.loadingOverlay) {
this.loadingOverlay.classList.add('hidden');
}
}
showMessage(message, type = 'info') {
console.log('💬 Showing message:', message, type);
// Create message popup
const messageDiv = document.createElement('div');
messageDiv.className = `message-popup ${type}`;
messageDiv.textContent = message;
messageDiv.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${type === 'error' ? '#fed7d7' : type === 'warning' ? '#fef5e7' : '#e6fffa'};
color: ${type === 'error' ? '#c53030' : type === 'warning' ? '#d69e2e' : '#00695c'};
padding: 15px 20px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
z-index: 1001;
max-width: 300px;
font-size: 14px;
`;
document.body.appendChild(messageDiv);
// Remove after 3 seconds
setTimeout(() => {
messageDiv.remove();
}, 3000);
}
submitAnswer(stepIndex) {
console.log('📝 Submit answer for step:', stepIndex);
const textarea = document.getElementById(`user-input-${stepIndex}`);
const inputArea = document.getElementById(`input-area-${stepIndex}`);
const responseDiv = document.getElementById(`response-${stepIndex}`);
if (!textarea || !inputArea || !responseDiv) {
console.error('❌ Could not find elements for step:', stepIndex);
return;
}
const answer = textarea.value.trim();
if (!answer) {
const message = this.getTranslation('write-thoughts') || 'Please write down your thoughts! 🤔';
this.showMessage(message, 'warning');
return;
}
// Store the answer
this.userAnswers[stepIndex] = answer;
// Mark as answered
inputArea.classList.add('answered');
textarea.disabled = true;
// Show AI response using server-side AI
this.generateAIResponseToAnswer(answer, stepIndex, responseDiv);
}
// Generate AI response to user answer using server-side AI
async generateAIResponseToAnswer(answer, stepIndex, responseDiv) {
console.log('🚀 generateAIResponseToAnswer called with:', { answer, stepIndex });
try {
// Show loading state
responseDiv.innerHTML = `
<div class="ai-response-content">
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
<p>${this.getTranslation('thinking-about-answer')}</p>
</div>
</div>
`;
responseDiv.style.display = 'block';
// Get current question context
const currentQuestion = this.currentSteps && this.currentSteps[stepIndex]
? this.currentSteps[stepIndex].text
: 'the current question';
// Analyze the answer to determine the appropriate response type
const answerLower = answer.toLowerCase().trim();
const isNegative = answerLower === 'no' || answerLower === 'nein' || answerLower === 'nope' || answerLower === 'nei';
// Check for pure "don't know" responses (without additional thinking)
const hasDontKnowPhrase = answerLower.includes("don't know") || answerLower.includes('weiß nicht') || answerLower.includes('keine ahnung') ||
answerLower.includes('ich weiß es nicht') || answerLower.includes('weis es nicht') || answerLower.includes('weiss es nicht') ||
answerLower.includes('i dont know') || answerLower.includes("i don't know");
const isOnlyWhyQuestion = answerLower === 'warum' || answerLower === 'why' || answerLower === 'warum?' || answerLower === 'why?';
// Check if child is explicitly asking for help or the answer
const isAskingForHelp = answerLower.includes('bitte verrate es mir') || answerLower.includes('please tell me') ||
answerLower.includes('was bedeutet es') || answerLower.includes('what does it mean') ||
answerLower.includes('wie komme ich zur') || answerLower.includes('how do i get to') ||
answerLower.includes('finalen antwort') || answerLower.includes('final answer') ||
answerLower.includes('komme nicht drauf') || answerLower.includes("can't figure it out") ||
answerLower.includes('verrate mir') || answerLower.includes('tell me the answer');
// Enhanced confusion detection
const isExpressingConfusion = answerLower.includes('verstehe nicht') || answerLower.includes("don't understand") ||
answerLower.includes('versteh das nicht') || answerLower.includes('verstehe es nicht') ||
answerLower.includes('ich verstehe nicht warum') || answerLower.includes("i don't understand why") ||
answerLower.includes('aber ich verstehe nicht') || answerLower.includes("but i don't understand") ||
answerLower.includes('verstehe den zusammenhang nicht') || answerLower.includes("don't understand the connection") ||
answerLower.includes('das erklärt nicht') || answerLower.includes("that doesn't explain") ||
answerLower.includes('das beantwortet nicht') || answerLower.includes("that doesn't answer") ||
answerLower.includes('hab ich doch schon gesagt') || answerLower.includes('already said that') ||
answerLower.includes('schon gesagt') || answerLower.includes('already told you') ||
answerLower.includes('fällt mir nicht ein') || answerLower.includes("can't think of") ||
answerLower.includes('mehr fällt mir nicht ein') || isAskingForHelp;
// Check if it's a substantial answer (has thinking beyond just "don't know")
const hasSubstantialThinking = answer.length > 15 && (
answerLower.includes('vielleicht') || answerLower.includes('maybe') || answerLower.includes('könnte') || answerLower.includes('could') ||
answerLower.includes('hat es') || answerLower.includes('does it') || answerLower.includes('is it') || answerLower.includes('liegt es') ||
answerLower.includes('temperatur') || answerLower.includes('temperature') || answerLower.includes('wetter') || answerLower.includes('weather') ||
answer.includes('?') // Contains a question showing thinking
);
// Pure "don't know" without additional thinking
const isPureDontKnow = (hasDontKnowPhrase || isOnlyWhyQuestion || answer.trim().length < 5) && !hasSubstantialThinking && !isExpressingConfusion && !isAskingForHelp;
// Check conversation history for repeated "don't know" responses (Chat Mode)
const conversationHistoryChat = Array.from(this.conversationContainer.querySelectorAll('.user-message .message-content'))
.map(el => el.textContent.toLowerCase().trim())
.slice(-4); // Last 4 user responses
console.log('🔍 Recent conversation history (Chat):', conversationHistoryChat);
const recentDontKnowCountChat = conversationHistoryChat.filter(msg =>
msg.includes('weiß nicht') || msg.includes('weis nicht') || msg.includes('weiss nicht') ||
msg.includes("don't know") || msg.includes('i dont know') || msg.includes('keine ahnung') ||
msg.includes('das weiß ich nicht') || msg.includes('das weiss ich nicht') ||
msg.includes('das weis ich nicht') || msg.includes('weiß ich auch nicht')
).length;
console.log(`🔢 Recent "don't know" count (Chat): ${recentDontKnowCountChat}`);
// If child has said "don't know" 2 or more times recently, they need help
const needsExplanationDueToRepeatedDontKnowChat = recentDontKnowCountChat >= 2;
let response;
if (isExpressingConfusion || needsExplanationDueToRepeatedDontKnowChat) {
// Child is expressing confusion or repeatedly saying "don't know" - provide a simple explanation
console.log('📤 Sending explanation request for confused child or repeated dont know (Chat mode)');
const contextReason = needsExplanationDueToRepeatedDontKnowChat ? 'repeated_dont_know' : 'confusion_explanation';
response = await fetch('/api/respond-to-answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
answer: answer,
question: currentQuestion,
originalTopic: originalQuestion,
language: this.currentLanguage,
context: contextReason,
stepIndex: questionIndex,
instructions: needsExplanationDueToRepeatedDontKnowChat
? (this.currentLanguage === 'de'
? 'Das Kind braucht jetzt eine einfache, klare Erklärung. Es hat bereits mehrmals "weiß nicht" gesagt. Gib eine vollständige Antwort mit praktischen Beispielen. Erkläre das Konzept Schritt für Schritt mit alltäglichen Vergleichen. Keine weiteren Fragen - das Kind braucht Wissen!'
: 'The child needs a simple, clear explanation now. They have said "don\'t know" multiple times. Give a complete answer with practical examples. Explain the concept step by step with everyday comparisons. No more questions - the child needs knowledge!')
: (this.currentLanguage === 'de'
? 'Das Kind ist verwirrt und braucht eine einfache Erklärung. Gib eine klare, konkrete Antwort für Kinder. Erkläre das Konzept mit alltäglichen Beispielen. Verwende einfache Wörter und lade zum Ausprobieren ein. Keine weiteren Fragen stellen - erst erklären!'
: 'The child is confused and needs a simple explanation. Give a clear, concrete answer for children. Explain the concept with everyday examples. Use simple words and invite experimentation. Don\'t ask more questions - explain first!')
})
});
} else if (isNegative || isPureDontKnow) {
// For pure "no" or "don't know" answers without thinking, get Socratic guidance questions
console.log('📤 Sending guidance request to /api/ask for Socratic questioning');
const guidancePrompt = this.currentLanguage === 'de'
? `Ein Kind hat "${answer}" geantwortet auf die Frage "${currentQuestion}". Das Kind weiß die Antwort nicht. Führe es durch 2-3 aufbauende Socratic Fragen zur Entdeckung, ohne direkte Antworten zu geben. Beginne mit einfachen Beobachtungen, die das Kind kennt.`
: `A child answered "${answer}" to the question "${currentQuestion}". The child doesn't know the answer. Guide them through 2-3 building Socratic questions to discovery without giving direct answers. Start with simple observations the child would know.`;
response = await fetch('/api/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
question: guidancePrompt,
language: this.currentLanguage
})
});
} else {
// For substantial answers, acknowledge and validate
console.log('📤 Sending validation request to /api/respond-to-answer');
response = await fetch('/api/respond-to-answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
answer: answer,
question: currentQuestion,
language: this.currentLanguage,
stepIndex: stepIndex
})
});
}
console.log('📥 Server response status:', response.status);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('✅ Server response data:', data);
let responseContent = '';
if (data.success) {
if (data.guidance && data.guidance.steps) {
// Response from /api/ask with Socratic guidance steps
const steps = data.guidance.steps.slice(0, 3); // Limit to 3 steps
responseContent = steps.map((step, index) =>
`<p><strong>${index + 1}.</strong> ${step.text}</p>`
).join('');
} else if (data.response) {
// Simple response from /api/respond-to-answer
responseContent = `<p>${data.response}</p>`;
} else {
// Fallback
responseContent = this.currentLanguage === 'de'
? '<p>🤔 Das ist eine interessante Frage! Lass uns zusammen darüber nachdenken...</p>'
: '<p>🤔 That\'s an interesting question! Let\'s think about it together...</p>';
}
responseDiv.innerHTML = `
<div class="ai-response-content">
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
${responseContent}
</div>
</div>
`;
} else {
throw new Error(data.error || 'Failed to generate response');
}
} catch (error) {
console.error('❌ Error generating AI response:', error);
// Fallback response
responseDiv.innerHTML = `
<div class="ai-response-content">
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
<p>${this.getTranslation('great-thinking-fallback')}</p>
</div>
</div>
`;
}
// Show next question or reveal option after response
setTimeout(() => {
const nextStepIndex = stepIndex + 1;
const nextStep = document.querySelector(`.step-${nextStepIndex}`);
if (nextStep) {
// Show next question after a delay
setTimeout(() => {
nextStep.classList.add('visible');
nextStep.scrollIntoView({ behavior: 'smooth' });
}, 1500);
} else {
// All questions answered, show reveal option
setTimeout(() => {
const revealSection = document.querySelector('.reveal-section');
if (revealSection) {
revealSection.style.display = 'block';
revealSection.scrollIntoView({ behavior: 'smooth' });
}
}, 2000);
}
}, 500);
}
// Generate AI response for chat system
async generateChatAIResponse(answer, questionIndex) {
console.log('🚀 generateChatAIResponse called with:', { answer, questionIndex });
try {
// Get current question context
const currentQuestion = this.questions && this.questions[questionIndex]
? this.questions[questionIndex]
: 'the current question';
// Get the original topic for better context
const originalQuestion = this.questionInput ? this.questionInput.value.trim() : '';
// Analyze the answer to determine the appropriate response type
const answerLower = answer.toLowerCase().trim();
const isNegative = answerLower === 'no' || answerLower === 'nein' || answerLower === 'nope' || answerLower === 'nei';
// Check for pure "don't know" responses (without additional thinking)
const hasDontKnowPhrase = answerLower.includes("don't know") || answerLower.includes('weiß nicht') || answerLower.includes('weis nicht') ||
answerLower.includes('weiss nicht') || answerLower.includes('keine ahnung') || answerLower.includes('keinen plan') ||
answerLower.includes('ich weiß es nicht') || answerLower.includes('weis es nicht') || answerLower.includes('weiss es nicht') ||
answerLower.includes('i dont know') || answerLower.includes("i don't know") || answerLower.includes('hab keine ahnung');
const isOnlyWhyQuestion = answerLower === 'warum' || answerLower === 'why' || answerLower === 'warum?' || answerLower === 'why?';
// Check if child is explicitly asking for help or the answer
const isAskingForHelp = answerLower.includes('bitte verrate es mir') || answerLower.includes('please tell me') ||
answerLower.includes('was bedeutet es') || answerLower.includes('what does it mean') ||
answerLower.includes('wie komme ich zur') || answerLower.includes('how do i get to') ||
answerLower.includes('finalen antwort') || answerLower.includes('final answer') ||
answerLower.includes('komme nicht drauf') || answerLower.includes("can't figure it out") ||
answerLower.includes('verrate mir') || answerLower.includes('tell me the answer');
// Enhanced confusion detection
const isExpressingConfusion = answerLower.includes('verstehe nicht') || answerLower.includes("don't understand") ||
answerLower.includes('versteh das nicht') || answerLower.includes('verstehe es nicht') ||
answerLower.includes('ich verstehe nicht warum') || answerLower.includes("i don't understand why") ||
answerLower.includes('aber ich verstehe nicht') || answerLower.includes("but i don't understand") ||
answerLower.includes('verstehe den zusammenhang nicht') || answerLower.includes("don't understand the connection") ||
answerLower.includes('das erklärt nicht') || answerLower.includes("that doesn't explain") ||
answerLower.includes('das beantwortet nicht') || answerLower.includes("that doesn't answer") ||
answerLower.includes('hab ich doch schon gesagt') || answerLower.includes('already said that') ||
answerLower.includes('schon gesagt') || answerLower.includes('already told you') ||
answerLower.includes('fällt mir nicht ein') || answerLower.includes("can't think of") ||
answerLower.includes('mehr fällt mir nicht ein') || isAskingForHelp;
// Check if it's a substantial answer (has thinking beyond "don't know")
const hasSubstantialThinking = answer.length > 15 && (
answerLower.includes('vielleicht') || answerLower.includes('maybe') || answerLower.includes('könnte') || answerLower.includes('could') ||
answerLower.includes('hat es') || answerLower.includes('does it') || answerLower.includes('is it') || answerLower.includes('liegt es') ||
answerLower.includes('temperatur') || answerLower.includes('temperature') || answerLower.includes('wetter') || answerLower.includes('weather') ||
answer.includes('?') // Contains a question showing thinking
);
// Pure "don't know" without additional thinking
const isPureDontKnow = (hasDontKnowPhrase || isOnlyWhyQuestion || answer.trim().length < 5) && !hasSubstantialThinking && !isExpressingConfusion && !isAskingForHelp;
// Check conversation history for repeated "don't know" responses
const conversationHistory = Array.from(this.conversationContainer.querySelectorAll('.user-message .message-content'))
.map(el => el.textContent.toLowerCase().trim())
.slice(-4); // Last 4 user responses
console.log('🔍 Recent conversation history:', conversationHistory);
const recentDontKnowCount = conversationHistory.filter(msg =>
msg.includes('weiß nicht') || msg.includes('weis nicht') || msg.includes('weiss nicht') ||
msg.includes("don't know") || msg.includes('i dont know') || msg.includes('keine ahnung') ||
msg.includes('das weiß ich nicht') || msg.includes('das weiss ich nicht') ||
msg.includes('das weis ich nicht') || msg.includes('weiß ich auch nicht')
).length;
console.log(`🔢 Recent "don't know" count: ${recentDontKnowCount}`);
// If child has said "don't know" 2 or more times recently, they need help
const needsExplanationDueToRepeatedDontKnow = recentDontKnowCount >= 2;
// Check if child is asking for a definition or explanation
const isAskingForDefinition = answerLower.startsWith('was ist') || answerLower.startsWith('what is') ||
answerLower.includes('was bedeutet') || answerLower.includes('what does') ||
answerLower.includes('was heißt') || answerLower.includes('what means') ||
answerLower.includes('was hat') || answerLower.includes('what has') ||
answerLower.includes('wo ist') || answerLower.includes('where is') ||
answerLower.includes('wo sind') || answerLower.includes('where are') ||
answerLower.includes('wie funktioniert') || answerLower.includes('how does') ||
answerLower.includes('warum ist') || answerLower.includes('why is') ||
(answerLower.includes('?') && (answerLower.includes('ist ein') || answerLower.includes('is a')));
let response;
if (isExpressingConfusion || isAskingForHelp || needsExplanationDueToRepeatedDontKnow) {
// Child is expressing confusion, asking for help, or repeatedly saying "don't know" - provide explanation
console.log('📤 Sending explanation request for confused child, help request, or repeated dont know');
const contextReason = needsExplanationDueToRepeatedDontKnow ? 'repeated_dont_know' : 'confusion_explanation';
response = await fetch('/api/respond-to-answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
answer: answer,
question: currentQuestion,
originalTopic: originalQuestion,
language: this.currentLanguage,
context: contextReason,
stepIndex: questionIndex,
instructions: needsExplanationDueToRepeatedDontKnow
? (this.currentLanguage === 'de'
? 'Das Kind braucht jetzt eine einfache, klare Erklärung. Es hat bereits mehrmals "weiß nicht" gesagt oder ist verwirrt. Gib eine vollständige Antwort mit praktischen Beispielen. Erkläre das Konzept Schritt für Schritt mit alltäglichen Vergleichen. Keine weiteren Fragen - das Kind braucht Wissen!'
: 'The child needs a simple, clear explanation now. They have said "don\'t know" multiple times or are confused. Give a complete answer with practical examples. Explain the concept step by step with everyday comparisons. No more questions - the child needs knowledge!')
: (this.currentLanguage === 'de'
? 'Das Kind ist verwirrt und braucht eine einfache Erklärung. Gib eine klare, konkrete Antwort für Kinder. Erkläre das Konzept mit alltäglichen Beispielen. Verwende einfache Worte und lade zum Experimentieren ein. Keine weiteren Fragen - erst erklären!'
: 'The child is confused and needs a simple explanation. Give a clear, concrete answer for children. Explain the concept with everyday examples. Use simple words and invite experimentation. Don\'t ask more questions - explain first!')
})
});
} else if (isAskingForDefinition) {
// Child is asking for a definition - provide a clear definition response
console.log('📤 Sending definition response request');
response = await fetch('/api/respond-to-answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
answer: answer,
question: currentQuestion,
originalTopic: originalQuestion,
language: this.currentLanguage,
context: 'definition_request',
stepIndex: questionIndex,
instructions: this.currentLanguage === 'de'
? 'Das Kind fragt nach einer Definition. Gib eine klare, kindgerechte Definition des Begriffs. Verwende einfache Sprache und Beispiele, die das Kind kennt. Lade das Kind ein, mehr Fragen zu stellen oder das Konzept zu erkunden.'
: 'The child is asking for a definition. Provide a clear, child-friendly definition of the term. Use simple language and examples the child would know. Invite the child to ask more questions or explore the concept.'
})
});
} else if (isNegative || isPureDontKnow) {
// For pure "no" or "don't know" answers without thinking, get Socratic guidance questions
console.log('📤 Sending guidance request to /api/ask for Socratic questioning');
const guidancePrompt = this.currentLanguage === 'de'
? `Ein Kind hat "${answer}" geantwortet auf die Frage "${currentQuestion}" über das Thema "${originalQuestion}". Das Kind weiß die Antwort nicht und braucht einfachere Grundlagen. Gib KEINE weiteren abstrakten Fragen! Stattdessen: 1) Beschreibe eine einfache Beobachtung, die das Kind machen kann (z.B. "Hast du schon mal Licht durch ein Glas Wasser gesehen?") 2) Lade zum praktischen Ausprobieren ein 3) Baue auf dem auf, was das Kind bereits kennt. Verwende konkrete, sichtbare Beispiele statt abstrakter Konzepte.`
: `A child answered "${answer}" to the question "${currentQuestion}" about the topic "${originalQuestion}". The child doesn't know and needs simpler foundations. Give NO more abstract questions! Instead: 1) Describe a simple observation the child can make (e.g. "Have you ever seen light through a glass of water?") 2) Invite practical experimentation 3) Build on what the child already knows. Use concrete, visible examples instead of abstract concepts.`;
response = await fetch('/api/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
question: guidancePrompt,
language: this.currentLanguage
})
});
} else {
// For substantial answers, acknowledge and validate
console.log('📤 Sending validation request to /api/respond-to-answer');
response = await fetch('/api/respond-to-answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
answer: answer,
question: currentQuestion,
language: this.currentLanguage,
stepIndex: questionIndex
})
});
}
console.log('📥 Chat server response status:', response.status);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('✅ Chat server response data:', data);
let responseContent = '';
if (data.success) {
if (data.guidance && data.guidance.steps) {
// Response from /api/ask with Socratic guidance steps
const steps = data.guidance.steps.slice(0, 3); // Limit to 3 steps
responseContent = steps.map((step, index) =>
`<p><strong>${index + 1}.</strong> ${step.text}</p>`
).join('');
} else if (data.response) {
// Simple response from /api/respond-to-answer
responseContent = `<p>${data.response}</p>`;
} else {
// Fallback
responseContent = this.currentLanguage === 'de'
? '<p>🤔 Das ist eine interessante Frage! Lass uns zusammen darüber nachdenken...</p>'
: '<p>🤔 That\'s an interesting question! Let\'s think about it together...</p>';
}
// Add AI response bubble
const responseBubble = document.createElement('div');
responseBubble.className = 'chat-message ai-message';
responseBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
${responseContent}
</div>
`;
this.conversationContainer.appendChild(responseBubble);
// Show AI response with animation
setTimeout(() => {
responseBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
// Determine next action based on response type
setTimeout(() => {
if (data.guidance && data.guidance.steps && (isNegative || isPureDontKnow)) {
// For pure "don't know" responses with Socratic guidance, continue to next question immediately
this.continueToNextQuestion();
} else {
// Check if AI response contains a question that needs answering
const hasQuestion = data.response && data.response.includes('?');
// Check if AI response contains explanations or new concepts that might trigger questions
const containsExplanation = data.response && (
data.response.includes('passiert, weil') || data.response.includes('happens because') ||
data.response.includes('Das liegt daran') || data.response.includes('This is because') ||
data.response.includes('Prisma') || data.response.includes('prism') ||
data.response.includes('Licht') || data.response.includes('light') ||
data.response.includes('besteht aus') || data.response.includes('consists of') ||
data.response.includes('brechen') || data.response.includes('break') ||
data.response.length > 150 // Longer responses likely contain explanations
);
if (hasQuestion || containsExplanation) {
// AI asked a question or gave an explanation - provide input area for follow-up questions
this.addUserInputArea();
} else {
// Simple response without question or explanation, show choice buttons
this.addContinueChoiceButtons();
}
}
}, 1500);
} else {
throw new Error(data.error || 'Failed to generate response');
}
} catch (error) {
console.error('❌ Error generating chat AI response:', error);
// Fallback response
const responseBubble = document.createElement('div');
responseBubble.className = 'chat-message ai-message';
responseBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
<p>${this.currentLanguage === 'de'
? 'Interessant! Lass uns das mal genauer betrachten... Was denkst du, was als nächstes passieren könnte? 🤔'
: 'Interesting! Let\'s look at this more closely... What do you think might happen next? 🤔'}</p>
</div>
`;
this.conversationContainer.appendChild(responseBubble);
setTimeout(() => {
responseBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
setTimeout(() => {
this.addContinueChoiceButtons();
}, 1500);
}
}
addContinueChoiceButtons() {
// Get translations before creating HTML to avoid context issues
const exploreDeeperText = this.getTranslation('explore-deeper') || (this.currentLanguage === 'de' ? "Ich möchte das tiefer erforschen" : "I want to explore this deeper");
const continueLearningText = this.getTranslation('continue-learning') || (this.currentLanguage === 'de' ? "Mit dem nächsten Thema fortfahren" : "Continue with next topic");
const tellMeMoreText = this.getTranslation('tell-me-more') || (this.currentLanguage === 'de' ? "Erzähl mir mehr! 🤔" : "Tell me more! 🤔");
const nextQuestionText = this.getTranslation('next-question') || (this.currentLanguage === 'de' ? "Nächste Frage! ➡️" : "Next question! ➡️");
const choiceContainer = document.createElement('div');
choiceContainer.className = 'choice-container';
choiceContainer.innerHTML = `
<div class="choice-prompt">
<p>💭 ${exploreDeeperText} ${this.currentLanguage === 'de' ? 'oder' : 'or'} ${continueLearningText}?</p>
</div>
<div class="choice-buttons">
<button class="choice-btn explore-btn" onclick="kidsAI.exploreCurrentTopicDeeper()">
<span class="btn-icon">🔍</span> ${tellMeMoreText}
</button>
<button class="choice-btn next-btn" onclick="kidsAI.continueToNextQuestion()">
<span class="btn-icon">➡️</span> ${nextQuestionText}
</button>
</div>
`;
this.conversationContainer.appendChild(choiceContainer);
// Animate in the choices
setTimeout(() => {
choiceContainer.classList.add('visible');
this.scrollToBottomSmoothly();
}, 200);
}
// Handle choice to explore current topic deeper
async exploreCurrentTopicDeeper() {
// Remove choice buttons
const choiceContainer = document.querySelector('.choice-container');
if (choiceContainer) {
choiceContainer.remove();
}
// Get the current question and user's last answer for context
const currentQuestion = this.questions[this.currentQuestionIndex];
const lastUserMessage = Array.from(this.conversationContainer.querySelectorAll('.user-message'))
.pop()?.querySelector('.message-content p')?.textContent || '';
try {
// Request deeper exploration from the server
const response = await fetch('/api/explore-deeper', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
question: currentQuestion,
userAnswer: lastUserMessage,
language: this.currentLanguage,
context: 'deeper_exploration',
instructions: this.currentLanguage === 'de'
? 'Stelle eine faszinierende Folgefrage, die das Kind dazu bringt, tiefer über das Thema nachzudenken. Verwende "Was würde passieren wenn...?" oder "Hast du schon mal bemerkt...?" Ermutige zur Beobachtung und zum Experimentieren.'
: 'Ask a fascinating follow-up question that makes the child think deeper about the topic. Use "What would happen if...?" or "Have you ever noticed...?" Encourage observation and experimentation.'
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.success && data.response) {
// Add deeper exploration response
const explorationBubble = document.createElement('div');
explorationBubble.className = 'chat-message ai-message exploration';
explorationBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
<p>${data.response}</p>
</div>
`;
this.conversationContainer.appendChild(explorationBubble);
setTimeout(() => {
explorationBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
// Check if the response contains a question that needs an answer
const hasQuestion = data.response.includes('?');
if (hasQuestion) {
// Add input area for user to respond to the deeper exploration question
setTimeout(() => {
this.addDeeperExplorationInputArea();
}, 1500);
} else {
// No question, just add choice buttons again
setTimeout(() => {
this.addContinueChoiceButtons();
}, 2000);
}
} else {
throw new Error(data.error || 'Failed to get deeper exploration');
}
} catch (error) {
console.error('❌ Error exploring deeper:', error);
// Fallback deeper exploration
const explorationBubble = document.createElement('div');
explorationBubble.className = 'chat-message ai-message exploration';
explorationBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
<p>${this.currentLanguage === 'de'
? '🔍 Das ist wirklich faszinierend! Hast du schon mal beobachtet, was passiert, wenn du durch ein Prisma oder ein Wasserglas schaust? Was könntest du damit entdecken?'
: '🔍 This is really fascinating! Have you ever observed what happens when you look through a prism or a water glass? What could you discover with that?'}</p>
</div>
`;
this.conversationContainer.appendChild(explorationBubble);
setTimeout(() => {
explorationBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
// This fallback has a question, so add input area
setTimeout(() => {
this.addDeeperExplorationInputArea();
}, 1500);
}
}
// Add input area specifically for deeper exploration questions
addDeeperExplorationInputArea() {
const inputContainer = document.createElement('div');
inputContainer.className = 'user-input-container deeper-exploration';
inputContainer.innerHTML = `
<div class="input-prompt">
<p>💭 ${this.getTranslation('share-thoughts') || (this.currentLanguage === 'de' ? 'Teile deine Gedanken mit:' : 'Share your thoughts:')}</p>
</div>
<div class="input-area">
<textarea id="deeper-chat-input" placeholder="${this.getTranslation('type-thoughts') || (this.currentLanguage === 'de' ? 'Schreibe hier deine Gedanken...' : 'Type your thoughts here...')}"
rows="3" style="width: 100%; padding: 10px; border-radius: 8px; border: 2px solid #e2e8f0; font-size: 14px;"></textarea>
<button onclick="kidsAI.submitDeeperExplorationAnswer()" class="submit-btn" style="margin-top: 10px; padding: 10px 20px; background: #4ade80; color: white; border: none; border-radius: 8px; cursor: pointer;">
${this.getTranslation('submit') || (this.currentLanguage === 'de' ? 'Abschicken' : 'Submit')} 🚀
</button>
</div>
`;
this.conversationContainer.appendChild(inputContainer);
// Show input area with animation
setTimeout(() => {
inputContainer.classList.add('visible');
this.scrollToBottomSmoothly();
// Focus on textarea
const textarea = inputContainer.querySelector('#deeper-chat-input');
if (textarea) {
textarea.focus();
}
}, 200);
}
// Submit answer for deeper exploration
submitDeeperExplorationAnswer() {
const textarea = document.getElementById('deeper-chat-input');
if (!textarea) {
console.error('❌ Deeper chat input not found');
return;
}
const answer = textarea.value.trim();
if (!answer) {
const message = this.getTranslation('write-thoughts') || (this.currentLanguage === 'de' ? 'Bitte schreibe deine Gedanken auf! 🤔' : 'Please write down your thoughts! 🤔');
this.showMessage(message, 'warning');
return;
}
// Add user message bubble
const userBubble = document.createElement('div');
userBubble.className = 'chat-message user-message';
userBubble.innerHTML = `
<div class="message-header">
<span class="user-avatar">👤</span>
<span class="user-label">${this.getTranslation('you') || (this.currentLanguage === 'de' ? 'Du' : 'You')}</span>
</div>
<div class="message-content">
<p>${answer}</p>
</div>
`;
// Remove input container and add user message
const inputContainer = document.querySelector('.user-input-container.deeper-exploration');
if (inputContainer) {
inputContainer.remove();
}
this.conversationContainer.appendChild(userBubble);
// Show user message with animation
setTimeout(() => {
userBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
// Generate AI response to the deeper exploration answer
setTimeout(() => {
this.generateDeeperExplorationResponse(answer);
}, 500);
}
// Generate AI response to deeper exploration answer
async generateDeeperExplorationResponse(answer) {
console.log('🚀 generateDeeperExplorationResponse called with:', answer);
try {
// Get the last AI question for context
const lastAIMessages = Array.from(this.conversationContainer.querySelectorAll('.ai-message.exploration'));
const lastExplorationQuestion = lastAIMessages.length > 0
? lastAIMessages[lastAIMessages.length - 1].querySelector('.message-content p')?.textContent || ''
: '';
console.log('📤 Sending deeper exploration response request:', { answer, lastExplorationQuestion });
// Call server API for contextual response
const response = await fetch('/api/respond-to-answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
answer: answer,
question: lastExplorationQuestion,
language: this.currentLanguage,
context: 'deeper_exploration_response',
instructions: this.currentLanguage === 'de'
? 'Du hilfst einem Kind beim tieferen Verstehen. Gib KEINE direkten Antworten oder Erklärungen. Stelle interessante Folgefragen, die das Kind zum Experimentieren oder Beobachten ermutigen. Verwende Analogien und lade zu eigenen Entdeckungen ein.'
: 'You are helping a child understand deeper. Give NO direct answers or explanations. Ask interesting follow-up questions that encourage the child to experiment or observe. Use analogies and invite them to make their own discoveries.'
})
});
console.log('📥 Deeper exploration response status:', response.status);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('✅ Deeper exploration response data:', data);
if (data.success && data.response) {
// Add AI response bubble
const responseBubble = document.createElement('div');
responseBubble.className = 'chat-message ai-message';
responseBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
<p>${data.response}</p>
</div>
`;
this.conversationContainer.appendChild(responseBubble);
// Show AI response with animation
setTimeout(() => {
responseBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
// Add choice buttons after response to continue or move on
setTimeout(() => {
this.addContinueChoiceButtons();
}, 1500);
} else {
throw new Error(data.error || 'Failed to generate response');
}
} catch (error) {
console.error('❌ Error generating deeper exploration response:', error);
// Fallback response
const responseBubble = document.createElement('div');
responseBubble.className = 'chat-message ai-message';
responseBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher')}</span>
</div>
<div class="message-content">
<p>${this.currentLanguage === 'de'
? 'Hmm, das ist eine spannende Beobachtung! Was glaubst du, könnten wir herausfinden, wenn wir das genauer untersuchen? 🔍'
: 'Hmm, that\'s an exciting observation! What do you think we could discover if we investigate this more closely? 🔍'}</p>
</div>
`;
this.conversationContainer.appendChild(responseBubble);
setTimeout(() => {
responseBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
setTimeout(() => {
this.addContinueChoiceButtons();
}, 1500);
}
}
// Handle choice to continue to next question
continueToNextQuestion() {
// Remove choice buttons
const choiceContainer = document.querySelector('.choice-container');
if (choiceContainer) {
choiceContainer.remove();
}
// Move to next question
this.currentQuestionIndex++;
this.askNextQuestion();
}
// Ask the next question in the conversation
askNextQuestion() {
console.log('❓ askNextQuestion called, currentQuestionIndex:', this.currentQuestionIndex);
if (!this.questions || this.currentQuestionIndex >= this.questions.length) {
console.log('✅ All questions completed');
this.showCompletionMessage();
return;
}
const question = this.questions[this.currentQuestionIndex];
// Add AI question bubble
const questionBubble = document.createElement('div');
questionBubble.className = 'chat-message ai-message';
questionBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher') || 'AI Teacher'}</span>
</div>
<div class="message-content">
<p>${question}</p>
</div>
`;
this.conversationContainer.appendChild(questionBubble);
// Show question with animation
setTimeout(() => {
questionBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
// Add input area for user response
setTimeout(() => {
this.addUserInputArea();
}, 1000);
}
// Add input area for user to respond
addUserInputArea() {
// Remove any existing input areas to avoid duplicates
const existingInputs = this.conversationContainer.querySelectorAll('.user-input-container');
existingInputs.forEach(input => input.remove());
// Generate unique ID for this input
const inputId = `chat-input-${Date.now()}`;
const inputContainer = document.createElement('div');
inputContainer.className = 'user-input-container';
inputContainer.innerHTML = `
<div class="input-prompt">
<p>💭 ${this.getTranslation('share-thoughts') || (this.currentLanguage === 'de' ? 'Teile deine Gedanken mit:' : 'Share your thoughts:')}</p>
</div>
<div class="input-area">
<textarea id="${inputId}" placeholder="${this.getTranslation('type-thoughts') || (this.currentLanguage === 'de' ? 'Schreibe hier deine Gedanken...' : 'Type your thoughts here...')}"
rows="3" style="width: 100%; padding: 10px; border-radius: 8px; border: 2px solid #e2e8f0; font-size: 14px;"></textarea>
<button onclick="kidsAI.submitChatAnswerFromInput('${inputId}')" class="submit-btn" style="margin-top: 10px; padding: 10px 20px; background: #4ade80; color: white; border: none; border-radius: 8px; cursor: pointer;">
${this.getTranslation('submit') || (this.currentLanguage === 'de' ? 'Abschicken' : 'Submit')} 🚀
</button>
</div>
`;
this.conversationContainer.appendChild(inputContainer);
// Show input area with animation
setTimeout(() => {
inputContainer.classList.add('visible');
this.scrollToBottomSmoothly();
// Focus on textarea
const textarea = inputContainer.querySelector(`#${inputId}`);
if (textarea) {
textarea.focus();
}
}, 200);
}
// Submit chat answer from dynamic input with specific ID
submitChatAnswerFromInput(inputId) {
const textarea = document.getElementById(inputId);
if (!textarea) {
console.error('❌ Chat input not found with ID:', inputId);
return;
}
const answer = textarea.value.trim();
if (!answer) {
const message = this.getTranslation('write-thoughts') || (this.currentLanguage === 'de' ? 'Bitte schreibe deine Gedanken auf! 🤔' : 'Please write down your thoughts! 🤔');
this.showMessage(message, 'warning');
return;
}
// Add user message bubble
const userBubble = document.createElement('div');
userBubble.className = 'chat-message user-message';
userBubble.innerHTML = `
<div class="message-header">
<span class="user-avatar">👤</span>
<span class="user-label">${this.getTranslation('you') || (this.currentLanguage === 'de' ? 'Du' : 'You')}</span>
</div>
<div class="message-content">
<p>${answer}</p>
</div>
`;
// Remove input container and add user message
const inputContainer = document.querySelector('.user-input-container');
if (inputContainer) {
inputContainer.remove();
}
this.conversationContainer.appendChild(userBubble);
// Show user message with animation
setTimeout(() => {
userBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
// Generate AI response
setTimeout(() => {
this.generateChatAIResponse(answer, this.currentQuestionIndex);
}, 500);
}
// Show completion message when all questions are done
showCompletionMessage() {
const completionBubble = document.createElement('div');
completionBubble.className = 'chat-message ai-message completion';
completionBubble.innerHTML = `
<div class="message-header">
<span class="ai-avatar">🤖</span>
<span class="ai-label">${this.getTranslation('ai-teacher') || 'AI Teacher'}</span>
</div>
<div class="message-content">
<p>🎉 ${this.getTranslation('great-exploration') || 'Wow! You did a great job exploring this topic! You\'re thinking like a real scientist!'}</p>
<p>💡 ${this.getTranslation('keep-wondering') || 'Keep wondering about the world around you - that\'s how we make amazing discoveries!'}</p>
</div>
`;
this.conversationContainer.appendChild(completionBubble);
setTimeout(() => {
completionBubble.classList.add('visible');
this.scrollToBottomSmoothly();
}, 100);
}
// Smooth scroll to bottom of conversation
scrollToBottomSmoothly() {
if (this.conversationContainer) {
this.conversationContainer.scrollIntoView({ behavior: 'smooth', block: 'end' });
}
}
// ...existing code...
}
// Global variable for external access
let kidsAI;
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
console.log('🚀 DOM loaded, initializing KidsAI Explorer...');
try {
kidsAI = new KidsAIExplorer();
window.kidsAI = kidsAI; // Make globally accessible
console.log('✅ KidsAI Explorer initialized successfully');
// Add visual indicator
const indicator = document.createElement('div');
indicator.innerHTML = '✅ KidsAI Ready!';
indicator.style.cssText = 'position:fixed;top:10px;left:10px;background:green;color:white;padding:5px;z-index:9999;border-radius:5px;font-size:12px;';
document.body.appendChild(indicator);
// Remove indicator after 3 seconds
setTimeout(() => indicator.remove(), 3000);
} catch (error) {
console.error('❌ Error initializing KidsAIExplorer:', error);
// Show error indicator
const indicator = document.createElement('div');
indicator.innerHTML = '❌ KidsAI Error: ' + error.message;
indicator.style.cssText = 'position:fixed;top:10px;left:10px;background:red;color:white;padding:5px;z-index:9999;border-radius:5px;font-size:12px;';
document.body.appendChild(indicator);
}
});
console.log('📜 KidsAI script-new.js loaded');