feat: Improve frontend conversation handling and loading UX

- Add session-based conversation history management
- Improve loading overlay with kid-friendly animated messages
- Disable premature completion messages in conversation mode
- Add better error handling and fallback mechanisms
- Improve conversation flow to work with new fundamentals approach
- Add comprehensive logging for debugging conversation state
- Fix conversation container management for smoother UX
This commit is contained in:
root
2025-07-02 15:02:23 +02:00
parent 647b9b3234
commit 122249d4f4

View File

@@ -15,6 +15,10 @@ class KidsAIExplorer {
this.currentLanguage = localStorage.getItem('kidsai-language') || 'en';
// Generate session ID for conversation tracking
this.sessionId = this.generateSessionId();
console.log('🔑 Session ID:', this.sessionId);
// Configure API base URL based on environment
this.apiBaseUrl = this.getApiBaseUrl();
console.log('🔗 API Base URL:', this.apiBaseUrl);
@@ -47,6 +51,11 @@ class KidsAIExplorer {
console.log('✅ KidsAI constructor completed');
}
// Generate unique session ID for conversation tracking
generateSessionId() {
return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
}
// Detect mobile device
isMobileDevice() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
@@ -117,6 +126,25 @@ class KidsAIExplorer {
this.switchLanguage(btn.dataset.lang);
});
});
// Logo click to return to main page
const logoButton = document.getElementById('logo-button');
if (logoButton) {
console.log('🏠 Adding click listener to logo');
logoButton.addEventListener('click', () => {
console.log('🏠 Logo clicked - returning to main page');
this.returnToMainPage();
});
// Add keyboard support for accessibility
logoButton.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
console.log('🏠 Logo activated via keyboard - returning to main page');
this.returnToMainPage();
}
});
}
console.log('✅ Event listeners setup complete');
}
@@ -195,6 +223,89 @@ class KidsAIExplorer {
this.initializeLanguage();
}
returnToMainPage() {
console.log('🏠 Returning to main page');
// Clear the question input
if (this.questionInput) {
this.questionInput.value = '';
this.questionInput.style.height = 'auto'; // Reset height if auto-resized
this.questionInput.blur(); // Remove focus to prevent keyboard from showing
}
// Hide thinking section
if (this.thinkingSection) {
this.thinkingSection.classList.add('hidden');
this.thinkingSection.classList.remove('chat-mode');
}
// Show main page sections that were hidden during chat
const welcomeSection = document.querySelector('.welcome-section');
const questionSection = document.querySelector('.question-section');
const suggestionsSection = document.querySelector('.suggestions-section');
if (welcomeSection) welcomeSection.style.display = '';
if (questionSection) questionSection.style.display = '';
if (suggestionsSection) suggestionsSection.style.display = '';
// Clear thinking steps
if (this.thinkingSteps) {
this.thinkingSteps.innerHTML = '';
}
// Hide action buttons
const actionButtons = document.getElementById('action-buttons');
if (actionButtons) {
actionButtons.classList.add('hidden');
}
// Hide loading overlay and ensure it's properly hidden
if (this.loadingOverlay) {
this.loadingOverlay.classList.add('hidden');
this.loadingOverlay.style.display = 'none';
}
// Clear any existing message popups
const messagePopups = document.querySelectorAll('.message-popup');
messagePopups.forEach(popup => popup.remove());
// Reset any conversation state
this.currentStep = 0;
this.userAnswers = [];
this.currentQuestionIndex = 0;
// Clear any chat input containers that might be stuck
const chatInputContainers = document.querySelectorAll('.chat-input-container');
chatInputContainers.forEach(container => {
if (container && container.parentNode) {
container.parentNode.removeChild(container);
}
});
// Reset conversation container state
const conversationContainer = document.querySelector('.conversation-container');
if (conversationContainer) {
conversationContainer.classList.remove('keyboard-open');
conversationContainer.style.height = '';
conversationContainer.style.maxHeight = '';
conversationContainer.style.position = '';
conversationContainer.style.bottom = '';
conversationContainer.style.left = '';
conversationContainer.style.width = '';
conversationContainer.style.zIndex = '';
}
// Smooth scroll to top instead of focusing input (prevents keyboard from showing)
setTimeout(() => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}, 100);
console.log('✅ Returned to main page state');
}
async handleQuestion() {
console.log('🤔 handleQuestion called');
@@ -219,7 +330,8 @@ class KidsAIExplorer {
},
body: JSON.stringify({
question: question,
language: this.currentLanguage
language: this.currentLanguage,
sessionId: this.sessionId
})
});
@@ -256,8 +368,18 @@ class KidsAIExplorer {
return;
}
// Show thinking section
// Show thinking section and hide other content
this.thinkingSection.classList.remove('hidden');
this.thinkingSection.classList.add('chat-mode');
// Hide other sections to focus on chat
const welcomeSection = document.querySelector('.welcome-section');
const questionSection = document.querySelector('.question-section');
const suggestionsSection = document.querySelector('.suggestions-section');
if (welcomeSection) welcomeSection.style.display = 'none';
if (questionSection) questionSection.style.display = 'none';
if (suggestionsSection) suggestionsSection.style.display = 'none';
// Clear previous content completely
this.thinkingSteps.innerHTML = '';
@@ -267,10 +389,36 @@ class KidsAIExplorer {
this.userAnswers = [];
this.currentQuestionIndex = 0;
// Create conversation container
// Create conversation container with explicit height enforcement
const conversationContainer = document.createElement('div');
conversationContainer.className = 'conversation-container';
// CRITICAL: Force container properties via JavaScript as backup
conversationContainer.style.height = '450px';
conversationContainer.style.maxHeight = '450px';
conversationContainer.style.minHeight = '450px';
conversationContainer.style.overflowY = 'scroll'; // Force scrollbar visibility
conversationContainer.style.overflowX = 'hidden';
conversationContainer.style.display = 'block';
conversationContainer.style.boxSizing = 'border-box';
conversationContainer.style.position = 'relative';
conversationContainer.style.contain = 'layout size style';
this.thinkingSteps.appendChild(conversationContainer);
// Store reference and start periodic height enforcement
this.conversationContainer = conversationContainer;
// Enforce height immediately and then periodically
this.enforceContainerHeight();
// Set up periodic enforcement to prevent CSS conflicts
if (this.heightEnforcementInterval) {
clearInterval(this.heightEnforcementInterval);
}
this.heightEnforcementInterval = setInterval(() => {
this.enforceContainerHeight();
}, 1000); // Check every second
// Show initial encouragement
const welcomeStep = document.createElement('div');
@@ -303,14 +451,17 @@ class KidsAIExplorer {
];
// 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' });
// Gently scroll to thinking section without jumping
setTimeout(() => {
if (this.thinkingSection) {
this.thinkingSection.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}, 500);
}
displayLocalGuidance(question) {
@@ -342,7 +493,13 @@ class KidsAIExplorer {
showLoading() {
console.log('⏳ Showing loading...');
if (this.loadingOverlay) {
console.log('🔍 Loading overlay found, removing hidden class');
this.loadingOverlay.classList.remove('hidden');
this.loadingOverlay.style.display = 'flex'; // Force display
console.log('✅ Loading overlay should now be visible');
this.startLoadingMessages();
} else {
console.error('❌ Loading overlay not found!');
}
}
@@ -350,6 +507,59 @@ class KidsAIExplorer {
console.log('✅ Hiding loading...');
if (this.loadingOverlay) {
this.loadingOverlay.classList.add('hidden');
this.loadingOverlay.style.display = 'none'; // Force hide
this.stopLoadingMessages();
}
}
startLoadingMessages() {
const loadingMessages = this.currentLanguage === 'de' ? [
"🧠 Ich denke nach...",
"💡 Ich sammle Ideen für dich...",
"🔍 Ich schaue, wie ich dir am besten helfen kann...",
"⚙️ Ich bereite eine tolle Antwort vor...",
"🚀 Gleich habe ich etwas Interessantes für dich!",
"🌟 Ich überlege, welche Frage dich zum Nachdenken bringt..."
] : [
"🧠 I'm thinking...",
"💡 I'm gathering ideas for you...",
"🔍 I'm figuring out the best way to help you...",
"⚙️ I'm preparing a great response...",
"🚀 I'll have something interesting for you soon!",
"🌟 I'm thinking of a question that will make you curious..."
];
const messageElement = this.loadingOverlay.querySelector('p');
if (!messageElement) return;
let messageIndex = 0;
messageElement.textContent = loadingMessages[0];
// Clear any existing interval
if (this.loadingMessageInterval) {
clearInterval(this.loadingMessageInterval);
}
// Rotate messages every 1.5 seconds
this.loadingMessageInterval = setInterval(() => {
messageIndex = (messageIndex + 1) % loadingMessages.length;
// Fade out current message
messageElement.classList.add('fade-out');
// After fade out, change text and fade in
setTimeout(() => {
messageElement.textContent = loadingMessages[messageIndex];
messageElement.classList.remove('fade-out');
}, 250);
}, 1500);
}
stopLoadingMessages() {
if (this.loadingMessageInterval) {
clearInterval(this.loadingMessageInterval);
this.loadingMessageInterval = null;
}
}
@@ -417,6 +627,8 @@ class KidsAIExplorer {
async generateAIResponseToAnswer(answer, stepIndex, responseDiv) {
console.log('🚀 generateAIResponseToAnswer called with:', { answer, stepIndex });
this.showLoading();
try {
// Show loading state
responseDiv.innerHTML = `
@@ -525,15 +737,84 @@ class KidsAIExplorer {
question: currentQuestion,
originalTopic: originalQuestion,
language: this.currentLanguage,
sessionId: this.sessionId,
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!')
? `ERKLÄRUNGS-AUFTRAG: Ein Kind braucht jetzt eine klare, verständliche Erklärung.
SITUATION: Das Kind hat mehrmals "weiß nicht" gesagt und braucht fundiertes Wissen, um weitermachen zu können.
AUFGABE: Gib eine vollständige, aber kindgerechte Erklärung zu "${currentQuestion}" im Kontext von "${originalQuestion}".
DEINE ERKLÄRUNG MUSS:
1. ALTERSGERECHT SEIN: Verwende Sprache und Konzepte für 8-12-Jährige
2. VOLLSTÄNDIG SEIN: Beantworte die Frage komplett, nicht nur teilweise
3. PRAKTISCHE BEISPIELE ENTHALTEN: Verwende Situationen aus dem Kinderalltag
4. EXPERIMENTE VORSCHLAGEN: Lade zu einfachen, sicheren Experimenten ein
5. SCHRITT-FÜR-SCHRITT AUFGEBAUT SEIN: Erkläre logisch von einfach zu komplex
6. NEUGIER WECKEN: Mache Lust auf weitere Entdeckungen
STIL:
- Freundlich und ermutigend
- Wissenschaftlich korrekt aber verständlich
- Mit konkreten Alltagsbeispielen
- Einladend zum Weiterforschen
Das Kind braucht jetzt Wissen, nicht weitere Fragen. Erkläre vollständig und kindgerecht!`
: `EXPLANATION TASK: A child now needs a clear, understandable explanation.
SITUATION: The child has said "don't know" multiple times and needs solid knowledge to continue.
TASK: Give a complete but child-friendly explanation about "${currentQuestion}" in the context of "${originalQuestion}".
YOUR EXPLANATION MUST:
1. BE AGE-APPROPRIATE: Use language and concepts for 8-12 year olds
2. BE COMPLETE: Answer the question fully, not just partially
3. CONTAIN PRACTICAL EXAMPLES: Use situations from children's daily lives
4. SUGGEST EXPERIMENTS: Invite simple, safe experiments
5. BE BUILT STEP-BY-STEP: Explain logically from simple to complex
6. SPARK CURIOSITY: Create desire for further discoveries
STYLE:
- Friendly and encouraging
- Scientifically correct but understandable
- With concrete everyday examples
- Inviting to further research
The child needs knowledge now, not more questions. Explain completely and child-appropriately!`)
: (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!')
? `VERWIRRUNG AUFLÖSEN: Ein Kind ist verwirrt und braucht Klarheit.
SITUATION: Das Kind ist bei "${currentQuestion}" im Kontext von "${originalQuestion}" verwirrt.
AUFGABE: Gib eine klare, beruhigende Erklärung, die das Verständnis wiederherstellt.
DEINE ERKLÄRUNG SOLLTE:
1. BERUHIGEND SEIN: Zeige, dass Verwirrung normal beim Lernen ist
2. EINFACH ANFANGEN: Beginne mit dem Grundlegendsten
3. ALLTÄGLICHE VERGLEICHE NUTZEN: Verwende Dinge, die das Kind kennt
4. SCHRITT-FÜR-SCHRITT AUFBAUEN: Vom Einfachen zum Komplexeren
5. PRAKTISCH SEIN: Lade zu einfachen Beobachtungen oder Tests ein
6. ERMUTIGEN: Mache deutlich, dass das Kind das verstehen kann
Das Kind braucht Klarheit und Ermutigung. Erkläre so, dass Verständnis entsteht!`
: `RESOLVE CONFUSION: A child is confused and needs clarity.
SITUATION: The child is confused about "${currentQuestion}" in the context of "${originalQuestion}".
TASK: Give a clear, reassuring explanation that restores understanding.
YOUR EXPLANATION SHOULD:
1. BE REASSURING: Show that confusion is normal when learning
2. START SIMPLE: Begin with the most basic elements
3. USE EVERYDAY COMPARISONS: Use things the child knows
4. BUILD STEP-BY-STEP: From simple to more complex
5. BE PRACTICAL: Invite simple observations or tests
6. ENCOURAGE: Make clear that the child can understand this
The child needs clarity and encouragement. Explain so that understanding emerges!`)
})
});
} else if (isNegative || isPureDontKnow) {
@@ -541,8 +822,56 @@ class KidsAIExplorer {
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.`;
? `SOCRATIC LEARNING GUIDANCE: Ein Kind braucht Hilfe beim Entdeckungslernen.
AKTUELLE LAGE:
- Frage: "${currentQuestion}"
- Antwort des Kindes: "${answer}"
- Problem: Das Kind weiß die Antwort nicht und braucht behutsame Führung
DEIN AUFTRAG: Entwickle EINE durchdachte Socratic Frage, die das Kind zur selbständigen Entdeckung führt.
PÄDAGOGISCHE PRINZIPIEN:
1. AUFBAU AUF BEKANNTEM: Beginne mit Erfahrungen, die das Kind bereits gemacht hat
2. KONKRETE BEOBACHTUNGEN: Lade zu spezifischen, sichtbaren Entdeckungen ein
3. EINFACHE EXPERIMENTE: Schlage Tests mit Haushaltsgegenständen vor
4. ALTERSGERECHTE SPRACHE: Verwende Wörter, die 8-12-Jährige problemlos verstehen
5. WISSENSCHAFTLICHE GENAUIGKEIT: Führe zu echten wissenschaftlichen Erkenntnissen
6. NEUGIER WECKEN: Formuliere so spannend, dass das Kind unbedingt weiterforschen möchte
QUALITÄT DEINER FRAGE:
- Baut direkt auf dem Nichtwissen des Kindes auf
- Ist praktisch umsetzbar (zu Hause, in der Schule)
- Führt zu einer "Aha!"-Erfahrung
- Ist wissenschaftlich korrekt aber kindgerecht
- Weckt Forscherdrang und Experimentierfreude
Entwickle jetzt EINE perfekte Socratic Leitfrage für dieses Kind:`
: `SOCRATIC LEARNING GUIDANCE: A child needs help with discovery learning.
CURRENT SITUATION:
- Question: "${currentQuestion}"
- Child's answer: "${answer}"
- Problem: The child doesn't know the answer and needs gentle guidance
YOUR TASK: Develop ONE thoughtful Socratic question that leads the child to independent discovery.
PEDAGOGICAL PRINCIPLES:
1. BUILD ON KNOWN: Start with experiences the child has already had
2. CONCRETE OBSERVATIONS: Invite specific, visible discoveries
3. SIMPLE EXPERIMENTS: Suggest tests with household items
4. AGE-APPROPRIATE LANGUAGE: Use words that 8-12 year olds easily understand
5. SCIENTIFIC ACCURACY: Lead to genuine scientific insights
6. SPARK CURIOSITY: Formulate so excitingly that the child absolutely wants to continue researching
QUALITY OF YOUR QUESTION:
- Builds directly on the child's not knowing
- Is practically achievable (at home, at school)
- Leads to an "Aha!" experience
- Is scientifically correct but child-friendly
- Sparks research drive and experimental joy
Now develop ONE perfect Socratic guiding question for this child:`;
response = await fetch(`${this.apiBaseUrl}/api/ask`, {
method: 'POST',
@@ -551,7 +880,8 @@ class KidsAIExplorer {
},
body: JSON.stringify({
question: guidancePrompt,
language: this.currentLanguage
language: this.currentLanguage,
sessionId: this.sessionId
})
});
} else {
@@ -567,6 +897,7 @@ class KidsAIExplorer {
answer: answer,
question: currentQuestion,
language: this.currentLanguage,
sessionId: this.sessionId,
stepIndex: stepIndex
})
});
@@ -631,6 +962,8 @@ class KidsAIExplorer {
`;
}
this.hideLoading();
// Show next question or reveal option after response
setTimeout(() => {
const nextStepIndex = stepIndex + 1;
@@ -659,6 +992,8 @@ class KidsAIExplorer {
async generateChatAIResponse(answer, questionIndex) {
console.log('🚀 generateChatAIResponse called with:', { answer, questionIndex });
this.showLoading();
try {
// Get current question context
const currentQuestion = this.questions && this.questions[questionIndex]
@@ -673,8 +1008,7 @@ class KidsAIExplorer {
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') ||
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") || answerLower.includes('hab keine ahnung');
@@ -742,14 +1076,15 @@ class KidsAIExplorer {
// Use AI to determine if child is asking for information/explanation
let isAskingForDefinition = false;
// Quick check: if it contains a question mark and isn't just expressing uncertainty
if (answer.includes('?') && !isPureDontKnow && !isExpressingConfusion) {
isAskingForDefinition = true;
} else {
// For non-obvious cases, we'll let the AI determine this in the server response
// The server can detect question patterns better than hard-coded rules
// DISABLED: Don't automatically switch to explanation mode for questions
// The educational approach is to guide children to discover answers themselves
// Even when they ask "what is X?", we should ask guiding questions
// if (answer.includes('?') && !isPureDontKnow && !isExpressingConfusion) {
// isAskingForDefinition = true;
// } else {
// Always use guided questioning approach
isAskingForDefinition = false;
}
// }
let response;
@@ -769,6 +1104,7 @@ class KidsAIExplorer {
question: currentQuestion,
originalTopic: originalQuestion,
language: this.currentLanguage,
sessionId: this.sessionId,
context: contextReason,
stepIndex: questionIndex,
instructions: needsExplanationDueToRepeatedDontKnow
@@ -794,6 +1130,7 @@ class KidsAIExplorer {
question: currentQuestion,
originalTopic: originalQuestion,
language: this.currentLanguage,
sessionId: this.sessionId,
context: 'definition_request',
stepIndex: questionIndex,
instructions: this.currentLanguage === 'de'
@@ -806,8 +1143,80 @@ class KidsAIExplorer {
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.`;
? `LERN-COACHING AUFGABE: Ein Kind im Alter von 8-12 Jahren braucht deine Hilfe beim Lernen.
AKTUELLE SITUATION:
- Ursprüngliche Frage: "${originalQuestion}"
- Gestellte Frage: "${currentQuestion}"
- Antwort des Kindes: "${answer}"
- Problem: Das Kind weiß die Antwort nicht und braucht einfachere, konkretere Hilfestellung
DEIN ZIEL: Entwickle EINE einzige, präzise Frage, die das Kind zu einer einfachen, beobachtbaren Entdeckung führt.
DEINE HERANGEHENSWEISE:
1. AUFBAU AUF BEKANNTEM: Beginne mit etwas, das das Kind garantiert schon erlebt hat
2. KONKRETE BEOBACHTUNG: Lade zu einer spezifischen, sichtbaren Beobachtung ein
3. HAUSHALTS-EXPERIMENTE: Schlage einfache Tests mit alltäglichen Gegenständen vor
4. SCHRITT-FÜR-SCHRITT: Führe das Kind von der Beobachtung zur Erkenntnis
5. NEUGIER WECKEN: Formuliere so spannend, dass das Kind sofort ausprobieren möchte
QUALITÄTSKRITERIEN:
- Verwende Sprache, die 8-12-Jährige problemlos verstehen
- Baue auf Alltagserfahrungen auf (Zuhause, Schule, Spielplatz)
- Schlage praktische Aktivitäten vor, die sofort umsetzbar sind
- Sei wissenschaftlich korrekt aber kindgerecht
- Wecke echte Neugier und Forscherdrang
BEISPIELE für gute Fragen:
- "Hast du schon mal beobachtet, was passiert, wenn du..."
- "Was siehst du, wenn du zuhause..."
- "Kannst du heute ausprobieren, ob..."
- "Hast du dir schon mal angeschaut, wie..."
VERMEIDE:
- Abstrakte oder komplizierte Konzepte
- Zu viele Fragen auf einmal
- Schwer verständliche Fachbegriffe
- Experimente, die gefährlich oder schwer durchführbar sind
Entwickle jetzt EINE perfekte Leitfrage für dieses Kind:`
: `LEARNING COACHING TASK: A child aged 8-12 years needs your help with learning.
CURRENT SITUATION:
- Original question: "${originalQuestion}"
- Question asked: "${currentQuestion}"
- Child's answer: "${answer}"
- Problem: The child doesn't know the answer and needs simpler, more concrete guidance
YOUR GOAL: Develop ONE single, precise question that leads the child to a simple, observable discovery.
YOUR APPROACH:
1. BUILD ON KNOWN: Start with something the child has definitely already experienced
2. CONCRETE OBSERVATION: Invite a specific, visible observation
3. HOUSEHOLD EXPERIMENTS: Suggest simple tests with everyday objects
4. STEP-BY-STEP: Lead the child from observation to understanding
5. SPARK CURIOSITY: Formulate so excitingly that the child wants to try immediately
QUALITY CRITERIA:
- Use language that 8-12 year olds easily understand
- Build on everyday experiences (home, school, playground)
- Suggest practical activities that are immediately doable
- Be scientifically correct but child-friendly
- Spark genuine curiosity and research drive
EXAMPLES of good questions:
- "Have you ever observed what happens when you..."
- "What do you see when you at home..."
- "Can you try today to see if..."
- "Have you ever looked at how..."
AVOID:
- Abstract or complicated concepts
- Too many questions at once
- Hard-to-understand technical terms
- Experiments that are dangerous or hard to perform
Now develop ONE perfect guiding question for this child:`;
response = await fetch(`${this.apiBaseUrl}/api/ask`, {
method: 'POST',
@@ -832,6 +1241,7 @@ class KidsAIExplorer {
answer: answer,
question: currentQuestion,
language: this.currentLanguage,
sessionId: this.sessionId,
stepIndex: questionIndex
})
});
@@ -947,6 +1357,8 @@ class KidsAIExplorer {
setTimeout(() => {
this.addContinueChoiceButtons();
}, 1500);
} finally {
this.hideLoading();
}
}
@@ -1174,6 +1586,8 @@ class KidsAIExplorer {
async generateDeeperExplorationResponse(answer) {
console.log('🚀 generateDeeperExplorationResponse called with:', answer);
this.showLoading();
try {
// Get the last AI question for context
const lastAIMessages = Array.from(this.conversationContainer.querySelectorAll('.ai-message.exploration'));
@@ -1193,6 +1607,7 @@ class KidsAIExplorer {
answer: answer,
question: lastExplorationQuestion,
language: this.currentLanguage,
sessionId: this.sessionId,
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.'
@@ -1267,6 +1682,8 @@ class KidsAIExplorer {
setTimeout(() => {
this.addContinueChoiceButtons();
}, 1500);
} finally {
this.hideLoading();
}
}
@@ -1287,9 +1704,11 @@ class KidsAIExplorer {
askNextQuestion() {
console.log('❓ askNextQuestion called, currentQuestionIndex:', this.currentQuestionIndex);
// DISABLED: Old completion logic for question-based system
// We now use a conversational fundamentals approach, so don't auto-complete
if (!this.questions || this.currentQuestionIndex >= this.questions.length) {
console.log('✅ All questions completed');
this.showCompletionMessage();
console.log('✅ Questions completed, but continuing conversation mode');
// Don't show completion - let conversation continue
return;
}
@@ -1353,10 +1772,18 @@ class KidsAIExplorer {
inputContainer.classList.add('visible');
this.scrollToBottomSmoothly();
// Focus on textarea
// Focus on textarea and add Enter key handler
const textarea = inputContainer.querySelector(`#${inputId}`);
if (textarea) {
textarea.focus();
// Add Enter key listener for chat input
textarea.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.submitChatAnswerFromInput(inputId);
}
});
}
}, 200);
}
@@ -1432,10 +1859,33 @@ class KidsAIExplorer {
}, 100);
}
// Smooth scroll to bottom of conversation
// Enforce conversation container height periodically to prevent CSS conflicts
enforceContainerHeight() {
if (this.conversationContainer) {
// Force height properties via JavaScript to override any CSS conflicts
this.conversationContainer.style.height = '450px';
this.conversationContainer.style.maxHeight = '450px';
this.conversationContainer.style.minHeight = '450px';
this.conversationContainer.style.overflowY = 'scroll'; // Force scrollbar visibility
this.conversationContainer.style.overflowX = 'hidden';
this.conversationContainer.style.display = 'block';
this.conversationContainer.style.boxSizing = 'border-box';
}
}
// Smooth scroll to bottom of conversation within the container
scrollToBottomSmoothly() {
if (this.conversationContainer) {
this.conversationContainer.scrollIntoView({ behavior: 'smooth', block: 'end' });
// Use requestAnimationFrame for smooth scrolling
requestAnimationFrame(() => {
// Scroll to the bottom of the conversation container
this.conversationContainer.scrollTop = this.conversationContainer.scrollHeight;
// Additional fallback for timing issues
setTimeout(() => {
this.conversationContainer.scrollTop = this.conversationContainer.scrollHeight;
}, 100);
});
}
}