Files
kidsai/html/kidsai/script-new.js
root b7c7bbfcb1 🔧 Fix Socratic teaching logic
- Fixed the critical issue where AI was giving direct answers instead of asking guiding questions
- Now when child answers 'no' or 'don't know', system calls /api/ask for Socratic guidance
- When child gives substantial answers, system calls /api/respond-to-answer for validation
- Applied fix to both chat mode and step-by-step mode
- Enhanced answer analysis to detect negative/unknown responses vs substantial answers
- Updated response handling to work with both guidance format and simple response format

This ensures the AI acts as a true Socratic teacher, guiding discovery rather than giving answers.
2025-06-30 11:32:19 +02:00

1207 lines
51 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';
const isDontKnow = answerLower.includes("don't know") || answerLower.includes('weiß nicht') || answerLower.includes('keine ahnung') || answer.trim().length < 3;
let response;
if (isNegative || isDontKnow) {
// For "no" or "don't know" answers, 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}". Führe es durch Socratic Fragen zur Entdeckung, ohne direkte Antworten zu geben.`
: `A child answered "${answer}" to the question "${currentQuestion}". Guide them through Socratic questions to discovery without giving direct answers.`;
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';
const isDontKnow = answerLower.includes("don't know") || answerLower.includes('weiß nicht') || answerLower.includes('keine ahnung') || answer.trim().length < 3;
let response;
if (isNegative || isDontKnow) {
// For "no" or "don't know" answers, 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}". Führe es durch Socratic Fragen zur Entdeckung, ohne direkte Antworten zu geben.`
: `A child answered "${answer}" to the question "${currentQuestion}" about the topic "${originalQuestion}". Guide them through Socratic questions to discovery without giving direct answers.`;
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,
originalTopic: originalQuestion,
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);
// Add choice buttons after AI response
setTimeout(() => {
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() {
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="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.submitChatAnswer()" 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('#chat-input');
if (textarea) {
textarea.focus();
}
}, 200);
}
// Submit chat answer
submitChatAnswer() {
const textarea = document.getElementById('chat-input');
if (!textarea) {
console.error('❌ 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');
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');