Major improvement: Detect child confusion and provide explanations. Always show input area after AI explanations so kids can ask follow-up questions about concepts like prisms.
This commit is contained in:
@@ -426,22 +426,13 @@ class KidsAIExplorer {
|
|||||||
|
|
||||||
const isOnlyWhyQuestion = answerLower === 'warum' || answerLower === 'why' || answerLower === 'warum?' || answerLower === 'why?';
|
const isOnlyWhyQuestion = answerLower === 'warum' || answerLower === 'why' || answerLower === 'warum?' || answerLower === 'why?';
|
||||||
|
|
||||||
// Check if child is asking for a definition or explanation
|
// Check if child is expressing confusion and needs explanation
|
||||||
const isAskingForDefinition = answerLower.startsWith('was ist') || answerLower.startsWith('what is') ||
|
const isExpressingConfusion = answerLower.includes('verstehe nicht') || answerLower.includes("don't understand") ||
|
||||||
answerLower.includes('was bedeutet') || answerLower.includes('what does') ||
|
answerLower.includes('versteh das nicht') || answerLower.includes('verstehe es nicht') ||
|
||||||
answerLower.includes('was heißt') || answerLower.includes('what means') ||
|
answerLower.includes('ich verstehe nicht warum') || answerLower.includes("i don't understand why") ||
|
||||||
(answerLower.includes('?') && (answerLower.includes('ist ein') || answerLower.includes('is a')));
|
answerLower.includes('aber ich verstehe nicht') || answerLower.includes("but i don't understand") ||
|
||||||
|
answerLower.includes('fällt mir nicht ein') || answerLower.includes("can't think of") ||
|
||||||
// Check if child is asking a specific "how/why" question that deserves explanation
|
answerLower.includes('mehr fällt mir nicht ein');
|
||||||
const isAskingSpecificQuestion = answerLower.includes('woher kommt') || answerLower.includes('where does') ||
|
|
||||||
answerLower.includes('wie entsteht') || answerLower.includes('how does') ||
|
|
||||||
answerLower.includes('warum ist das so') || answerLower.includes('why is that') ||
|
|
||||||
answerLower.includes('ich verstehe nicht') || answerLower.includes("i don't understand") ||
|
|
||||||
(answerLower.includes('?') && (answerLower.includes('woher') || answerLower.includes('wie') || answerLower.includes('warum'))) ||
|
|
||||||
(answer.length > 30 && answerLower.includes('verstehe') && answerLower.includes('nicht'));
|
|
||||||
|
|
||||||
// Combine both definition and specific question detection
|
|
||||||
const needsExplanation = isAskingForDefinition || isAskingSpecificQuestion;
|
|
||||||
|
|
||||||
// Check if it's a substantial answer (has thinking beyond just "don't know")
|
// Check if it's a substantial answer (has thinking beyond just "don't know")
|
||||||
const hasSubstantialThinking = answer.length > 15 && (
|
const hasSubstantialThinking = answer.length > 15 && (
|
||||||
@@ -452,18 +443,13 @@ class KidsAIExplorer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Pure "don't know" without additional thinking
|
// Pure "don't know" without additional thinking
|
||||||
const isPureDontKnow = (hasDontKnowPhrase || isOnlyWhyQuestion || answer.trim().length < 5) && !hasSubstantialThinking && !needsExplanation;
|
const isPureDontKnow = (hasDontKnowPhrase || isOnlyWhyQuestion || answer.trim().length < 5) && !hasSubstantialThinking;
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
if (needsExplanation) {
|
if (isExpressingConfusion) {
|
||||||
// Child is asking for explanation - provide simple, concrete explanation
|
// Child is expressing confusion - provide a simple explanation
|
||||||
console.log('📤 Sending explanation request to /api/respond-to-answer');
|
console.log('📤 Sending explanation request for confused child');
|
||||||
|
|
||||||
const contextType = isAskingForDefinition ? 'definition_request' : 'specific_question';
|
|
||||||
const instructionText = this.currentLanguage === 'de'
|
|
||||||
? 'Das Kind stellt eine spezifische Frage und möchte verstehen. Gib eine EINFACHE, konkrete Erklärung für Kinder. Beantworte die spezifische Frage direkt aber kindgerecht. Verwende Analogien und alltägliche Vergleiche. Für "woher kommt die farbe" erkläre einfach, dass weißes Licht alle Farben enthält, wie ein unsichtbarer Regenbogen. Keine weiteren Fragen stellen.'
|
|
||||||
: 'The child is asking a specific question and wants to understand. Give a SIMPLE, concrete explanation for children. Answer the specific question directly but age-appropriately. Use analogies and everyday comparisons. For "where does color come from" explain simply that white light contains all colors, like an invisible rainbow. Don\'t ask more questions.';
|
|
||||||
|
|
||||||
response = await fetch('/api/respond-to-answer', {
|
response = await fetch('/api/respond-to-answer', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -475,9 +461,11 @@ class KidsAIExplorer {
|
|||||||
question: currentQuestion,
|
question: currentQuestion,
|
||||||
originalTopic: originalQuestion,
|
originalTopic: originalQuestion,
|
||||||
language: this.currentLanguage,
|
language: this.currentLanguage,
|
||||||
context: contextType,
|
context: 'confusion_explanation',
|
||||||
stepIndex: questionIndex,
|
stepIndex: questionIndex,
|
||||||
instructions: instructionText
|
instructions: this.currentLanguage === 'de'
|
||||||
|
? 'Das Kind ist verwirrt und braucht eine einfache Erklärung. Gib eine klare, konkrete Antwort für Kinder. Erkläre das Konzept mit alltäglichen Beispielen. Verwende einfache Wörter und lade zum Ausprobieren ein. Keine weiteren Fragen stellen - erst erklären!'
|
||||||
|
: 'The child is confused and needs a simple explanation. Give a clear, concrete answer for children. Explain the concept with everyday examples. Use simple words and invite experimentation. Don\'t ask more questions - explain first!'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
} else if (isNegative || isPureDontKnow) {
|
} else if (isNegative || isPureDontKnow) {
|
||||||
@@ -624,22 +612,13 @@ class KidsAIExplorer {
|
|||||||
|
|
||||||
const isOnlyWhyQuestion = answerLower === 'warum' || answerLower === 'why' || answerLower === 'warum?' || answerLower === 'why?';
|
const isOnlyWhyQuestion = answerLower === 'warum' || answerLower === 'why' || answerLower === 'warum?' || answerLower === 'why?';
|
||||||
|
|
||||||
// Check if child is asking for a definition or explanation
|
// Check if child is expressing confusion and needs explanation
|
||||||
const isAskingForDefinition = answerLower.startsWith('was ist') || answerLower.startsWith('what is') ||
|
const isExpressingConfusion = answerLower.includes('verstehe nicht') || answerLower.includes("don't understand") ||
|
||||||
answerLower.includes('was bedeutet') || answerLower.includes('what does') ||
|
answerLower.includes('versteh das nicht') || answerLower.includes('verstehe es nicht') ||
|
||||||
answerLower.includes('was heißt') || answerLower.includes('what means') ||
|
answerLower.includes('ich verstehe nicht warum') || answerLower.includes("i don't understand why") ||
|
||||||
(answerLower.includes('?') && (answerLower.includes('ist ein') || answerLower.includes('is a')));
|
answerLower.includes('aber ich verstehe nicht') || answerLower.includes("but i don't understand") ||
|
||||||
|
answerLower.includes('fällt mir nicht ein') || answerLower.includes("can't think of") ||
|
||||||
// Check if child is asking a specific "how/why" question that deserves explanation
|
answerLower.includes('mehr fällt mir nicht ein');
|
||||||
const isAskingSpecificQuestion = answerLower.includes('woher kommt') || answerLower.includes('where does') ||
|
|
||||||
answerLower.includes('wie entsteht') || answerLower.includes('how does') ||
|
|
||||||
answerLower.includes('warum ist das so') || answerLower.includes('why is that') ||
|
|
||||||
answerLower.includes('ich verstehe nicht') || answerLower.includes("i don't understand") ||
|
|
||||||
(answerLower.includes('?') && (answerLower.includes('woher') || answerLower.includes('wie') || answerLower.includes('warum'))) ||
|
|
||||||
(answer.length > 30 && answerLower.includes('verstehe') && answerLower.includes('nicht'));
|
|
||||||
|
|
||||||
// Combine both definition and specific question detection
|
|
||||||
const needsExplanation = isAskingForDefinition || isAskingSpecificQuestion;
|
|
||||||
|
|
||||||
// Check if it's a substantial answer (has thinking beyond just "don't know")
|
// Check if it's a substantial answer (has thinking beyond just "don't know")
|
||||||
const hasSubstantialThinking = answer.length > 15 && (
|
const hasSubstantialThinking = answer.length > 15 && (
|
||||||
@@ -650,41 +629,17 @@ class KidsAIExplorer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Pure "don't know" without additional thinking
|
// Pure "don't know" without additional thinking
|
||||||
const isPureDontKnow = (hasDontKnowPhrase || isOnlyWhyQuestion || answer.trim().length < 5) && !hasSubstantialThinking && !needsExplanation;
|
const isPureDontKnow = (hasDontKnowPhrase || isOnlyWhyQuestion || answer.trim().length < 5) && !hasSubstantialThinking;
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
if (needsExplanation) {
|
if (isNegative || isPureDontKnow) {
|
||||||
// Child is asking for explanation - provide simple, concrete explanation
|
|
||||||
console.log('📤 Sending explanation request to /api/respond-to-answer');
|
|
||||||
|
|
||||||
const contextType = isAskingForDefinition ? 'definition_request' : 'specific_question';
|
|
||||||
const instructionText = this.currentLanguage === 'de'
|
|
||||||
? 'Das Kind stellt eine spezifische Frage und möchte verstehen. Gib eine EINFACHE, konkrete Erklärung für Kinder. Beantworte die spezifische Frage direkt aber kindgerecht. Verwende Analogien und alltägliche Vergleiche. Für "woher kommt die farbe" erkläre einfach, dass weißes Licht alle Farben enthält, wie ein unsichtbarer Regenbogen. Keine weiteren Fragen stellen.'
|
|
||||||
: 'The child is asking a specific question and wants to understand. Give a SIMPLE, concrete explanation for children. Answer the specific question directly but age-appropriately. Use analogies and everyday comparisons. For "where does color come from" explain simply that white light contains all colors, like an invisible rainbow. Don\'t ask more questions.';
|
|
||||||
|
|
||||||
response = await fetch('/api/respond-to-answer', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
answer: answer,
|
|
||||||
question: currentQuestion,
|
|
||||||
originalTopic: originalQuestion,
|
|
||||||
language: this.currentLanguage,
|
|
||||||
context: contextType,
|
|
||||||
stepIndex: questionIndex,
|
|
||||||
instructions: instructionText
|
|
||||||
})
|
|
||||||
});
|
|
||||||
} else if (isNegative || isPureDontKnow) {
|
|
||||||
// For pure "no" or "don't know" answers without thinking, get Socratic guidance questions
|
// For pure "no" or "don't know" answers without thinking, get Socratic guidance questions
|
||||||
console.log('📤 Sending guidance request to /api/ask for Socratic questioning');
|
console.log('📤 Sending guidance request to /api/ask for Socratic questioning');
|
||||||
|
|
||||||
const guidancePrompt = this.currentLanguage === 'de'
|
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.`
|
? `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}". 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.`;
|
: `A child answered "${answer}" to the question "${currentQuestion}" about the topic "${originalQuestion}". The child doesn't know and needs simpler foundations. Give NO more abstract questions! Instead: 1) Describe a simple observation the child can make (e.g. "Have you ever seen light through a glass of water?") 2) Invite practical experimentation 3) Build on what the child already knows. Use concrete, visible examples instead of abstract concepts.`;
|
||||||
|
|
||||||
response = await fetch('/api/ask', {
|
response = await fetch('/api/ask', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -696,6 +651,21 @@ class KidsAIExplorer {
|
|||||||
language: this.currentLanguage
|
language: this.currentLanguage
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
} else if (isExpressingConfusion) {
|
||||||
|
// If the child is confused, provide an explanation instead of more questions
|
||||||
|
console.log('📤 Sending explanation request to /api/explain');
|
||||||
|
|
||||||
|
response = await fetch('/api/explain', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
question: currentQuestion,
|
||||||
|
language: this.currentLanguage,
|
||||||
|
userAnswer: answer
|
||||||
|
})
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// For substantial answers, acknowledge and validate
|
// For substantial answers, acknowledge and validate
|
||||||
console.log('📤 Sending validation request to /api/respond-to-answer');
|
console.log('📤 Sending validation request to /api/respond-to-answer');
|
||||||
@@ -772,11 +742,22 @@ class KidsAIExplorer {
|
|||||||
// Check if AI response contains a question that needs answering
|
// Check if AI response contains a question that needs answering
|
||||||
const hasQuestion = data.response && data.response.includes('?');
|
const hasQuestion = data.response && data.response.includes('?');
|
||||||
|
|
||||||
if (hasQuestion) {
|
// Check if AI response contains explanations or new concepts that might trigger questions
|
||||||
// AI asked a follow-up question, provide input area
|
const containsExplanation = data.response && (
|
||||||
|
data.response.includes('passiert, weil') || data.response.includes('happens because') ||
|
||||||
|
data.response.includes('Das liegt daran') || data.response.includes('This is because') ||
|
||||||
|
data.response.includes('Prisma') || data.response.includes('prism') ||
|
||||||
|
data.response.includes('Licht') || data.response.includes('light') ||
|
||||||
|
data.response.includes('besteht aus') || data.response.includes('consists of') ||
|
||||||
|
data.response.includes('brechen') || data.response.includes('break') ||
|
||||||
|
data.response.length > 150 // Longer responses likely contain explanations
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasQuestion || containsExplanation) {
|
||||||
|
// AI asked a question or gave an explanation - provide input area for follow-up questions
|
||||||
this.addUserInputArea();
|
this.addUserInputArea();
|
||||||
} else {
|
} else {
|
||||||
// No question in response, show choice buttons
|
// Simple response without question or explanation, show choice buttons
|
||||||
this.addContinueChoiceButtons();
|
this.addContinueChoiceButtons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,15 +557,14 @@ app.post('/api/respond-to-answer', async (req, res) => {
|
|||||||
|
|
||||||
console.log(`📝 Generating response to answer: "${answer}" for question: "${question}" with context: ${context}`);
|
console.log(`📝 Generating response to answer: "${answer}" for question: "${question}" with context: ${context}`);
|
||||||
|
|
||||||
// Handle definition requests and specific questions specially
|
// Handle confusion explanation requests specially
|
||||||
if ((context === 'definition_request' || context === 'specific_question') && instructions) {
|
if (context === 'confusion_explanation' && instructions) {
|
||||||
// For definition requests and specific questions, use the provided instructions
|
|
||||||
const explanationPrompt = `${instructions}
|
const explanationPrompt = `${instructions}
|
||||||
|
|
||||||
CHILD'S QUESTION: "${answer}"
|
CHILD'S CONFUSED RESPONSE: "${answer}"
|
||||||
CONTEXT: The child asked this while learning about: "${question}"
|
ORIGINAL QUESTION: "${question}"
|
||||||
|
|
||||||
Provide a simple, concrete explanation for children using everyday comparisons and practical examples.`;
|
The child is expressing confusion and needs help understanding. Provide a clear, simple explanation using everyday examples and concrete comparisons that a child can understand.`;
|
||||||
|
|
||||||
// Try OpenAI first for explanations
|
// Try OpenAI first for explanations
|
||||||
if (process.env.OPENAI_API_KEY) {
|
if (process.env.OPENAI_API_KEY) {
|
||||||
@@ -585,44 +584,28 @@ Provide a simple, concrete explanation for children using everyday comparisons a
|
|||||||
const aiResponse = completion.choices[0]?.message?.content?.trim();
|
const aiResponse = completion.choices[0]?.message?.content?.trim();
|
||||||
|
|
||||||
if (aiResponse && aiResponse.length > 10) {
|
if (aiResponse && aiResponse.length > 10) {
|
||||||
console.log('✅ OpenAI explanation response generated successfully');
|
console.log('✅ OpenAI confusion explanation generated successfully');
|
||||||
return res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
response: aiResponse,
|
response: aiResponse,
|
||||||
source: `OpenAI GPT-3.5 (${context})`
|
source: 'OpenAI GPT-3.5 (Confusion Explanation)'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (openaiError) {
|
} catch (openaiError) {
|
||||||
console.log('❌ OpenAI error for explanation:', openaiError.message);
|
console.log('❌ OpenAI error for confusion explanation:', openaiError.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enhanced fallbacks for specific questions
|
// Fallback for confusion explanations
|
||||||
const answerLower = answer.toLowerCase();
|
const isGerman = language === 'de';
|
||||||
let explanationFallback;
|
const confusionFallback = isGerman ?
|
||||||
|
'Das passiert, weil Sonnenlicht aus vielen verschiedenen Farben besteht! Wenn Licht durch Regentropfen geht, werden diese Farben getrennt - wie bei einem Prisma. Du kannst das selbst ausprobieren: Halte ein Glas Wasser ins Sonnenlicht und schau, welche Farben entstehen! 🌈' :
|
||||||
if (answerLower.includes('woher kommt') && answerLower.includes('farbe')) {
|
'This happens because sunlight is made of many different colors! When light goes through raindrops, these colors get separated - just like with a prism. You can try this yourself: hold a glass of water in sunlight and see what colors appear! 🌈';
|
||||||
explanationFallback = language === 'de' ?
|
|
||||||
'🌈 Weißes Sonnenlicht ist wie ein unsichtbarer Regenbogen! Es enthält alle Farben gleichzeitig - rot, orange, gelb, grün, blau, violett. Wenn das Licht durch Wassertropfen geht, werden diese versteckten Farben sichtbar gemacht - wie Magie! Du kannst das mit einem Gartenschlauch im Sonnenschein ausprobieren!' :
|
|
||||||
'🌈 White sunlight is like an invisible rainbow! It contains all colors at once - red, orange, yellow, green, blue, violet. When light goes through water drops, these hidden colors become visible - like magic! You can try this with a garden hose in the sunshine!';
|
|
||||||
} else if (answerLower.includes('prisma') || answerLower.includes('prism')) {
|
|
||||||
explanationFallback = language === 'de' ?
|
|
||||||
'🔍 Ein Prisma ist wie ein magisches Glas, das weißes Licht in alle Regenbogenfarben zerlegt! Du kannst das selbst ausprobieren: Halte ein Glas Wasser ins Sonnenlicht und schau, welche Farben entstehen!' :
|
|
||||||
'🔍 A prism is like a magic glass that breaks white light into all the rainbow colors! You can try this yourself: hold a glass of water in the sunlight and see what colors appear!';
|
|
||||||
} else if (answerLower.includes('verstehe nicht') || answerLower.includes("don't understand")) {
|
|
||||||
explanationFallback = language === 'de' ?
|
|
||||||
'💡 Kein Problem! Das ist wirklich faszinierend. Lass es mich einfacher erklären: Stell dir vor, weißes Licht ist wie eine Süßigkeitentüte mit vielen verschiedenen Farben drin. Normalerweise siehst du nur die Tüte (weißes Licht), aber Wasser kann die Tüte "öffnen" und alle bunten Süßigkeiten (Farben) zeigen!' :
|
|
||||||
'💡 No problem! This is really fascinating. Let me explain it simpler: Imagine white light is like a candy bag with many different colors inside. Usually you only see the bag (white light), but water can "open" the bag and show all the colorful candies (colors)!';
|
|
||||||
} else {
|
|
||||||
explanationFallback = language === 'de' ?
|
|
||||||
'🤔 Das ist eine wirklich gute Frage! Lass mich das Schritt für Schritt erklären...' :
|
|
||||||
'🤔 That\'s a really good question! Let me explain this step by step...';
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
response: explanationFallback,
|
response: confusionFallback,
|
||||||
source: 'Enhanced Explanation Fallback'
|
source: 'Fallback Confusion Explanation'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user