- 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.
1207 lines
51 KiB
JavaScript
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');
|