851 lines
35 KiB
JavaScript
851 lines
35 KiB
JavaScript
// Данные по уровням
|
||
const levelsData = {
|
||
A1: {
|
||
title: "A1 - Beginner (Начинающий)",
|
||
theory: [
|
||
{
|
||
title: "Глагол to be (быть)",
|
||
content: "Глагол to be используется в настоящем времени: I am, You/We/They are, He/She/It is.",
|
||
example: "I am a student. (Я студент) / She is a teacher. (Она учитель)"
|
||
},
|
||
{
|
||
title: "Артикли a/an/the",
|
||
content: "Неопределённый артикль a/an используется с исчисляемыми существительными в единственном числе. Определённый артикль the - когда говорим о чём-то конкретном.",
|
||
example: "a book (какая-то книга) / the book (конкретная книга)"
|
||
},
|
||
{
|
||
title: "Множественное число",
|
||
content: "Большинство существительных образуют множественное число добавлением -s. Исключения: man→men, woman→women, child→children.",
|
||
example: "cat→cats, box→boxes, person→people"
|
||
},
|
||
{
|
||
title: "Present Simple",
|
||
content: "Настоящее простое время для регулярных действий. Для he/she/it добавляем -s к глаголу.",
|
||
example: "I work every day. / He works every day."
|
||
}
|
||
],
|
||
vocabulary: [
|
||
{ en: "hello", ru: "привет" }, { en: "goodbye", ru: "до свидания" },
|
||
{ en: "please", ru: "пожалуйста" }, { en: "thank you", ru: "спасибо" },
|
||
{ en: "yes", ru: "да" }, { en: "no", ru: "нет" },
|
||
{ en: "I", ru: "я" }, { en: "you", ru: "ты, вы" },
|
||
{ en: "he", ru: "он" }, { en: "she", ru: "она" },
|
||
{ en: "we", ru: "мы" }, { en: "they", ru: "они" },
|
||
{ en: "family", ru: "семья" }, { en: "friend", ru: "друг" },
|
||
{ en: "house", ru: "дом" }, { en: "water", ru: "вода" },
|
||
{ en: "food", ru: "еда" }, { en: "time", ru: "время" },
|
||
{ en: "day", ru: "день" }, { en: "night", ru: "ночь" }
|
||
],
|
||
exercises: [
|
||
{
|
||
question: "Выберите правильную форму: I ___ a student.",
|
||
options: ["am", "is", "are"],
|
||
correct: 0
|
||
},
|
||
{
|
||
question: "Выберите правильный перевод: 'Она учитель'",
|
||
options: ["She am a teacher", "She is a teacher", "She are a teacher"],
|
||
correct: 1
|
||
},
|
||
{
|
||
question: "Множественное число от 'cat':",
|
||
options: ["cat", "cats", "cates"],
|
||
correct: 1
|
||
}
|
||
]
|
||
},
|
||
A2: {
|
||
title: "A2 - Elementary (Элементарный)",
|
||
theory: [
|
||
{
|
||
title: "Present Continuous",
|
||
content: "Настоящее длительное время: am/is/are + глагол-ing. Используется для действий в момент речи.",
|
||
example: "I am reading now. (Я читаю сейчас)"
|
||
},
|
||
{
|
||
title: "Past Simple",
|
||
content: "Прошедшее простое время. Правильные глаголы: +ed, неправильные - вторая форма.",
|
||
example: "I worked yesterday. / I went to school."
|
||
},
|
||
{
|
||
title: "Модальные глаголы",
|
||
content: "can (мочь), must (должен), should (следует). После модального глагола инфинитив без to.",
|
||
example: "I can swim. / You must go. / He should study."
|
||
},
|
||
{
|
||
title: "Степени сравнения прилагательных",
|
||
content: "Короткие: -er, -est. Длинные: more, the most. Исключения: good→better→the best.",
|
||
example: "big→bigger→the biggest / beautiful→more beautiful→the most beautiful"
|
||
}
|
||
],
|
||
vocabulary: [
|
||
{ en: "yesterday", ru: "вчера" }, { en: "tomorrow", ru: "завтра" },
|
||
{ en: "today", ru: "сегодня" }, { en: "morning", ru: "утро" },
|
||
{ en: "evening", ru: "вечер" }, { en: "week", ru: "неделя" },
|
||
{ en: "month", ru: "месяц" }, { en: "year", ru: "год" },
|
||
{ en: "work", ru: "работа" }, { en: "study", ru: "учиться" },
|
||
{ en: "learn", ru: "изучать" }, { en: "speak", ru: "говорить" },
|
||
{ en: "understand", ru: "понимать" }, { en: "know", ru: "знать" },
|
||
{ en: "think", ru: "думать" }, { en: "want", ru: "хотеть" },
|
||
{ en: "need", ru: "нуждаться" }, { en: "like", ru: "нравиться" },
|
||
{ en: "love", ru: "любить" }, { en: "hate", ru: "ненавидеть" }
|
||
],
|
||
exercises: [
|
||
{
|
||
question: "Выберите правильную форму: She ___ now.",
|
||
options: ["reads", "is reading", "read"],
|
||
correct: 1
|
||
},
|
||
{
|
||
question: "Past Simple от 'go':",
|
||
options: ["goed", "gone", "went"],
|
||
correct: 2
|
||
},
|
||
{
|
||
question: "'Более красивый' по-английски:",
|
||
options: ["beautifuler", "more beautiful", "beautifulest"],
|
||
correct: 1
|
||
}
|
||
]
|
||
},
|
||
B1: {
|
||
title: "B1 - Intermediate (Средний)",
|
||
theory: [
|
||
{
|
||
title: "Present Perfect",
|
||
content: "have/has + V3 (третья форма). Действие завершилось к настоящему моменту или важен результат.",
|
||
example: "I have finished my work. (Я закончил работу)"
|
||
},
|
||
{
|
||
title: "Future Simple",
|
||
content: "will + инфинитив без to. Используется для будущих действий, обещаний, предсказаний.",
|
||
example: "I will call you tomorrow."
|
||
},
|
||
{
|
||
title: "Условные предложения 1 типа",
|
||
content: "If + Present Simple, will + инфинитив. Реальные условия в будущем.",
|
||
example: "If it rains, I will stay at home."
|
||
},
|
||
{
|
||
title: "Пассивный залог",
|
||
content: "be + V3 (третья форма). Подлежащее подвергается действию.",
|
||
example: "The book was written by Tolstoy."
|
||
}
|
||
],
|
||
vocabulary: [
|
||
{ en: "experience", ru: "опыт" }, { en: "opportunity", ru: "возможность" },
|
||
{ en: "decision", ru: "решение" }, { en: "development", ru: "развитие" },
|
||
{ en: "information", ru: "информация" }, { en: "knowledge", ru: "знание" },
|
||
{ en: "ability", ru: "способность" }, { en: "difference", ru: "разница" },
|
||
{ en: "important", ru: "важный" }, { en: "necessary", ru: "необходимый" },
|
||
{ en: "possible", ru: "возможный" }, { en: "available", ru: "доступный" },
|
||
{ en: "recently", ru: "недавно" }, { en: "probably", ru: "вероятно" },
|
||
{ en: "actually", ru: "на самом деле" }, { en: "especially", ru: "особенно" },
|
||
{ en: "however", ru: "однако" }, { en: "therefore", ru: "поэтому" },
|
||
{ en: "although", ru: "хотя" }, { en: "because", ru: "потому что" }
|
||
],
|
||
exercises: [
|
||
{
|
||
question: "Выберите: I ___ already ___ this film.",
|
||
options: ["did / see", "have / seen", "will / see"],
|
||
correct: 1
|
||
},
|
||
{
|
||
question: "If you ___ hard, you will pass the exam.",
|
||
options: ["study", "will study", "studied"],
|
||
correct: 0
|
||
},
|
||
{
|
||
question: "Пассивный залог: 'The letter ___ yesterday.'",
|
||
options: ["sent", "was sent", "is sent"],
|
||
correct: 1
|
||
}
|
||
]
|
||
},
|
||
B2: {
|
||
title: "B2 - Upper-Intermediate (Выше среднего)",
|
||
theory: [
|
||
{
|
||
title: "Present Perfect Continuous",
|
||
content: "have/has been + глагол-ing. Действие началось в прошлом и продолжается до сих пор.",
|
||
example: "I have been studying English for 3 years."
|
||
},
|
||
{
|
||
title: "Условные предложения 2 типа",
|
||
content: "If + Past Simple, would + инфинитив. Маловероятные или нереальные условия.",
|
||
example: "If I had money, I would buy a car."
|
||
},
|
||
{
|
||
title: "Косвенная речь",
|
||
content: "При передаче чужих слов времена сдвигаются в прошлое.",
|
||
example: "He said that he was tired."
|
||
},
|
||
{
|
||
title: "Модальные глаголы совершенного вида",
|
||
content: "must have done (должно быть сделал), should have done (следовало сделать), could have done (мог бы сделать).",
|
||
example: "You should have told me earlier."
|
||
}
|
||
],
|
||
vocabulary: [
|
||
{ en: "accomplish", ru: "достигать" }, { en: "significant", ru: "значительный" },
|
||
{ en: "consequently", ru: "следовательно" }, { en: "furthermore", ru: "более того" },
|
||
{ en: "nevertheless", ru: "тем не менее" }, { en: "meanwhile", ru: "между тем" },
|
||
{ en: "sufficient", ru: "достаточный" }, { en: "appropriate", ru: "подходящий" },
|
||
{ en: "considerable", ru: "значительный" }, { en: "potential", ru: "потенциал" },
|
||
{ en: "challenge", ru: "вызов, сложность" }, { en: "approach", ru: "подход" },
|
||
{ en: "concept", ru: "концепция" }, { en: "context", ru: "контекст" },
|
||
{ en: "evidence", ru: "доказательство" }, { en: "factor", ru: "фактор" },
|
||
{ en: "aspect", ru: "аспект" }, { en: "issue", ru: "вопрос, проблема" },
|
||
{ en: "trend", ru: "тенденция" }, { en: "strategy", ru: "стратегия" }
|
||
],
|
||
exercises: [
|
||
{
|
||
question: "I ___ for 2 hours when you called.",
|
||
options: ["studied", "have been studying", "had been studying"],
|
||
correct: 2
|
||
},
|
||
{
|
||
question: "If I ___ you, I would accept the offer.",
|
||
options: ["am", "were", "would be"],
|
||
correct: 1
|
||
},
|
||
{
|
||
question: "He said he ___ busy.",
|
||
options: ["is", "was", "will be"],
|
||
correct: 1
|
||
}
|
||
]
|
||
},
|
||
C1: {
|
||
title: "C1 - Advanced (Продвинутый)",
|
||
theory: [
|
||
{
|
||
title: "Inversion",
|
||
content: "Инверсия для эмфазы: Never have I seen, Not only did he... Используется в формальной речи.",
|
||
example: "Never have I been so surprised!"
|
||
},
|
||
{
|
||
title: "Mixed Conditionals",
|
||
content: "Смешанные условные предложения: комбинация разных времён в условии и результате.",
|
||
example: "If I had studied harder, I would be at a better university now."
|
||
},
|
||
{
|
||
title: "Subjunctive Mood",
|
||
content: "Сослагательное наклонение: I suggest that he go, It's important that she be informed.",
|
||
example: "I recommend that he see a doctor."
|
||
},
|
||
{
|
||
title: "Cleft Sentences",
|
||
content: "Расщеплённые предложения для выделения: What I need is... / It was John who...",
|
||
example: "What I really want is to travel the world."
|
||
}
|
||
],
|
||
vocabulary: [
|
||
{ en: "unprecedented", ru: "беспрецедентный" }, { en: "comprehensive", ru: "всесторонний" },
|
||
{ en: "sophisticated", ru: "сложный, изощрённый" }, { en: "simultaneously", ru: "одновременно" },
|
||
{ en: "subsequently", ru: "впоследствии" }, { en: "inevitably", ru: "неизбежно" },
|
||
{ en: "predominantly", ru: "преимущественно" }, { en: "notwithstanding", ru: "несмотря на" },
|
||
{ en: "implementation", ru: "осуществление" }, { en: "sustainability", ru: "устойчивость" },
|
||
{ en: "methodology", ru: "методология" }, { en: "infrastructure", ru: "инфраструктура" },
|
||
{ en: "phenomenon", ru: "феномен" }, { en: "hypothesis", ru: "гипотеза" },
|
||
{ en: "paradigm", ru: "парадигма" }, { en: "implication", ru: "последствие" },
|
||
{ en: "credibility", ru: "достоверность" }, { en: "authenticity", ru: "подлинность" },
|
||
{ en: "spontaneous", ru: "спонтанный" }, { en: "meticulous", ru: "скрупулёзный" }
|
||
],
|
||
exercises: [
|
||
{
|
||
question: "Выберите правильную инверсию: '___ such a beautiful place.'",
|
||
options: ["Never I have seen", "Never have I seen", "I have never seen"],
|
||
correct: 1
|
||
},
|
||
{
|
||
question: "Mixed Conditional: 'If she had taken the job, she ___ in London now.'",
|
||
options: ["would live", "will live", "would have lived"],
|
||
correct: 0
|
||
},
|
||
{
|
||
question: "Subjunctive: 'I suggest that he ___ immediately.'",
|
||
options: ["leaves", "leave", "will leave"],
|
||
correct: 1
|
||
}
|
||
]
|
||
}
|
||
};
|
||
|
||
// Текущее состояние
|
||
let currentLevel = null;
|
||
let chatSessionId = null;
|
||
let chatHistory = []; // История переписки для контекста
|
||
|
||
// DOM элементы
|
||
const levelsSection = document.getElementById('levels-section');
|
||
const levelContent = document.getElementById('level-content');
|
||
const levelTitle = document.getElementById('level-title');
|
||
const backBtn = document.getElementById('back-btn');
|
||
const tabBtns = document.querySelectorAll('.tab-btn');
|
||
const tabContents = document.querySelectorAll('.tab-content');
|
||
const vocabSearch = document.getElementById('vocab-search');
|
||
|
||
// Учитель
|
||
const teacherBtn = document.getElementById('teacher-btn');
|
||
const teacherChat = document.getElementById('teacher-chat');
|
||
const closeChat = document.getElementById('close-chat');
|
||
const chatMessages = document.getElementById('chat-messages');
|
||
const chatInput = document.getElementById('chat-input');
|
||
const sendBtn = document.getElementById('send-btn');
|
||
|
||
// Инициализация
|
||
function init() {
|
||
// Клик по уровням
|
||
document.querySelectorAll('.level-card').forEach(card => {
|
||
card.addEventListener('click', () => {
|
||
const level = card.dataset.level;
|
||
showLevel(level);
|
||
});
|
||
});
|
||
|
||
// Назад
|
||
backBtn.addEventListener('click', () => {
|
||
levelContent.classList.add('hidden');
|
||
levelsSection.classList.remove('hidden');
|
||
currentLevel = null;
|
||
});
|
||
|
||
// Табы
|
||
tabBtns.forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const tab = btn.dataset.tab;
|
||
switchTab(tab);
|
||
});
|
||
});
|
||
|
||
// Поиск слов
|
||
vocabSearch.addEventListener('input', (e) => {
|
||
filterVocabulary(e.target.value);
|
||
});
|
||
|
||
// Учитель
|
||
teacherBtn.addEventListener('click', toggleChat);
|
||
closeChat.addEventListener('click', toggleChat);
|
||
sendBtn.addEventListener('click', sendMessage);
|
||
chatInput.addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') sendMessage();
|
||
});
|
||
}
|
||
|
||
// Показать уровень
|
||
function showLevel(level) {
|
||
currentLevel = level;
|
||
const data = levelsData[level];
|
||
|
||
levelTitle.textContent = data.title;
|
||
|
||
// Теория
|
||
const theoryContent = document.getElementById('theory-content');
|
||
theoryContent.innerHTML = data.theory.map(t => `
|
||
<div class="theory-card">
|
||
<h4>${t.title}</h4>
|
||
<p>${t.content}</p>
|
||
<div class="example">💡 ${t.example}</div>
|
||
</div>
|
||
`).join('');
|
||
|
||
// Словарь
|
||
const vocabContent = document.getElementById('vocab-content');
|
||
renderVocabulary(data.vocabulary);
|
||
|
||
// Упражнения
|
||
const practiceContent = document.getElementById('practice-content');
|
||
practiceContent.innerHTML = data.exercises.map((ex, idx) => `
|
||
<div class="exercise-card">
|
||
<div class="exercise-question">${idx + 1}. ${ex.question}</div>
|
||
<div class="exercise-options">
|
||
${ex.options.map((opt, i) => `
|
||
<div class="exercise-option" data-exercise="${idx}" data-option="${i}">${opt}</div>
|
||
`).join('')}
|
||
</div>
|
||
<div class="exercise-feedback" id="feedback-${idx}"></div>
|
||
</div>
|
||
`).join('');
|
||
|
||
// Обработчики упражнений
|
||
document.querySelectorAll('.exercise-option').forEach(opt => {
|
||
opt.addEventListener('click', handleExerciseClick);
|
||
});
|
||
|
||
// Переключение
|
||
levelsSection.classList.add('hidden');
|
||
levelContent.classList.remove('hidden');
|
||
}
|
||
|
||
// Переключение таба
|
||
function switchTab(tab) {
|
||
tabBtns.forEach(btn => btn.classList.remove('active'));
|
||
tabContents.forEach(content => content.classList.remove('active'));
|
||
|
||
document.querySelector(`[data-tab="${tab}"]`).classList.add('active');
|
||
document.getElementById(tab).classList.add('active');
|
||
}
|
||
|
||
// Рендер словаря
|
||
function renderVocabulary(vocab) {
|
||
const vocabContent = document.getElementById('vocab-content');
|
||
vocabContent.innerHTML = vocab.map(w => `
|
||
<div class="vocab-item">
|
||
<span class="word-en">${w.en}</span>
|
||
<span class="word-ru">${w.ru}</span>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// Фильтр словаря
|
||
function filterVocabulary(query) {
|
||
const data = levelsData[currentLevel];
|
||
const filtered = data.vocabulary.filter(w =>
|
||
w.en.toLowerCase().includes(query.toLowerCase()) ||
|
||
w.ru.toLowerCase().includes(query.toLowerCase())
|
||
);
|
||
renderVocabulary(filtered);
|
||
}
|
||
|
||
// Обработка упражнения
|
||
function handleExerciseClick(e) {
|
||
const option = e.target;
|
||
const exerciseIdx = parseInt(option.dataset.exercise);
|
||
const selectedOption = parseInt(option.dataset.option);
|
||
const exercise = levelsData[currentLevel].exercises[exerciseIdx];
|
||
const feedback = document.getElementById(`feedback-${exerciseIdx}`);
|
||
|
||
// Блокируем повторные клики
|
||
const parent = option.parentElement;
|
||
if (parent.querySelector('.correct') || parent.querySelector('.incorrect')) return;
|
||
|
||
// Проверка
|
||
if (selectedOption === exercise.correct) {
|
||
option.classList.add('correct');
|
||
feedback.textContent = '✅ Правильно!';
|
||
feedback.className = 'exercise-feedback correct';
|
||
} else {
|
||
option.classList.add('incorrect');
|
||
const correctOption = parent.children[exercise.correct];
|
||
correctOption.classList.add('correct');
|
||
feedback.textContent = '❌ Неправильно. Правильный ответ выделен зелёным.';
|
||
feedback.className = 'exercise-feedback incorrect';
|
||
}
|
||
}
|
||
|
||
// Учитель - функции
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
async function sendMessage() {
|
||
const text = chatInput.value.trim();
|
||
if (!text) return;
|
||
|
||
// Добавляем сообщение студента
|
||
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('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}`;
|
||
|
||
// Добавляем аватарки
|
||
const avatar = type === 'teacher' ? '👨🏫' : '👤';
|
||
messageDiv.innerHTML = `
|
||
<div class="message-avatar">${avatar}</div>
|
||
<div class="message-bubble">${text}</div>
|
||
`;
|
||
chatMessages.appendChild(messageDiv);
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
}
|
||
|
||
function showTypingIndicator() {
|
||
const typing = document.createElement('div');
|
||
typing.className = 'message teacher';
|
||
typing.id = 'typing-indicator';
|
||
typing.innerHTML = `
|
||
<div class="message-bubble">
|
||
<div class="typing-indicator">
|
||
<div class="typing-dot"></div>
|
||
<div class="typing-dot"></div>
|
||
<div class="typing-dot"></div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
chatMessages.appendChild(typing);
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
}
|
||
|
||
function hideTypingIndicator() {
|
||
const typing = document.getElementById('typing-indicator');
|
||
if (typing) typing.remove();
|
||
}
|
||
|
||
// Готовые ответы для статической версии (без сервера) - РАЗГОВОРНЫЙ РЕЖИМ
|
||
const teacherResponses = {
|
||
greetings: {
|
||
keywords: ['hello', 'hi', 'привет', 'здравствуй', 'good morning', 'good afternoon', 'hey'],
|
||
answers: [
|
||
'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', 'благодарю'],
|
||
answers: [
|
||
'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', 'объясни', 'assist'],
|
||
answers: [
|
||
'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 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', 'значит'],
|
||
answers: [
|
||
'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', 'болтать', 'conversation'],
|
||
answers: [
|
||
'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', 'правильно', 'right'],
|
||
answers: [
|
||
'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', 'gotta go', 'must go'],
|
||
answers: [
|
||
'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', 'suck', 'bad at'],
|
||
answers: [
|
||
'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: [
|
||
'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! 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;
|
||
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!',
|
||
'Я тебя понимаю! Давай попробуем сказать это по-английски вместе!'
|
||
];
|
||
|
||
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 с поддержкой разговора
|
||
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 ? `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, conversational English teacher. Have a NATURAL conversation with the student.
|
||
|
||
${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',
|
||
content: message
|
||
}
|
||
];
|
||
|
||
const response = await fetch('/api/ai', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({ messages }),
|
||
timeout: 8000
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error('AI error: ' + response.status);
|
||
}
|
||
|
||
const data = await response.json();
|
||
const answer = data.choices?.[0]?.message?.content;
|
||
|
||
if (!answer) {
|
||
throw new Error('Empty AI response');
|
||
}
|
||
|
||
// Сохраняем ответ учителя
|
||
chatHistory.push({ role: 'assistant', content: answer, timestamp: Date.now() });
|
||
|
||
return answer.replace(/\n/g, '<br>');
|
||
} catch (error) {
|
||
// Фолбэк на статические ответы с разговорной логикой
|
||
console.log('Using static responses:', error.message);
|
||
const response = getStaticResponse(message);
|
||
|
||
// Сохраняем ответ в историю
|
||
chatHistory.push({ role: 'assistant', content: response, timestamp: Date.now() });
|
||
|
||
return response;
|
||
}
|
||
}
|
||
|
||
// Запуск
|
||
init();
|