From 14a21dbcbe9c702fe172229a3386bd20c4f3ecc5 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Wed, 9 Sep 2026 11:03:37 +0000 Subject: [PATCH] v4: conversational teacher with context memory --- script.js | 308 +++++++++++++++++++++++++++++++++++++++++++----------- style.css | 14 +++ 2 files changed, 262 insertions(+), 60 deletions(-) diff --git a/script.js b/script.js index c66b628..99f2102 100644 --- a/script.js +++ b/script.js @@ -275,6 +275,7 @@ const levelsData = { // Текущее состояние let currentLevel = null; let chatSessionId = null; +let chatHistory = []; // История переписки для контекста // DOM элементы const levelsSection = document.getElementById('levels-section'); @@ -438,6 +439,12 @@ function toggleChat() { teacherChat.classList.toggle('hidden'); if (!teacherChat.classList.contains('hidden')) { 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'); chatInput.value = ''; + sendBtn.disabled = true; // Показываем индикатор набора showTypingIndicator(); try { + // Небольшая задержка для естественности + await new Promise(resolve => setTimeout(resolve, 600)); + // Получаем ответ от ИИ const response = await askTeacher(text); hideTypingIndicator(); addMessage(response, 'teacher'); } catch (error) { hideTypingIndicator(); - addMessage('Извини, я временно недоступен. Попробуй ещё раз!', 'teacher'); + addMessage('Hmm, I had trouble processing that. Try rephrasing? 😊', 'teacher'); console.error('Teacher error:', error); } + + sendBtn.disabled = false; + chatInput.focus(); } function addMessage(text, type) { const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}`; - messageDiv.innerHTML = `
${text}
`; + + // Добавляем аватарки + const avatar = type === 'teacher' ? '👨‍🏫' : '👤'; + messageDiv.innerHTML = ` +
${avatar}
+
${text}
+ `; chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } @@ -494,135 +514,295 @@ function hideTypingIndicator() { if (typing) typing.remove(); } -// Готовые ответы для статической версии (без сервера) +// Готовые ответы для статической версии (без сервера) - РАЗГОВОРНЫЙ РЕЖИМ const teacherResponses = { greetings: { - keywords: ['hello', 'hi', 'привет', 'здравствуй', 'good morning', 'good afternoon'], + keywords: ['hello', 'hi', 'привет', 'здравствуй', 'good morning', 'good afternoon', 'hey'], answers: [ - 'Hello! Great to see you! How can I help you with English today?', - 'Hi there! Ready to practice English? What would you like to work on?', - 'Hello! I\'m your English teacher. Ask me anything about grammar, vocabulary, or let\'s just chat!' - ] + 'Hello! Great to see you! 😊 How are you today? Tell me in English!', + 'Hi there! Ready to practice English? What have you been doing lately?', + '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: { - keywords: ['thank', 'спасибо', 'thanks'], + keywords: ['thank', 'спасибо', 'thanks', 'благодарю'], answers: [ - 'You\'re welcome! Keep up the good work! 👍', - 'Anytime! That\'s what I\'m here for! 😊', - 'No problem! Feel free to ask more questions!' + 'You\'re welcome! 😊 You\'re making great progress! Keep it up!', + 'Anytime! That\'s what I\'m here for! Do you have 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: { - keywords: ['help', 'помощь', 'помоги', 'explain', 'объясни'], + keywords: ['help', 'помощь', 'помоги', 'explain', 'объясни', 'assist'], answers: [ - 'I can help you with: grammar rules, vocabulary, pronunciation tips, or just conversation practice. What do you need?', - 'Sure! I can explain grammar, check your sentences, or suggest words. What topic interests you?' + 'I\'d love to help! 🎯 I can: check your sentences, explain grammar, teach new words, or just chat. What do you prefer?', + 'Of course! What\'s troubling you? Grammar? Vocabulary? Or maybe you want conversation practice?' ] }, grammar: { keywords: ['grammar', 'грамматик', 'rule', 'правило', 'tense', 'время'], 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?', - 'English grammar has 12 tenses, but you only need 5-6 for daily conversation. Which tense would you like to learn?' + 'Grammar time! 📚 Let me explain simply. Which tense confuses you? Present, Past, or Future?', + 'Great question! Grammar is like puzzle pieces. Once you get the pattern, it clicks! What specifically?' ] }, vocabulary: { - keywords: ['word', 'слово', 'vocabulary', 'translate', 'перевод', 'meaning'], + keywords: ['word', 'слово', 'vocabulary', 'translate', 'перевод', 'meaning', 'значит'], answers: [ - 'Great question! Building vocabulary takes time. Try learning 5-10 new words daily and use them in sentences. What word interests you?', - 'I can help with translations! Just tell me the word you want to know.' + 'Vocabulary is key! 🔑 Tell me the word you want to know, or I can teach you a new one!', + 'I love teaching new words! What topic interests you? Food? Travel? Work? Emotions?' ] }, practice: { - keywords: ['practice', 'практик', 'speak', 'говорить', 'chat', 'болтать'], + keywords: ['practice', 'практик', 'speak', 'говорить', 'chat', 'болтать', 'conversation'], answers: [ - 'Let\'s practice! Tell me about your day in English. Don\'t worry about mistakes - I\'ll help you correct them!', - 'Great! Let\'s have a conversation. What topics interest you? Hobbies, work, travel, movies?' + 'Awesome! Let\'s chat! 💬 Tell me - what did you do yesterday? Use past tense!', + 'Perfect! I love conversations! So... what are your hobbies? What do you enjoy doing?' ] }, mistake: { - keywords: ['mistake', 'ошибка', 'wrong', 'correct', 'правильно'], + keywords: ['mistake', 'ошибка', 'wrong', 'correct', 'правильно', 'right'], answers: [ - 'Mistakes are how we learn! Don\'t be afraid to make them. Even native speakers make mistakes!', - 'Good catch! Let me explain the rule so you remember it better.' + 'Mistakes are GOLD! ✨ They show you\'re trying! Tell me what you\'re unsure about.', + 'Don\'t worry about mistakes - they\'re part of learning! Even natives make them! Let\'s figure it out together.' ] }, goodbye: { - keywords: ['bye', 'goodbye', 'пока', 'до свидания', 'see you'], + keywords: ['bye', 'goodbye', 'пока', 'до свидания', 'see you', 'gotta go', 'must go'], answers: [ - 'Goodbye! Keep practicing and you\'ll improve fast! See you next time! 👋', - 'Bye! Great job today! Come back when you want to practice more!' + 'Bye! 🌟 You did great today! Come back soon for more practice!', + 'See you later! Keep thinking in English! See you next time! 👋', + 'Goodbye! Remember - consistency is key! Practice a little every day! 💪' ] }, encouragement: { - keywords: ['hard', 'трудно', 'difficult', 'can\'t', 'не могу', 'impossible'], + keywords: ['hard', 'трудно', 'difficult', 'can\'t', 'не могу', 'impossible', 'suck', 'bad at'], answers: [ - 'Learning English takes time, but you\'re doing great! Every day you\'re getting better. Keep going! 💪', - 'I understand it can be challenging. Break it into small steps. What specifically is difficult? I\'ll help!' + 'Hey, listen - learning a language is HARD! 🎯 But you know what? You\'re capable! Every mistake makes you stronger!', + '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: { keywords: ['level', 'уровень', 'beginner', 'intermediate', 'advanced'], answers: [ - 'Choose your level from the cards above! Each level has theory, vocabulary, and exercises. Start where you feel comfortable.', - 'Don\'t worry too much about levels. Just start practicing and you\'ll naturally progress!' + 'Levels are just guides! 📍 Start where you feel comfy. You can always move up or review. Which feels right?', + '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 = [ - 'Interesting! Tell me more about it in English. Practice makes perfect! 😊', - 'I see! Can you give me an example sentence? I\'ll help you check it.', - 'That\'s a great topic! What specific aspect would you like to discuss?', - 'Good question! Let me think... Actually, the best way to learn is through practice. Try making a sentence with this!', - 'Hmm, I\'m not sure I understand completely. Can you rephrase that? Or ask me something more specific about English.' + 'Interesting! 😊 Tell me more! I\'m curious about your thoughts!', + 'I see! Can you give me an example? That helps me understand better!', + 'That\'s a great topic! What specifically interests you about it?', + 'Hmm, tell me more! Try to use English - I\'ll help if you get stuck! 💬', + '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) { 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)) { if (data.keywords.some(kw => lower.includes(kw))) { 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 lastUserMessage = chatHistory.filter(m => m.role === 'user').slice(-2, -1)[0]; + const lastTeacherMessage = chatHistory.filter(m => m.role === 'assistant').slice(-1)[0]; + if (isRussian) { + // Ответы на русском с английскими вставками 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 - return fallbackAnswers[Math.floor(Math.random() * fallbackAnswers.length)]; + // English fallback с поддержкой разговора + 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) { - // Пробуем серверный ИИ (если есть) + // Сохраняем сообщение пользователя в историю + chatHistory.push({ role: 'user', content: message, timestamp: Date.now() }); + + // Пробуем серверный ИИ (если есть) - с полной историей диалога 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 = [ { role: 'system', - content: `You are a friendly and supportive English teacher. Your tasks: -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 + content: `You are a friendly, conversational English teacher. Have a NATURAL conversation with the student. -${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', @@ -636,7 +816,7 @@ ${levelContext}Respond briefly (2-4 sentences), in a friendly manner. If the stu 'Content-Type': 'application/json' }, body: JSON.stringify({ messages }), - timeout: 5000 + timeout: 8000 }); 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'); } + // Сохраняем ответ учителя + chatHistory.push({ role: 'assistant', content: answer, timestamp: Date.now() }); + return answer.replace(/\n/g, '
'); } catch (error) { - // Фолбэк на статические ответы + // Фолбэк на статические ответы с разговорной логикой 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; } } diff --git a/style.css b/style.css index d7c4569..fee54fb 100644 --- a/style.css +++ b/style.css @@ -175,21 +175,35 @@ body { .message { margin-bottom: 16px; display: flex; + align-items: flex-start; + gap: 10px; } .message.student { justify-content: flex-end; + flex-direction: row-reverse; } .message.teacher { 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 { max-width: 80%; padding: 12px 16px; border-radius: 16px; line-height: 1.5; + word-wrap: break-word; } .message.teacher .message-bubble {