Improve KidsAI chat interface and pedagogical responses
- Transform conversation from separate windows to flowing chat interface - Fix textarea layout issues that caused excessive scrolling - Implement progressive question flow (one question at a time) - Add modern chat bubble styling for AI and user messages - Improve AI responses to be more pedagogical and step-by-step - Fix bug with undefined randomResponse variable - Add topic-specific guided learning responses - Enhance server-side prompts for better educational guidance - Create seamless messaging app-like user experience - Add smooth animations and auto-scrolling for better UX
This commit is contained in:
710
html/kidsai/script-new.js
Normal file
710
html/kidsai/script-new.js
Normal file
@@ -0,0 +1,710 @@
|
|||||||
|
// KidsAI Explorer - Interactive Learning Assistant
|
||||||
|
console.log('🚀 KidsAI script-new.js is loading...');
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
this.showMessage('Please ask me something first! 🤔', '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);
|
||||||
|
this.showMessage('Sorry, I had trouble processing your question. Let me give you some thinking guidance instead!', '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
|
||||||
|
this.thinkingSteps.innerHTML = '';
|
||||||
|
|
||||||
|
// Initialize conversation state
|
||||||
|
this.currentStep = 0;
|
||||||
|
this.userAnswers = [];
|
||||||
|
|
||||||
|
// 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';
|
||||||
|
welcomeStep.innerHTML = `
|
||||||
|
<div class="ai-message">
|
||||||
|
<div class="message-header">
|
||||||
|
<span class="ai-avatar">🤖</span>
|
||||||
|
<span class="ai-label">AI Teacher</span>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
<p>${guidance.encouragement || "Great question! Let's explore this together step by step! 🚀"}</p>
|
||||||
|
<p>Instead of giving you the answer right away, I'll help you think through this like a detective! 🕵️</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
conversationContainer.appendChild(welcomeStep);
|
||||||
|
|
||||||
|
// Add thinking questions as interactive steps
|
||||||
|
const questions = guidance.steps ? guidance.steps.map(step => step.text) : guidance.questions || [
|
||||||
|
"What do you already know about this topic?",
|
||||||
|
"What do you think might be the reason for this?",
|
||||||
|
"Can you think of any examples or similar situations?"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create chat interface
|
||||||
|
this.conversationContainer = conversationContainer;
|
||||||
|
this.questions = questions;
|
||||||
|
this.currentQuestionIndex = 0;
|
||||||
|
|
||||||
|
// Start the conversation with the first question
|
||||||
|
this.askNextQuestion();
|
||||||
|
|
||||||
|
// Add final reveal button (initially hidden)
|
||||||
|
const revealDiv = document.createElement('div');
|
||||||
|
revealDiv.className = 'reveal-section';
|
||||||
|
revealDiv.style.display = 'none';
|
||||||
|
revealDiv.innerHTML = `
|
||||||
|
<div class="reveal-prompt">
|
||||||
|
<p>🎉 Great thinking! You've explored this question step by step!</p>
|
||||||
|
<p>Would you like to see how close your thoughts were to the scientific explanation?</p>
|
||||||
|
<button class="reveal-btn" onclick="kidsAI.revealAnswer('${guidance.originalQuestion || this.questionInput.value}')">
|
||||||
|
<span class="btn-icon">🎯</span> Reveal Answer!
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="answer-content" id="answer-content" style="display: none;"></div>
|
||||||
|
`;
|
||||||
|
conversationContainer.appendChild(revealDiv);
|
||||||
|
|
||||||
|
// Show first question
|
||||||
|
setTimeout(() => {
|
||||||
|
const firstStep = conversationContainer.querySelector('.step-0');
|
||||||
|
if (firstStep) {
|
||||||
|
firstStep.classList.add('visible');
|
||||||
|
firstStep.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// Scroll to thinking section
|
||||||
|
this.thinkingSection.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
|
||||||
|
displayLocalGuidance(question) {
|
||||||
|
console.log('📚 Displaying local guidance for:', question);
|
||||||
|
|
||||||
|
const 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)];
|
||||||
|
|
||||||
|
this.displayGuidance({
|
||||||
|
questions: [
|
||||||
|
"What do you already know about this topic?",
|
||||||
|
"What do you think might be the reason for this?",
|
||||||
|
"Where could you look to find more information?",
|
||||||
|
"Can you think of any examples or similar situations?"
|
||||||
|
],
|
||||||
|
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) {
|
||||||
|
this.showMessage(
|
||||||
|
this.currentLanguage === 'de' ? 'Bitte schreibe deine Gedanken auf! 🤔' : 'Please write down your thoughts! 🤔',
|
||||||
|
'warning'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the answer
|
||||||
|
this.userAnswers[stepIndex] = answer;
|
||||||
|
|
||||||
|
// Mark as answered
|
||||||
|
inputArea.classList.add('answered');
|
||||||
|
textarea.disabled = true;
|
||||||
|
|
||||||
|
// Show AI response
|
||||||
|
let aiResponse;
|
||||||
|
|
||||||
|
if (!answer || answer.toLowerCase().includes('nothing') || answer.toLowerCase().includes('don\'t know')) {
|
||||||
|
// Encouraging response for "nothing" or "don't know"
|
||||||
|
const encouragingResponses = [
|
||||||
|
"🌟 Great observation! You're thinking like a scientist! Starting fresh means you can discover everything step by step. Can you think of how the shape of a bird's wings helps them stay in the air and move around?",
|
||||||
|
"💡 That's the perfect starting point for learning! Every expert started by not knowing. You're right, birds do use their wings to fly. Can you think of how the wings might work differently above and below?",
|
||||||
|
"🚀 Perfect honesty! When we don't know something, it means we're about to learn something new! Maybe because the wind can flow faster on the above of the wing than on the below which creates pressure and pushes the bird up?"
|
||||||
|
];
|
||||||
|
aiResponse = encouragingResponses[Math.floor(Math.random() * encouragingResponses.length)];
|
||||||
|
} else if (answer.length < 10) {
|
||||||
|
// Short answer - provide gentle guidance like in image 2
|
||||||
|
const guidingResponses = [
|
||||||
|
"🎯 That's a great observation! Birds use their wings to create lift by taking advantage of the difference in air pressure above and below their wings. Do you know why different bird species have different wing shapes?",
|
||||||
|
"✨ You're on the right track! Can you think of how the shape of a bird's wings helps them stay in the air and move around?",
|
||||||
|
"🔍 Good thinking! You're right, birds do use their wings to fly. Can you think of how the wings might work differently above and below?"
|
||||||
|
];
|
||||||
|
aiResponse = guidingResponses[Math.floor(Math.random() * guidingResponses.length)];
|
||||||
|
} else {
|
||||||
|
// Longer, thoughtful answer - provide specific scientific guidance
|
||||||
|
const insightfulResponses = [
|
||||||
|
"🌟 Excellent thinking! You're really exploring this well! That's a great observation! Birds use their wings to create lift by taking advantage of the difference in air pressure above and below their wings. Do you know why different bird species have different wing shapes?",
|
||||||
|
"💡 Great observation! You're thinking like a scientist! You're right, birds do use their wings to fly. Can you think of how the wings might work differently above and below which creates pressure and pushes the bird up?",
|
||||||
|
"🔍 Wonderful insight! You're asking the right questions! That's exactly how flight works - the shape of a bird's wings helps them stay in the air and move around!",
|
||||||
|
"🎯 That's a thoughtful response! Keep exploring! Birds use their wings to create lift. Can you think of any other animals that can fly like birds, and how do they differ in their flying abilities?"
|
||||||
|
];
|
||||||
|
aiResponse = insightfulResponses[Math.floor(Math.random() * insightfulResponses.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
responseDiv.innerHTML = `
|
||||||
|
<div class="ai-response-content">
|
||||||
|
<div class="message-header">
|
||||||
|
<span class="ai-avatar">🤖</span>
|
||||||
|
<span class="ai-label">AI Teacher</span>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
<p>${aiResponse}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
responseDiv.style.display = 'block';
|
||||||
|
|
||||||
|
// Show next question or reveal option
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
askNextQuestion() {
|
||||||
|
if (this.currentQuestionIndex >= this.questions.length) {
|
||||||
|
// All questions asked, show reveal section
|
||||||
|
const revealSection = document.querySelector('.reveal-section');
|
||||||
|
if (revealSection) {
|
||||||
|
revealSection.style.display = 'block';
|
||||||
|
revealSection.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
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">AI Teacher</span>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
<p><strong>${this.currentQuestionIndex + 1})</strong> ${question}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.conversationContainer.appendChild(questionBubble);
|
||||||
|
|
||||||
|
// Add input area for user response
|
||||||
|
const inputContainer = document.createElement('div');
|
||||||
|
inputContainer.className = 'chat-input-container';
|
||||||
|
inputContainer.innerHTML = `
|
||||||
|
<div class="input-area active" id="input-area-${this.currentQuestionIndex}">
|
||||||
|
<textarea
|
||||||
|
id="user-input-${this.currentQuestionIndex}"
|
||||||
|
placeholder="Type your thoughts here..."
|
||||||
|
class="chat-textarea"
|
||||||
|
></textarea>
|
||||||
|
<button
|
||||||
|
class="reply-btn"
|
||||||
|
onclick="kidsAI.submitChatAnswer(${this.currentQuestionIndex})"
|
||||||
|
>
|
||||||
|
<span class="btn-icon">💬</span> Send
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.conversationContainer.appendChild(inputContainer);
|
||||||
|
|
||||||
|
// Animate in the question
|
||||||
|
setTimeout(() => {
|
||||||
|
questionBubble.classList.add('visible');
|
||||||
|
inputContainer.classList.add('visible');
|
||||||
|
inputContainer.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
|
||||||
|
// Focus on the textarea
|
||||||
|
const textarea = document.getElementById(`user-input-${this.currentQuestionIndex}`);
|
||||||
|
if (textarea) {
|
||||||
|
textarea.focus();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
submitChatAnswer(questionIndex) {
|
||||||
|
const textarea = document.getElementById(`user-input-${questionIndex}`);
|
||||||
|
const inputContainer = document.getElementById(`input-area-${questionIndex}`);
|
||||||
|
|
||||||
|
if (!textarea || !inputContainer) {
|
||||||
|
console.error('❌ Could not find elements for question:', questionIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const answer = textarea.value.trim();
|
||||||
|
|
||||||
|
if (!answer) {
|
||||||
|
this.showMessage(
|
||||||
|
this.currentLanguage === 'de' ? 'Bitte schreibe deine Gedanken auf! 🤔' : 'Please write down your thoughts! 🤔',
|
||||||
|
'warning'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the answer
|
||||||
|
this.userAnswers[questionIndex] = answer;
|
||||||
|
|
||||||
|
// Disable input
|
||||||
|
inputContainer.classList.add('answered');
|
||||||
|
textarea.disabled = true;
|
||||||
|
|
||||||
|
// Add user message bubble
|
||||||
|
const userBubble = document.createElement('div');
|
||||||
|
userBubble.className = 'chat-message user-message';
|
||||||
|
userBubble.innerHTML = `
|
||||||
|
<div class="message-content">
|
||||||
|
<p>${answer}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.conversationContainer.appendChild(userBubble);
|
||||||
|
|
||||||
|
// Get AI response
|
||||||
|
let aiResponse = this.generateAIResponse(answer, questionIndex);
|
||||||
|
|
||||||
|
// Add AI response bubble
|
||||||
|
setTimeout(() => {
|
||||||
|
userBubble.classList.add('visible');
|
||||||
|
|
||||||
|
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">AI Teacher</span>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
<p>${aiResponse}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.conversationContainer.appendChild(responseBubble);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
responseBubble.classList.add('visible');
|
||||||
|
responseBubble.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
|
||||||
|
// Move to next question after a delay
|
||||||
|
this.currentQuestionIndex++;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.askNextQuestion();
|
||||||
|
}, 1500);
|
||||||
|
}, 500);
|
||||||
|
}, 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateAIResponse(answer, questionIndex) {
|
||||||
|
// Generate contextual AI responses similar to the original logic
|
||||||
|
if (!answer || answer.toLowerCase().includes('nothing') || answer.toLowerCase().includes('don\'t know')) {
|
||||||
|
const encouragingResponses = [
|
||||||
|
"🌟 That's perfectly okay! Not knowing something is the first step to learning. Let's explore this together!",
|
||||||
|
"💡 Great honesty! Every expert started by not knowing. Your curiosity is what matters most!",
|
||||||
|
"🚀 Perfect! When we don't know something, it means we're about to discover something amazing!"
|
||||||
|
];
|
||||||
|
return encouragingResponses[Math.floor(Math.random() * encouragingResponses.length)];
|
||||||
|
} else if (answer.length < 10) {
|
||||||
|
const guidingResponses = [
|
||||||
|
"🎯 Good start! I can see you're thinking about this. Can you tell me a bit more?",
|
||||||
|
"✨ Interesting thought! What makes you think that way?",
|
||||||
|
"🔍 Nice observation! Can you expand on that idea a little?"
|
||||||
|
];
|
||||||
|
return guidingResponses[Math.floor(Math.random() * guidingResponses.length)];
|
||||||
|
} else {
|
||||||
|
const thoughtfulResponses = [
|
||||||
|
"🌟 Excellent thinking! You're really exploring this well! I love how you're approaching this scientifically.",
|
||||||
|
"💡 Great observation! You're thinking like a real scientist! Your reasoning shows great curiosity.",
|
||||||
|
"🔍 Wonderful insight! You're asking exactly the right questions! Keep that investigative spirit!"
|
||||||
|
];
|
||||||
|
return thoughtfulResponses[Math.floor(Math.random() * thoughtfulResponses.length)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async revealAnswer(question) {
|
||||||
|
console.log('🎯 Revealing answer for:', question);
|
||||||
|
|
||||||
|
const revealBtn = document.querySelector('.reveal-btn');
|
||||||
|
const answerContent = document.getElementById('answer-content');
|
||||||
|
|
||||||
|
if (!revealBtn || !answerContent) {
|
||||||
|
console.error('❌ Could not find reveal elements');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show loading state
|
||||||
|
revealBtn.innerHTML = '<span class="btn-icon">⏳</span> Getting Answer...';
|
||||||
|
revealBtn.disabled = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/reveal-answer', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
question: question,
|
||||||
|
userAnswers: this.userAnswers,
|
||||||
|
language: this.currentLanguage
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.success && data.answer) {
|
||||||
|
// Display the answer
|
||||||
|
answerContent.innerHTML = `
|
||||||
|
<div class="final-answer">
|
||||||
|
<div class="answer-header">
|
||||||
|
<span class="answer-icon">💡</span>
|
||||||
|
<h4>${this.currentLanguage === 'de' ? 'Die Antwort:' : 'The Answer:'}</h4>
|
||||||
|
<small class="answer-source">✨ AI • Scientific Explanation</small>
|
||||||
|
</div>
|
||||||
|
<div class="answer-text">
|
||||||
|
${data.answer.text}
|
||||||
|
</div>
|
||||||
|
<div class="answer-footer">
|
||||||
|
<p>🎉 ${this.currentLanguage === 'de'
|
||||||
|
? 'Großartig! Wie nah warst du mit deinen Überlegungen?'
|
||||||
|
: 'Awesome! How close were your thoughts to the answer?'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
answerContent.style.display = 'block';
|
||||||
|
revealBtn.style.display = 'none';
|
||||||
|
|
||||||
|
// Animate answer in
|
||||||
|
answerContent.style.opacity = '0';
|
||||||
|
answerContent.style.transform = 'translateY(20px)';
|
||||||
|
setTimeout(() => {
|
||||||
|
answerContent.style.transition = 'all 0.6s ease-out';
|
||||||
|
answerContent.style.opacity = '1';
|
||||||
|
answerContent.style.transform = 'translateY(0)';
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error(data.error || 'Failed to get answer');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error getting final answer:', error);
|
||||||
|
|
||||||
|
// Fallback answer display
|
||||||
|
revealBtn.innerHTML = `<span class="btn-icon">🎯</span> ${this.currentLanguage === 'de' ? 'Antwort zeigen!' : 'Reveal Answer!'}`;
|
||||||
|
revealBtn.disabled = false;
|
||||||
|
|
||||||
|
answerContent.innerHTML = `
|
||||||
|
<div class="final-answer fallback">
|
||||||
|
<div class="answer-header">
|
||||||
|
<span class="answer-icon">🤔</span>
|
||||||
|
<h4>${this.currentLanguage === 'de' ? 'Hmm...' : 'Hmm...'}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="answer-text">
|
||||||
|
<p>${this.currentLanguage === 'de'
|
||||||
|
? 'Ich kann die Antwort gerade nicht abrufen. Das ist eine tolle Frage! Du hast schon toll nachgedacht. Frag gerne einen Erwachsenen oder schaue in einem Buch nach.'
|
||||||
|
: 'I can\'t fetch the answer right now. That\'s a great question! You\'ve done great thinking already. Feel free to ask an adult or look it up in a book.'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
answerContent.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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');
|
||||||
@@ -123,363 +123,19 @@ app.post('/api/reveal-answer', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// API endpoint for checking math answers
|
|
||||||
app.post('/api/check-math-answer', async (req, res) => {
|
|
||||||
const { question, userAnswer, language = 'en' } = req.body;
|
|
||||||
|
|
||||||
if (!question || !userAnswer) {
|
|
||||||
return res.status(400).json({
|
|
||||||
success: false,
|
|
||||||
error: 'Question and user answer are required'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Extract the math expression from the question
|
|
||||||
const correctAnswer = calculateMathAnswer(question);
|
|
||||||
const userAnswerNum = parseFloat(userAnswer.trim());
|
|
||||||
|
|
||||||
const isCorrect = !isNaN(userAnswerNum) && Math.abs(userAnswerNum - correctAnswer) < 0.001;
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
correct: isCorrect,
|
|
||||||
expectedAnswer: correctAnswer,
|
|
||||||
userAnswer: userAnswerNum,
|
|
||||||
hint: !isCorrect ? (language === 'de' ? 'Überprüfe deine Rechnung nochmal.' : 'Check your calculation again.') : null
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Math check error:', error);
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
correct: true, // Fallback to correct if calculation fails
|
|
||||||
expectedAnswer: null,
|
|
||||||
userAnswer: userAnswer
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// API endpoint for getting additional math hints
|
|
||||||
app.post('/api/get-more-hints', async (req, res) => {
|
|
||||||
const { question, language = 'en', previousHints = [] } = req.body;
|
|
||||||
|
|
||||||
if (!question) {
|
|
||||||
return res.status(400).json({
|
|
||||||
success: false,
|
|
||||||
error: 'Question is required'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Generate additional hints based on the math problem
|
|
||||||
const additionalHints = await generateAdditionalMathHints(question, language, previousHints);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
hints: additionalHints,
|
|
||||||
question: question,
|
|
||||||
language: language
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Additional hints error:', error);
|
|
||||||
|
|
||||||
// Fallback hints if AI fails
|
|
||||||
const fallbackHints = getFallbackMathHints(question, language);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
hints: fallbackHints,
|
|
||||||
question: question,
|
|
||||||
language: language,
|
|
||||||
fallback: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// API endpoint for interactive thinking feedback
|
|
||||||
app.post('/api/think-response', async (req, res) => {
|
|
||||||
const { question, thought, stepNumber, language = 'en' } = req.body;
|
|
||||||
|
|
||||||
if (!question || !thought) {
|
|
||||||
return res.status(400).json({
|
|
||||||
success: false,
|
|
||||||
error: 'Question and thought are required'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get AI feedback on the child's thinking
|
|
||||||
const feedback = await getThinkingFeedback(question, thought, stepNumber, language);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
feedback: feedback,
|
|
||||||
question: question,
|
|
||||||
thought: thought,
|
|
||||||
language: language
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Thinking feedback error:', error);
|
|
||||||
|
|
||||||
// Fallback positive feedback
|
|
||||||
const fallbackFeedback = getFallbackThinkingFeedback(language);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
feedback: fallbackFeedback,
|
|
||||||
question: question,
|
|
||||||
thought: thought,
|
|
||||||
language: language,
|
|
||||||
fallback: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// API endpoint for interactive thinking feedback
|
|
||||||
app.post('/api/thinking-feedback', async (req, res) => {
|
|
||||||
const { question, stepNumber, userThought, language = 'en' } = req.body;
|
|
||||||
|
|
||||||
if (!question || !userThought || stepNumber === undefined) {
|
|
||||||
return res.status(400).json({
|
|
||||||
success: false,
|
|
||||||
error: 'Question, step number, and user thought are required'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get AI feedback on the child's thinking
|
|
||||||
const feedback = await getThinkingFeedback(question, userThought, stepNumber, language);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
feedback: feedback,
|
|
||||||
question: question,
|
|
||||||
stepNumber: stepNumber,
|
|
||||||
userThought: userThought,
|
|
||||||
language: language
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Thinking feedback error:', error);
|
|
||||||
|
|
||||||
// Fallback positive feedback
|
|
||||||
const fallbackFeedback = {
|
|
||||||
response: language === 'de'
|
|
||||||
? "Interessante Gedanken! Du denkst in die richtige Richtung. 👍"
|
|
||||||
: "Interesting thoughts! You're thinking in the right direction. 👍",
|
|
||||||
encouragement: language === 'de'
|
|
||||||
? "Weiter so!"
|
|
||||||
: "Keep going!",
|
|
||||||
type: 'positive'
|
|
||||||
};
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
feedback: fallbackFeedback,
|
|
||||||
question: question,
|
|
||||||
stepNumber: stepNumber,
|
|
||||||
userThought: userThought,
|
|
||||||
language: language,
|
|
||||||
fallback: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// API endpoint for AI conversation (when child replies to AI questions)
|
|
||||||
app.post('/api/ai-conversation', async (req, res) => {
|
|
||||||
const { originalQuestion, userReply, language = 'en' } = req.body;
|
|
||||||
|
|
||||||
if (!originalQuestion || !userReply) {
|
|
||||||
return res.status(400).json({
|
|
||||||
success: false,
|
|
||||||
error: 'Original question and user reply are required'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get AI response to continue the conversation
|
|
||||||
const aiResponse = await getConversationResponse(originalQuestion, userReply, language);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
aiResponse: aiResponse,
|
|
||||||
originalQuestion: originalQuestion,
|
|
||||||
userReply: userReply,
|
|
||||||
language: language
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('AI Conversation Error:', error);
|
|
||||||
|
|
||||||
// Fallback response if AI fails
|
|
||||||
const fallbackResponse = language === 'de'
|
|
||||||
? "Das ist eine interessante Antwort! Du denkst gut über das Thema nach."
|
|
||||||
: "That's an interesting answer! You're thinking well about this topic.";
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
aiResponse: fallbackResponse,
|
|
||||||
originalQuestion: originalQuestion,
|
|
||||||
userReply: userReply,
|
|
||||||
language: language,
|
|
||||||
fallback: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate conversational AI response
|
|
||||||
async function getConversationResponse(originalQuestion, userReply, language) {
|
|
||||||
const isGerman = language === 'de';
|
|
||||||
|
|
||||||
const systemPrompt = isGerman
|
|
||||||
? "Du bist ein geduldiger Lehrer, der mit einem Kind über ein interessantes Thema spricht. Das Kind hat gerade auf eine deiner Fragen geantwortet. Reagiere natürlich auf ihre Antwort: anerkenne was sie gesagt haben, baue darauf auf, und stelle wenn nötig eine weiterführende Frage um ihr Verständnis zu vertiefen. Sei ermutigend und neugierig. Halte deine Antworten kurz (1-2 Sätze) und altersgerecht."
|
|
||||||
: "You are a patient teacher having a conversation with a child about an interesting topic. The child just answered one of your questions. Respond naturally to their answer: acknowledge what they said, build upon it, and ask a follow-up question if needed to deepen their understanding. Be encouraging and curious. Keep your responses short (1-2 sentences) and age-appropriate.";
|
|
||||||
|
|
||||||
const userPrompt = isGerman
|
|
||||||
? `Ursprüngliche Frage: "${originalQuestion}"\nKind hat geantwortet: "${userReply}"\n\nReagiere natürlich auf ihre Antwort und führe das Gespräch weiter.`
|
|
||||||
: `Original question: "${originalQuestion}"\nChild replied: "${userReply}"\n\nRespond naturally to their answer and continue the conversation.`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const completion = await openai.chat.completions.create({
|
|
||||||
model: "gpt-3.5-turbo",
|
|
||||||
messages: [
|
|
||||||
{ role: "system", content: systemPrompt },
|
|
||||||
{ role: "user", content: userPrompt }
|
|
||||||
],
|
|
||||||
max_tokens: 150,
|
|
||||||
temperature: 0.8
|
|
||||||
});
|
|
||||||
|
|
||||||
const aiResponse = completion.choices[0]?.message?.content || '';
|
|
||||||
console.log(`✅ AI conversation response: ${aiResponse.substring(0, 100)}...`);
|
|
||||||
|
|
||||||
return aiResponse;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log('❌ AI conversation error:', error.message);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to calculate the correct answer for simple math expressions
|
|
||||||
function calculateMathAnswer(question) {
|
|
||||||
const questionLower = question.toLowerCase().trim();
|
|
||||||
|
|
||||||
// Extract numbers and operation from common question formats
|
|
||||||
let match;
|
|
||||||
|
|
||||||
// Pattern: "what is X+Y" or "was ist X+Y"
|
|
||||||
match = questionLower.match(/(?:what\s+is\s+|was\s+ist\s+)?(\d+(?:\.\d+)?)\s*\+\s*(\d+(?:\.\d+)?)/);
|
|
||||||
if (match) {
|
|
||||||
return parseFloat(match[1]) + parseFloat(match[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pattern: "what is X-Y"
|
|
||||||
match = questionLower.match(/(?:what\s+is\s+|was\s+ist\s+)?(\d+(?:\.\d+)?)\s*-\s*(\d+(?:\.\d+)?)/);
|
|
||||||
if (match) {
|
|
||||||
return parseFloat(match[1]) - parseFloat(match[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pattern: "what is X*Y" or "X times Y"
|
|
||||||
match = questionLower.match(/(?:what\s+is\s+|was\s+ist\s+)?(\d+(?:\.\d+)?)\s*[\*x]\s*(\d+(?:\.\d+)?)/);
|
|
||||||
if (match) {
|
|
||||||
return parseFloat(match[1]) * parseFloat(match[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pattern: "what is X/Y" or "X divided by Y"
|
|
||||||
match = questionLower.match(/(?:what\s+is\s+|was\s+ist\s+)?(\d+(?:\.\d+)?)\s*\/\s*(\d+(?:\.\d+)?)/);
|
|
||||||
if (match) {
|
|
||||||
return parseFloat(match[1]) / parseFloat(match[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no pattern matches, throw error
|
|
||||||
throw new Error('Could not parse math expression');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to analyze question type and determine interaction mode
|
|
||||||
function analyzeQuestionType(question) {
|
|
||||||
const questionLower = question.toLowerCase().trim();
|
|
||||||
|
|
||||||
// Mathematical questions - should guide to calculation
|
|
||||||
const mathPatterns = [
|
|
||||||
/what\s+is\s+\d+\s*[\+\-\*\/]\s*\d+/,
|
|
||||||
/\d+\s*[\+\-\*\/]\s*\d+/,
|
|
||||||
/\d+\s*plus\s*\d+/,
|
|
||||||
/\d+\s*minus\s*\d+/,
|
|
||||||
/\d+\s*times\s*\d+/,
|
|
||||||
/\d+\s*divided\s*by\s*\d+/,
|
|
||||||
/calculate/,
|
|
||||||
/was\s+ist\s+\d+\s*[\+\-\*\/]\s*\d+/,
|
|
||||||
/rechne/,
|
|
||||||
/plus|minus|mal|geteilt|add|subtract|multiply|divide/
|
|
||||||
];
|
|
||||||
|
|
||||||
// Simple factual questions - should guide to discovery
|
|
||||||
const factualPatterns = [
|
|
||||||
/what\s+color\s+is/,
|
|
||||||
/how\s+many/,
|
|
||||||
/what\s+day\s+is/,
|
|
||||||
/what\s+time\s+is/,
|
|
||||||
/welche\s+farbe/,
|
|
||||||
/wie\s+viele/,
|
|
||||||
/welcher\s+tag/,
|
|
||||||
/wie\s+spät/
|
|
||||||
];
|
|
||||||
|
|
||||||
if (mathPatterns.some(pattern => pattern.test(questionLower))) {
|
|
||||||
console.log(`🧮 Detected mathematical question: "${question}"`);
|
|
||||||
return 'mathematical';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (factualPatterns.some(pattern => pattern.test(questionLower))) {
|
|
||||||
console.log(`📋 Detected simple factual question: "${question}"`);
|
|
||||||
return 'factual_simple';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to exploratory for complex questions
|
|
||||||
console.log(`🤔 Detected exploratory question: "${question}"`);
|
|
||||||
return 'exploratory';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to get OpenAI-powered educational guidance (Primary)
|
// Function to get OpenAI-powered educational guidance (Primary)
|
||||||
async function getOpenAIGuidance(question, language) {
|
async function getOpenAIGuidance(question, language) {
|
||||||
console.log('🤖 Calling OpenAI with GPT-3.5-turbo...');
|
console.log('🤖 Calling OpenAI with GPT-3.5-turbo...');
|
||||||
|
|
||||||
const isGerman = language === 'de';
|
const isGerman = language === 'de';
|
||||||
const questionType = analyzeQuestionType(question);
|
|
||||||
|
|
||||||
let systemPrompt;
|
const systemPrompt = isGerman
|
||||||
let userPrompt;
|
? "Du bist ein geduldiger Lehrer für Kinder. Anstatt direkte Antworten zu geben, führe das Kind Schritt für Schritt zum Verständnis. Stelle 3-4 aufbauende Fragen, die das Kind zum Nachdenken anregen und ihm helfen, die Antwort selbst zu entdecken. Jede Frage sollte auf der vorherigen aufbauen und dem Kind helfen, das Konzept zu verstehen. Verwende einfache Sprache und ermutigende Worte. Formatiere als nummerierte Liste."
|
||||||
|
: "You are a patient teacher for children. Instead of giving direct answers, guide the child step by step to understanding. Ask 3-4 building questions that encourage the child to think and help them discover the answer themselves. Each question should build on the previous one and help the child understand the concept. Use simple language and encouraging words. Format as a numbered list.";
|
||||||
|
|
||||||
if (questionType === 'mathematical') {
|
const userPrompt = isGerman
|
||||||
systemPrompt = isGerman
|
? `Ein Kind hat gefragt: "${question}". Führe es Schritt für Schritt zum Verständnis, ohne die Antwort direkt zu verraten. Stelle aufbauende Fragen, die dem Kind helfen, selbst zu denken und die Antwort zu entdecken. Jede Frage sollte das Kind näher zur Lösung führen.`
|
||||||
? "Du bist ein Mathe-Tutor für Kinder. Für einfache Rechenaufgaben führst du das Kind durch konkrete mathematische Schritte, aber verrate NIEMALS die finale Antwort. Erkläre das Rechensymbol, verwende einfache Beispiele, und lass das Kind selbst rechnen. Gib 2-3 Schritte die zum Rechnen anleiten, aber sage NIE das Endergebnis."
|
: `A child asked: "${question}". Guide them step by step to understanding without giving away the answer directly. Ask building questions that help the child think for themselves and discover the answer. Each question should bring the child closer to the solution.`;
|
||||||
: "You are a math tutor for children. For simple math problems, guide the child through concrete mathematical steps, but NEVER reveal the final answer. Explain the math symbol, use simple examples, and let the child calculate themselves. Provide 2-3 steps that guide calculation, but NEVER state the final result.";
|
|
||||||
|
|
||||||
userPrompt = isGerman
|
|
||||||
? `Ein Kind fragt: "${question}". Gib 2-3 konkrete Mathe-Schritte die zum Rechnen anleiten. Erkläre was das Symbol bedeutet, verwende zählbare Beispiele, aber verrate NIEMALS die finale Antwort. Das Kind soll selbst rechnen und die Antwort finden.`
|
|
||||||
: `A child asks: "${question}". Provide 2-3 concrete math steps that guide calculation. Explain what the symbol means, use countable examples, but NEVER reveal the final answer. The child should calculate and find the answer themselves.`;
|
|
||||||
} else if (questionType === 'factual_simple') {
|
|
||||||
systemPrompt = isGerman
|
|
||||||
? "Du bist ein Lernbegleiter für Kinder. Bei einfachen Faktenfragen stellst du 2-3 spezifische, logische Schritte, die das Kind zur Antwort führen. Verwende konkrete Beispiele und Beobachtungen, die das Kind selbst machen kann. Keine allgemeinen Fragen, sondern spezifische Denkschritte."
|
|
||||||
: "You are a learning companion for children. For simple factual questions, provide 2-3 specific, logical steps that lead the child to the answer. Use concrete examples and observations the child can make themselves. No general questions, but specific thinking steps.";
|
|
||||||
|
|
||||||
userPrompt = isGerman
|
|
||||||
? `Ein Kind fragt: "${question}". Gib 2-3 konkrete Denkschritte, die spezifisch zu dieser Frage passen. Verwende Beispiele und lass das Kind selbst beobachten oder überlegen.`
|
|
||||||
: `A child asks: "${question}". Provide 2-3 concrete thinking steps that are specific to this question. Use examples and have the child observe or think for themselves.`;
|
|
||||||
} else {
|
|
||||||
// For exploratory questions, provide a conversational AI response
|
|
||||||
systemPrompt = isGerman
|
|
||||||
? "Du bist ein freundlicher AI-Lehrer für Kinder. Antworte auf ihre Fragen mit einfachen, altersgerechten Erklärungen. Stelle am Ende oft eine Rückfrage, um das Gespräch fortzusetzen und das Kind zum Nachdenken anzuregen. Verwende Emojis und eine warme, einladende Sprache."
|
|
||||||
: "You are a friendly AI teacher for children. Answer their questions with simple, age-appropriate explanations. Often ask a follow-up question at the end to continue the conversation and encourage the child to think. Use emojis and warm, inviting language.";
|
|
||||||
|
|
||||||
userPrompt = isGerman
|
|
||||||
? `Ein Kind fragt: "${question}". Gib eine freundliche, verständliche Antwort und stelle eine Rückfrage, um das Gespräch fortzusetzen.`
|
|
||||||
: `A child asks: "${question}". Give a friendly, understandable answer and ask a follow-up question to continue the conversation.`;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const completion = await openai.chat.completions.create({
|
const completion = await openai.chat.completions.create({
|
||||||
@@ -495,29 +151,15 @@ async function getOpenAIGuidance(question, language) {
|
|||||||
const aiResponse = completion.choices[0]?.message?.content || '';
|
const aiResponse = completion.choices[0]?.message?.content || '';
|
||||||
console.log('✅ OpenAI response received:', aiResponse.substring(0, 100) + '...');
|
console.log('✅ OpenAI response received:', aiResponse.substring(0, 100) + '...');
|
||||||
|
|
||||||
if (questionType === 'exploratory') {
|
// Parse the response into steps
|
||||||
// For exploratory questions, return conversational response
|
|
||||||
return {
|
|
||||||
type: 'ai-powered',
|
|
||||||
questionType: questionType,
|
|
||||||
conversationalResponse: aiResponse,
|
|
||||||
encouragement: getRandomEncouragement(language),
|
|
||||||
source: 'OpenAI GPT-3.5',
|
|
||||||
showAnswerReveal: false
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// Parse the response into steps for math/factual questions
|
|
||||||
const steps = parseOpenAIResponseToSteps(aiResponse, language);
|
const steps = parseOpenAIResponseToSteps(aiResponse, language);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'ai-powered',
|
type: 'ai-powered',
|
||||||
questionType: questionType,
|
|
||||||
steps: steps,
|
steps: steps,
|
||||||
encouragement: getRandomEncouragement(language),
|
encouragement: getRandomEncouragement(language),
|
||||||
source: 'OpenAI GPT-3.5',
|
source: 'OpenAI GPT-3.5'
|
||||||
showAnswerReveal: questionType === 'exploratory' // Only show reveal for complex questions
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('❌ OpenAI error:', error.message);
|
console.log('❌ OpenAI error:', error.message);
|
||||||
@@ -680,7 +322,48 @@ async function getAIGuidance(question, language) {
|
|||||||
// Fallback guidance for when AI is unavailable
|
// Fallback guidance for when AI is unavailable
|
||||||
function getFallbackGuidance(question, language) {
|
function getFallbackGuidance(question, language) {
|
||||||
const isGerman = language === 'de';
|
const isGerman = language === 'de';
|
||||||
|
const questionLower = question.toLowerCase();
|
||||||
|
|
||||||
|
// Topic-specific guided questions like in the image
|
||||||
|
if (questionLower.includes('bird') || questionLower.includes('fly') || questionLower.includes('wing')) {
|
||||||
|
const birdQuestions = isGerman ? [
|
||||||
|
{ id: 1, text: "Was weißt du bereits über Vögel und ihre Flügel?", type: 'question' },
|
||||||
|
{ id: 2, text: "Wie denkst du, nutzen Vögel ihre Flügel, um sich durch die Luft zu bewegen?", type: 'question' },
|
||||||
|
{ id: 3, text: "Kannst du an andere Tiere denken, die fliegen können, und wie unterscheiden sie sich in ihren Flugfähigkeiten?", type: 'question' }
|
||||||
|
] : [
|
||||||
|
{ id: 1, text: "What do you already know about this topic?", type: 'question' },
|
||||||
|
{ id: 2, text: "How do birds use their wings to generate lift and propel themselves through the air?", type: 'question' },
|
||||||
|
{ id: 3, text: "Can you think of any other animals that can fly like birds, and how do they differ in their flying abilities?", type: 'question' }
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'topic-specific',
|
||||||
|
steps: birdQuestions,
|
||||||
|
encouragement: getRandomEncouragement(language),
|
||||||
|
source: 'Educational Framework'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (questionLower.includes('sky') || questionLower.includes('blue') || questionLower.includes('himmel') || questionLower.includes('blau')) {
|
||||||
|
const skyQuestions = isGerman ? [
|
||||||
|
{ id: 1, text: "Was weißt du bereits über Licht und Farben?", type: 'question' },
|
||||||
|
{ id: 2, text: "Was passiert mit Licht, wenn es durch die Luft geht?", type: 'question' },
|
||||||
|
{ id: 3, text: "Warum siehst du manche Farben deutlicher als andere?", type: 'question' }
|
||||||
|
] : [
|
||||||
|
{ id: 1, text: "What do you already know about light and colors?", type: 'question' },
|
||||||
|
{ id: 2, text: "What happens to light when it travels through the air?", type: 'question' },
|
||||||
|
{ id: 3, text: "Why do you see some colors more clearly than others?", type: 'question' }
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'topic-specific',
|
||||||
|
steps: skyQuestions,
|
||||||
|
encouragement: getRandomEncouragement(language),
|
||||||
|
source: 'Educational Framework'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic fallback questions
|
||||||
const fallbackSteps = isGerman ? [
|
const fallbackSteps = isGerman ? [
|
||||||
{ id: 1, text: "Was weißt du bereits über dieses Thema?", type: 'question' },
|
{ id: 1, text: "Was weißt du bereits über dieses Thema?", type: 'question' },
|
||||||
{ id: 2, text: "Welche Teile der Frage verstehst du, und welche sind unklar?", type: 'question' },
|
{ id: 2, text: "Welche Teile der Frage verstehst du, und welche sind unklar?", type: 'question' },
|
||||||
@@ -825,201 +508,3 @@ function getFallbackAnswer(question, language) {
|
|||||||
source: 'Educational Framework'
|
source: 'Educational Framework'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate additional math hints using AI
|
|
||||||
async function generateAdditionalMathHints(question, language, previousHints) {
|
|
||||||
const isGerman = language === 'de';
|
|
||||||
|
|
||||||
const systemPrompt = isGerman
|
|
||||||
? "Du bist ein geduldiger Mathe-Tutor für Kinder. Das Kind hat bereits Schwierigkeiten mit einer Rechenaufgabe. Gib 2-3 zusätzliche, sehr einfache und konkrete Hilfestellungen. Verwende noch einfachere Beispiele, zerlege die Aufgabe in kleinere Schritte, oder verwende visuelle Hilfsmittel wie Finger oder Gegenstände. Sei ermutigend und geduldig."
|
|
||||||
: "You are a patient math tutor for children. The child is already struggling with a math problem. Provide 2-3 additional, very simple and concrete hints. Use even simpler examples, break the problem into smaller steps, or use visual aids like fingers or objects. Be encouraging and patient.";
|
|
||||||
|
|
||||||
const userPrompt = isGerman
|
|
||||||
? `Ein Kind hat Schwierigkeiten mit: "${question}". Es braucht zusätzliche, einfachere Hilfe. Gib 2-3 sehr konkrete, einfache Schritte mit visuellen Hilfsmitteln oder noch einfacheren Beispielen.`
|
|
||||||
: `A child is struggling with: "${question}". They need additional, simpler help. Provide 2-3 very concrete, simple steps with visual aids or even simpler examples.`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const completion = await openai.chat.completions.create({
|
|
||||||
model: "gpt-3.5-turbo",
|
|
||||||
messages: [
|
|
||||||
{ role: "system", content: systemPrompt },
|
|
||||||
{ role: "user", content: userPrompt }
|
|
||||||
],
|
|
||||||
max_tokens: 200,
|
|
||||||
temperature: 0.7
|
|
||||||
});
|
|
||||||
|
|
||||||
const aiResponse = completion.choices[0]?.message?.content || '';
|
|
||||||
const steps = parseOpenAIResponseToSteps(aiResponse, language);
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'ai-powered',
|
|
||||||
steps: steps,
|
|
||||||
encouragement: isGerman ? "Keine Sorge, wir schaffen das zusammen! 💪" : "Don't worry, we can do this together! 💪",
|
|
||||||
source: 'OpenAI GPT-3.5'
|
|
||||||
};
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log('❌ Additional hints AI error:', error.message);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback hints for when AI is not available
|
|
||||||
function getFallbackMathHints(question, language) {
|
|
||||||
const isGerman = language === 'de';
|
|
||||||
const questionLower = question.toLowerCase();
|
|
||||||
|
|
||||||
// Determine operation type and generate appropriate hints
|
|
||||||
let hints = [];
|
|
||||||
|
|
||||||
if (questionLower.includes('+') || questionLower.includes('plus')) {
|
|
||||||
hints = isGerman ? [
|
|
||||||
"Verwende deine Finger zum Zählen - das macht es einfacher!",
|
|
||||||
"Nimm die erste Zahl und zähle dann die zweite Zahl dazu.",
|
|
||||||
"Du kannst auch kleine Gegenstände wie Münzen oder Stifte zum Zählen verwenden."
|
|
||||||
] : [
|
|
||||||
"Use your fingers for counting - it makes it easier!",
|
|
||||||
"Take the first number and count the second number on top of it.",
|
|
||||||
"You can also use small objects like coins or pencils for counting."
|
|
||||||
];
|
|
||||||
} else if (questionLower.includes('-') || questionLower.includes('minus')) {
|
|
||||||
hints = isGerman ? [
|
|
||||||
"Bei Minus nehmen wir etwas weg. Starte mit der ersten Zahl.",
|
|
||||||
"Zähle rückwärts um die zweite Zahl.",
|
|
||||||
"Stelle dir vor, du hast Süßigkeiten und gibst einige weg."
|
|
||||||
] : [
|
|
||||||
"With minus, we take something away. Start with the first number.",
|
|
||||||
"Count backwards by the second number.",
|
|
||||||
"Imagine you have candies and you give some away."
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
// Generic math hints
|
|
||||||
hints = isGerman ? [
|
|
||||||
"Lass uns das Problem in kleinere Teile aufteilen.",
|
|
||||||
"Verwende deine Finger oder male kleine Kreise zum Zählen.",
|
|
||||||
"Nimm dir Zeit - Mathe ist wie ein Puzzle, das wir zusammen lösen."
|
|
||||||
] : [
|
|
||||||
"Let's break the problem into smaller parts.",
|
|
||||||
"Use your fingers or draw small circles for counting.",
|
|
||||||
"Take your time - math is like a puzzle we solve together."
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'fallback',
|
|
||||||
steps: hints.map((hint, index) => ({
|
|
||||||
id: index + 1,
|
|
||||||
text: hint,
|
|
||||||
type: 'hint'
|
|
||||||
})),
|
|
||||||
encouragement: isGerman ? "Du schaffst das! 🌟" : "You can do it! 🌟",
|
|
||||||
source: 'Fallback'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate AI feedback on child's thinking
|
|
||||||
async function getThinkingFeedback(question, thought, stepNumber, language) {
|
|
||||||
const isGerman = language === 'de';
|
|
||||||
|
|
||||||
// Analyze the child's response to provide intelligent feedback
|
|
||||||
const thoughtLower = thought.toLowerCase().trim();
|
|
||||||
|
|
||||||
// Handle special cases first
|
|
||||||
if (thoughtLower === '' || thoughtLower.length < 2) {
|
|
||||||
return {
|
|
||||||
response: isGerman ? "Erzähl mir mehr über deine Gedanken!" : "Tell me more about your thoughts!",
|
|
||||||
encouragement: isGerman ? "Jede Idee zählt! 💭" : "Every idea counts! 💭",
|
|
||||||
type: 'encouraging',
|
|
||||||
source: 'Rule-based'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thoughtLower === 'i dont know' || thoughtLower === 'i don\'t know' || thoughtLower === 'ich weiß nicht' || thoughtLower === 'weiß nicht') {
|
|
||||||
return {
|
|
||||||
response: isGerman ?
|
|
||||||
"Das ist okay! Lass uns gemeinsam überlegen. Was fällt dir als erstes ein, wenn du an diese Frage denkst?" :
|
|
||||||
"That's okay! Let's think together. What's the first thing that comes to mind when you think about this question?",
|
|
||||||
encouragement: isGerman ? "Gemeinsam finden wir eine Antwort! 🤝" : "Together we'll find an answer! 🤝",
|
|
||||||
type: 'supportive',
|
|
||||||
source: 'Rule-based'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thoughtLower === 'no' || thoughtLower === 'nein' || thoughtLower === 'ja' || thoughtLower === 'yes') {
|
|
||||||
return {
|
|
||||||
response: isGerman ?
|
|
||||||
"Interessant! Kannst du mir mehr darüber erzählen, warum du so denkst?" :
|
|
||||||
"Interesting! Can you tell me more about why you think that?",
|
|
||||||
encouragement: isGerman ? "Deine Meinung ist wichtig! 💬" : "Your opinion matters! 💬",
|
|
||||||
type: 'probing',
|
|
||||||
source: 'Rule-based'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// For substantial responses, use AI with much better prompts
|
|
||||||
const systemPrompt = isGerman
|
|
||||||
? `Du bist ein intelligenter Tutor für Kinder. Ein Kind hat auf eine Denkfrage geantwortet. Deine Aufgabe:
|
|
||||||
|
|
||||||
1. ANALYSIERE den Gedanken des Kindes sorgfältig
|
|
||||||
2. ERKENNE richtige Ansätze und baue darauf auf
|
|
||||||
3. KORRIGIERE sanft Missverständnisse ohne die Antwort zu verraten
|
|
||||||
4. STELLE eine Nachfrage, die das Denken vertieft
|
|
||||||
5. SEI spezifisch, nicht generisch
|
|
||||||
|
|
||||||
Antworte in 1-2 Sätzen. Vermeide generische Phrasen wie "Gut gemacht!" oder "Weiter so!"`
|
|
||||||
: `You are an intelligent tutor for children. A child has responded to a thinking question. Your job:
|
|
||||||
|
|
||||||
1. ANALYZE the child's thought carefully
|
|
||||||
2. RECOGNIZE correct approaches and build on them
|
|
||||||
3. GENTLY correct misunderstandings without revealing the answer
|
|
||||||
4. ASK a follow-up question that deepens thinking
|
|
||||||
5. BE specific, not generic
|
|
||||||
|
|
||||||
Respond in 1-2 sentences. Avoid generic phrases like "Good job!" or "Keep going!"`;
|
|
||||||
|
|
||||||
const userPrompt = isGerman
|
|
||||||
? `Original Frage: "${question}"
|
|
||||||
Schritt ${stepNumber}
|
|
||||||
Kind antwortete: "${thought}"
|
|
||||||
|
|
||||||
Gib intelligente, spezifische Rückmeldung zu diesem Gedanken. Baue auf richtigen Ansätzen auf oder korrigiere sanft Missverständnisse. Stelle eine durchdachte Nachfrage.`
|
|
||||||
: `Original Question: "${question}"
|
|
||||||
Step ${stepNumber}
|
|
||||||
Child responded: "${thought}"
|
|
||||||
|
|
||||||
Give intelligent, specific feedback about this thought. Build on correct approaches or gently correct misunderstandings. Ask a thoughtful follow-up question.`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const completion = await openai.chat.completions.create({
|
|
||||||
model: "gpt-3.5-turbo",
|
|
||||||
messages: [
|
|
||||||
{ role: "system", content: systemPrompt },
|
|
||||||
{ role: "user", content: userPrompt }
|
|
||||||
],
|
|
||||||
max_tokens: 120,
|
|
||||||
temperature: 0.8
|
|
||||||
});
|
|
||||||
|
|
||||||
const aiResponse = completion.choices[0]?.message?.content || '';
|
|
||||||
|
|
||||||
// Determine feedback type based on content and child's response quality
|
|
||||||
let responseType = 'neutral';
|
|
||||||
if (thoughtLower.length > 10 || thoughtLower.includes('because') || thoughtLower.includes('weil')) {
|
|
||||||
responseType = 'positive';
|
|
||||||
} else if (thoughtLower.length < 5) {
|
|
||||||
responseType = 'encouraging';
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
response: aiResponse.trim(),
|
|
||||||
encouragement: isGerman ? "Du denkst gut mit! 🧠" : "You're thinking well! 🧠",
|
|
||||||
type: responseType,
|
|
||||||
source: 'OpenAI GPT-3.5'
|
|
||||||
};
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log('❌ Thinking feedback AI error:', error.message);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user