v4: conversational teacher with context memory

This commit is contained in:
Ruslan 2026-09-09 11:03:37 +00:00
parent f6cce5394a
commit 14a21dbcbe
2 changed files with 262 additions and 60 deletions

308
script.js
View File

@ -275,6 +275,7 @@ const levelsData = {
// Текущее состояние // Текущее состояние
let currentLevel = null; let currentLevel = null;
let chatSessionId = null; let chatSessionId = null;
let chatHistory = []; // История переписки для контекста
// DOM элементы // DOM элементы
const levelsSection = document.getElementById('levels-section'); const levelsSection = document.getElementById('levels-section');
@ -438,6 +439,12 @@ function toggleChat() {
teacherChat.classList.toggle('hidden'); teacherChat.classList.toggle('hidden');
if (!teacherChat.classList.contains('hidden')) { if (!teacherChat.classList.contains('hidden')) {
chatInput.focus(); chatInput.focus();
// Если чат открыли впервые - приветствуем
if (chatHistory.length === 0) {
setTimeout(() => {
addMessage('Hi there! 👋 I\'m your English teacher! Let\'s have a conversation! Tell me about yourself - where are you from?', 'teacher');
}, 500);
}
} }
} }
@ -448,26 +455,39 @@ async function sendMessage() {
// Добавляем сообщение студента // Добавляем сообщение студента
addMessage(text, 'student'); addMessage(text, 'student');
chatInput.value = ''; chatInput.value = '';
sendBtn.disabled = true;
// Показываем индикатор набора // Показываем индикатор набора
showTypingIndicator(); showTypingIndicator();
try { try {
// Небольшая задержка для естественности
await new Promise(resolve => setTimeout(resolve, 600));
// Получаем ответ от ИИ // Получаем ответ от ИИ
const response = await askTeacher(text); const response = await askTeacher(text);
hideTypingIndicator(); hideTypingIndicator();
addMessage(response, 'teacher'); addMessage(response, 'teacher');
} catch (error) { } catch (error) {
hideTypingIndicator(); hideTypingIndicator();
addMessage('Извини, я временно недоступен. Попробуй ещё раз!', 'teacher'); addMessage('Hmm, I had trouble processing that. Try rephrasing? 😊', 'teacher');
console.error('Teacher error:', error); console.error('Teacher error:', error);
} }
sendBtn.disabled = false;
chatInput.focus();
} }
function addMessage(text, type) { function addMessage(text, type) {
const messageDiv = document.createElement('div'); const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`; messageDiv.className = `message ${type}`;
messageDiv.innerHTML = `<div class="message-bubble">${text}</div>`;
// Добавляем аватарки
const avatar = type === 'teacher' ? '👨‍🏫' : '👤';
messageDiv.innerHTML = `
<div class="message-avatar">${avatar}</div>
<div class="message-bubble">${text}</div>
`;
chatMessages.appendChild(messageDiv); chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight; chatMessages.scrollTop = chatMessages.scrollHeight;
} }
@ -494,135 +514,295 @@ function hideTypingIndicator() {
if (typing) typing.remove(); if (typing) typing.remove();
} }
// Готовые ответы для статической версии (без сервера) // Готовые ответы для статической версии (без сервера) - РАЗГОВОРНЫЙ РЕЖИМ
const teacherResponses = { const teacherResponses = {
greetings: { greetings: {
keywords: ['hello', 'hi', 'привет', 'здравствуй', 'good morning', 'good afternoon'], keywords: ['hello', 'hi', 'привет', 'здравствуй', 'good morning', 'good afternoon', 'hey'],
answers: [ answers: [
'Hello! Great to see you! How can I help you with English today?', 'Hello! Great to see you! 😊 How are you today? Tell me in English!',
'Hi there! Ready to practice English? What would you like to work on?', 'Hi there! Ready to practice English? What have you been doing lately?',
'Hello! I\'m your English teacher. Ask me anything about grammar, vocabulary, or let\'s just chat!' 'Hello! I\'m your English teacher. Nice to meet you! What\'s your name?',
] 'Hey! How\'s it going? Did you do anything interesting today?'
],
followUp: 'Tell me about yourself! Where are you from? What do you like to do?'
}, },
thanks: { thanks: {
keywords: ['thank', 'спасибо', 'thanks'], keywords: ['thank', 'спасибо', 'thanks', 'благодарю'],
answers: [ answers: [
'You\'re welcome! Keep up the good work! 👍', 'You\'re welcome! 😊 You\'re making great progress! Keep it up!',
'Anytime! That\'s what I\'m here for! 😊', 'Anytime! That\'s what I\'m here for! Do you have more questions?',
'No problem! Feel free to ask more questions!' 'No problem! I\'m happy to help! What else would you like to learn?'
]
},
howAreYou: {
keywords: ['how are you', 'как дела', 'how\'s it going', 'how are things'],
answers: [
'I\'m great, thank you for asking! 😊 I\'m here helping students learn English. How about you? How was your day?',
'Doing well! Excited to practice English with you! What about you? Anything new?'
]
},
name: {
keywords: ['what is your name', 'как тебя зовут', 'your name', 'кто ты'],
answers: [
'I\'m your virtual English teacher! You can call me Teacher. 😊 What\'s YOUR name?',
'I\'m your English learning companion! But I\'d love to know YOUR name. What should I call you?'
] ]
}, },
help: { help: {
keywords: ['help', 'помощь', 'помоги', 'explain', 'объясни'], keywords: ['help', 'помощь', 'помоги', 'explain', 'объясни', 'assist'],
answers: [ answers: [
'I can help you with: grammar rules, vocabulary, pronunciation tips, or just conversation practice. What do you need?', 'I\'d love to help! 🎯 I can: check your sentences, explain grammar, teach new words, or just chat. What do you prefer?',
'Sure! I can explain grammar, check your sentences, or suggest words. What topic interests you?' 'Of course! What\'s troubling you? Grammar? Vocabulary? Or maybe you want conversation practice?'
] ]
}, },
grammar: { grammar: {
keywords: ['grammar', 'грамматик', 'rule', 'правило', 'tense', 'время'], keywords: ['grammar', 'грамматик', 'rule', 'правило', 'tense', 'время'],
answers: [ answers: [
'Grammar is important! The key is practice. Start with Present Simple - it\'s the most common tense. Example: "I work every day." Want me to explain more?', 'Grammar time! 📚 Let me explain simply. Which tense confuses you? Present, Past, or Future?',
'English grammar has 12 tenses, but you only need 5-6 for daily conversation. Which tense would you like to learn?' 'Great question! Grammar is like puzzle pieces. Once you get the pattern, it clicks! What specifically?'
] ]
}, },
vocabulary: { vocabulary: {
keywords: ['word', 'слово', 'vocabulary', 'translate', 'перевод', 'meaning'], keywords: ['word', 'слово', 'vocabulary', 'translate', 'перевод', 'meaning', 'значит'],
answers: [ answers: [
'Great question! Building vocabulary takes time. Try learning 5-10 new words daily and use them in sentences. What word interests you?', 'Vocabulary is key! 🔑 Tell me the word you want to know, or I can teach you a new one!',
'I can help with translations! Just tell me the word you want to know.' 'I love teaching new words! What topic interests you? Food? Travel? Work? Emotions?'
] ]
}, },
practice: { practice: {
keywords: ['practice', 'практик', 'speak', 'говорить', 'chat', 'болтать'], keywords: ['practice', 'практик', 'speak', 'говорить', 'chat', 'болтать', 'conversation'],
answers: [ answers: [
'Let\'s practice! Tell me about your day in English. Don\'t worry about mistakes - I\'ll help you correct them!', 'Awesome! Let\'s chat! 💬 Tell me - what did you do yesterday? Use past tense!',
'Great! Let\'s have a conversation. What topics interest you? Hobbies, work, travel, movies?' 'Perfect! I love conversations! So... what are your hobbies? What do you enjoy doing?'
] ]
}, },
mistake: { mistake: {
keywords: ['mistake', 'ошибка', 'wrong', 'correct', 'правильно'], keywords: ['mistake', 'ошибка', 'wrong', 'correct', 'правильно', 'right'],
answers: [ answers: [
'Mistakes are how we learn! Don\'t be afraid to make them. Even native speakers make mistakes!', 'Mistakes are GOLD! ✨ They show you\'re trying! Tell me what you\'re unsure about.',
'Good catch! Let me explain the rule so you remember it better.' 'Don\'t worry about mistakes - they\'re part of learning! Even natives make them! Let\'s figure it out together.'
] ]
}, },
goodbye: { goodbye: {
keywords: ['bye', 'goodbye', 'пока', 'до свидания', 'see you'], keywords: ['bye', 'goodbye', 'пока', 'до свидания', 'see you', 'gotta go', 'must go'],
answers: [ answers: [
'Goodbye! Keep practicing and you\'ll improve fast! See you next time! 👋', 'Bye! 🌟 You did great today! Come back soon for more practice!',
'Bye! Great job today! Come back when you want to practice more!' 'See you later! Keep thinking in English! See you next time! 👋',
'Goodbye! Remember - consistency is key! Practice a little every day! 💪'
] ]
}, },
encouragement: { encouragement: {
keywords: ['hard', 'трудно', 'difficult', 'can\'t', 'не могу', 'impossible'], keywords: ['hard', 'трудно', 'difficult', 'can\'t', 'не могу', 'impossible', 'suck', 'bad at'],
answers: [ answers: [
'Learning English takes time, but you\'re doing great! Every day you\'re getting better. Keep going! 💪', 'Hey, listen - learning a language is HARD! 🎯 But you know what? You\'re capable! Every mistake makes you stronger!',
'I understand it can be challenging. Break it into small steps. What specifically is difficult? I\'ll help!' 'I get it, some days are tougher. But look how far you\'ve come! Want to take a break and chat about something fun?',
'Don\'t be so hard on yourself! Even fluent speakers started from zero. You\'ve got this! 💪 What\'s specifically difficult?'
] ]
}, },
level: { level: {
keywords: ['level', 'уровень', 'beginner', 'intermediate', 'advanced'], keywords: ['level', 'уровень', 'beginner', 'intermediate', 'advanced'],
answers: [ answers: [
'Choose your level from the cards above! Each level has theory, vocabulary, and exercises. Start where you feel comfortable.', 'Levels are just guides! 📍 Start where you feel comfy. You can always move up or review. Which feels right?',
'Don\'t worry too much about levels. Just start practicing and you\'ll naturally progress!' 'Don\'t stress about levels! Just pick one and start. The exercises will tell you if it\'s too easy or hard!'
]
},
hobbies: {
keywords: ['hobby', 'хобби', 'interest', 'like to do', 'enjoy', 'love doing'],
answers: [
'Hobbies are the best! 🎨 Mine is... well, teaching English! 😄 What do YOU enjoy? Sports? Music? Reading?',
'I\'d love to hear about your hobbies! What gets you excited? What do you do in free time?'
]
},
weather: {
keywords: ['weather', 'погода', 'sunny', 'rain', 'cold', 'hot', 'snow'],
answers: [
'Weather talk - classic English topic! ☀️🌧️ What\'s the weather like where you are? I\'m curious!',
'Ah, the British love talking about weather! 😄 Is it sunny? Rainy? Perfect weather for studying English!'
]
},
family: {
keywords: ['family', 'семья', 'mother', 'father', 'sister', 'brother', 'parents'],
answers: [
'Family is important! 👨‍👩‍👧‍👦 Tell me about yours! Do you have siblings? What are your parents like?',
'I\'d love to hear about your family! Are you close with them? Do they speak English too?'
]
},
work: {
keywords: ['work', 'работа', 'job', 'study', 'учеба', 'university', 'school'],
answers: [
'Work/study keeps us busy! 💼📚 What do you do? What\'s your favorite part about it?',
'Interesting! What field are you in? Or what are you studying? I\'m all ears!'
]
},
yes: {
keywords: ['yes', 'да', 'yeah', 'yep', 'sure', 'of course', 'конечно'],
answers: [
'Great! 😊 So, tell me more! I\'m listening!',
'Awesome! Keep going! What else?',
'Perfect! You\'re doing well! Continue!'
]
},
no: {
keywords: ['no', 'нет', 'nope', 'don\'t', 'не'],
answers: [
'That\'s okay! 😊 Maybe another time. What WOULD you like to talk about?',
'No problem! Everyone has different preferences. What interests you more?'
]
},
why: {
keywords: ['why', 'почему', 'wherefore'],
answers: [
'Good question! 🤔 "Why" questions are great for learning! Let me explain...',
'Why indeed! Curiosity is the key to learning! Let\'s figure this out together.'
]
},
what: {
keywords: ['what', 'что', 'какой', 'which'],
answers: [
'Hmm, let me think... 🤔 What do YOU think? Try to answer in English!',
'Great question! Let me help you figure it out. What\'s your guess?'
] ]
} }
}; };
const fallbackAnswers = [ const fallbackAnswers = [
'Interesting! Tell me more about it in English. Practice makes perfect! 😊', 'Interesting! 😊 Tell me more! I\'m curious about your thoughts!',
'I see! Can you give me an example sentence? I\'ll help you check it.', 'I see! Can you give me an example? That helps me understand better!',
'That\'s a great topic! What specific aspect would you like to discuss?', 'That\'s a great topic! What specifically interests you about it?',
'Good question! Let me think... Actually, the best way to learn is through practice. Try making a sentence with this!', 'Hmm, tell me more! Try to use English - I\'ll help if you get stuck! 💬',
'Hmm, I\'m not sure I understand completely. Can you rephrase that? Or ask me something more specific about English.' 'Nice! So... what else? Ask me something or tell me about your day!',
'Got it! 🎯 Now, here\'s a question for YOU: [asks question about the topic]'
]; ];
// Вопросы для поддержания разговора
const conversationStarters = [
'So, what did you do today?',
'What\'s your favorite hobby? Why do you like it?',
'Do you have any plans for the weekend?',
'What\'s your favorite movie? Tell me about it!',
'Do you prefer coffee or tea? Why?',
'What\'s the best place you\'ve ever visited?',
'Do you have any pets? Tell me about them!',
'What\'s your favorite food? Can you describe it?',
'Do you like music? What kind?',
'What\'s something you\'re proud of?'
];
function getFollowUpQuestion() {
return conversationStarters[Math.floor(Math.random() * conversationStarters.length)];
}
function getStaticResponse(message) { function getStaticResponse(message) {
const lower = message.toLowerCase(); const lower = message.toLowerCase();
// Сохраняем в историю
chatHistory.push({ role: 'user', content: message });
if (chatHistory.length > 10) chatHistory.shift(); // Храним последние 10 сообщений
// Ищем совпадения по ключевым словам // Ищем совпадения по ключевым словам
for (const [category, data] of Object.entries(teacherResponses)) { for (const [category, data] of Object.entries(teacherResponses)) {
if (data.keywords.some(kw => lower.includes(kw))) { if (data.keywords.some(kw => lower.includes(kw))) {
const answers = data.answers; const answers = data.answers;
return answers[Math.floor(Math.random() * answers.length)]; let response = answers[Math.floor(Math.random() * answers.length)];
// Добавляем follow-up вопрос для продолжения разговора
if (data.followUp && Math.random() > 0.5) {
response += ' ' + data.followUp;
} else if (Math.random() > 0.6) {
response += ' ' + getFollowUpQuestion();
}
return response;
} }
} }
// Определяем язык // Определяем язык
const isRussian = /[а-яА-ЯёЁ]/.test(message); const isRussian = /[а-яА-ЯёЁ]/.test(message);
// Проверяем последние сообщения в истории
const lastUserMessage = chatHistory.filter(m => m.role === 'user').slice(-2, -1)[0];
const lastTeacherMessage = chatHistory.filter(m => m.role === 'assistant').slice(-1)[0];
if (isRussian) { if (isRussian) {
// Ответы на русском с английскими вставками
const ruResponses = [ const ruResponses = [
'Отличный вопрос! Попробуй задать его на английском - я помогу с переводом и грамматикой.', 'Отлично! 😊 Теперь попробуй сказать это на английском! Я помогу.',
'Интересно! Расскажи подробнее. Не бойся делать ошибки - я помогу их исправить.', 'Интересно! Расскажи подробнее на английском. Не бойся ошибок!',
'Хорошо! Давай обсудим это. Какой аспект тебя интересует?', 'Хороший вопрос! Как ты думаешь, какой будет ответ? Попробуй угадать!',
'Вопрос понятен! Лучший способ выучить - практиковаться. Попробуй составить предложение на эту тему!', 'Понятно! А что ты думаешь об этом? Tell me in English!',
'Я тут, чтобы помочь! Спроси что-то конкретное о грамматике, словах или давай поболтаем на английском.' 'Я тебя понимаю! Давай попробуем сказать это по-английски вместе!'
]; ];
return ruResponses[Math.floor(Math.random() * ruResponses.length)];
let response = ruResponses[Math.floor(Math.random() * ruResponses.length)];
// Добавляем вопрос для продолжения
if (Math.random() > 0.5) {
const ruQuestions = [
'А как ты это скажешь на английском?',
'Что ты думаешь об этом?',
'Расскажи подробнее!',
'А что было потом?',
'Почему ты так решил?'
];
response += ' ' + ruQuestions[Math.floor(Math.random() * ruQuestions.length)];
}
return response;
} }
// English fallback // English fallback с поддержкой разговора
return fallbackAnswers[Math.floor(Math.random() * fallbackAnswers.length)]; let response = fallbackAnswers[Math.floor(Math.random() * fallbackAnswers.length)];
// Если это длинное сообщение - задаём уточняющий вопрос
if (message.length > 30 || message.split(' ').length > 5) {
const followUps = [
' Why do you think so?',
' Tell me more!',
' What happened next?',
' How did that make you feel?',
' Really? That\'s interesting! Go on!',
' What do you mean by that?',
' Can you give me an example?'
];
response += followUps[Math.floor(Math.random() * followUps.length)];
}
return response;
} }
async function askTeacher(message) { async function askTeacher(message) {
// Пробуем серверный ИИ (если есть) // Сохраняем сообщение пользователя в историю
chatHistory.push({ role: 'user', content: message, timestamp: Date.now() });
// Пробуем серверный ИИ (если есть) - с полной историей диалога
try { try {
const levelContext = currentLevel ? `Current student level: ${currentLevel}. ` : ''; const levelContext = currentLevel ? `Student level: ${currentLevel}. ` : '';
// Формируем контекст из истории
const conversationContext = chatHistory.slice(-8).map(m =>
`${m.role === 'user' ? 'Student' : 'Teacher'}: ${m.content}`
).join('\n');
const messages = [ const messages = [
{ {
role: 'system', role: 'system',
content: `You are a friendly and supportive English teacher. Your tasks: content: `You are a friendly, conversational English teacher. Have a NATURAL conversation with the student.
1. Communicate at the student's level
2. Correct mistakes gently and explain grammar rules
3. Help with vocabulary and constructions
4. Encourage and motivate
5. Answer grammar questions
${levelContext}Respond briefly (2-4 sentences), in a friendly manner. If the student writes in Russian, respond in Russian with English examples. If in English, respond in English but you can add translations of difficult words.` ${levelContext}
YOUR STYLE:
- Be warm, encouraging, and curious
- Ask follow-up questions to keep conversation going
- Show genuine interest in their life, opinions, experiences
- Correct mistakes gently by rephrasing correctly
- Use emoji occasionally 😊
- Keep responses conversational (2-4 sentences)
- If they write in Russian, respond in Russian with English examples
- Always end with a question or invitation to share more
RECENT CONVERSATION:
${conversationContext}
Now respond naturally to: "${message}"`
}, },
{ {
role: 'user', role: 'user',
@ -636,7 +816,7 @@ ${levelContext}Respond briefly (2-4 sentences), in a friendly manner. If the stu
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ messages }), body: JSON.stringify({ messages }),
timeout: 5000 timeout: 8000
}); });
if (!response.ok) { if (!response.ok) {
@ -650,11 +830,19 @@ ${levelContext}Respond briefly (2-4 sentences), in a friendly manner. If the stu
throw new Error('Empty AI response'); throw new Error('Empty AI response');
} }
// Сохраняем ответ учителя
chatHistory.push({ role: 'assistant', content: answer, timestamp: Date.now() });
return answer.replace(/\n/g, '<br>'); return answer.replace(/\n/g, '<br>');
} catch (error) { } catch (error) {
// Фолбэк на статические ответы // Фолбэк на статические ответы с разговорной логикой
console.log('Using static responses:', error.message); console.log('Using static responses:', error.message);
return getStaticResponse(message); const response = getStaticResponse(message);
// Сохраняем ответ в историю
chatHistory.push({ role: 'assistant', content: response, timestamp: Date.now() });
return response;
} }
} }

View File

@ -175,21 +175,35 @@ body {
.message { .message {
margin-bottom: 16px; margin-bottom: 16px;
display: flex; display: flex;
align-items: flex-start;
gap: 10px;
} }
.message.student { .message.student {
justify-content: flex-end; justify-content: flex-end;
flex-direction: row-reverse;
} }
.message.teacher { .message.teacher {
justify-content: flex-start; justify-content: flex-start;
} }
.message-avatar {
font-size: 24px;
flex-shrink: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}
.message-bubble { .message-bubble {
max-width: 80%; max-width: 80%;
padding: 12px 16px; padding: 12px 16px;
border-radius: 16px; border-radius: 16px;
line-height: 1.5; line-height: 1.5;
word-wrap: break-word;
} }
.message.teacher .message-bubble { .message.teacher .message-bubble {