diff --git a/bot/handlers/tasks.py b/bot/handlers/tasks.py
new file mode 100644
index 0000000..e900da9
--- /dev/null
+++ b/bot/handlers/tasks.py
@@ -0,0 +1,233 @@
+from aiogram import Router, F
+from aiogram.filters import Command
+from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery
+from aiogram.fsm.context import FSMContext
+from aiogram.fsm.state import State, StatesGroup
+
+from database.db import async_session_maker
+from services.user_service import UserService
+from services.task_service import TaskService
+from services.ai_service import ai_service
+
+router = Router()
+
+
+class TaskStates(StatesGroup):
+ """Состояния для прохождения заданий"""
+ doing_tasks = State()
+ waiting_for_answer = State()
+
+
+@router.message(Command("task"))
+async def cmd_task(message: Message, state: FSMContext):
+ """Обработчик команды /task"""
+ async with async_session_maker() as session:
+ user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
+
+ if not user:
+ await message.answer("Сначала запусти бота командой /start")
+ return
+
+ # Генерируем задания
+ tasks = await TaskService.generate_translation_tasks(session, user.id, count=5)
+
+ if not tasks:
+ await message.answer(
+ "📚 У тебя пока нет слов для практики!\n\n"
+ "Добавь несколько слов командой /add, а затем возвращайся."
+ )
+ return
+
+ # Сохраняем задания в состоянии
+ await state.update_data(
+ tasks=tasks,
+ current_task_index=0,
+ correct_count=0,
+ user_id=user.id
+ )
+ await state.set_state(TaskStates.doing_tasks)
+
+ # Показываем первое задание
+ await show_current_task(message, state)
+
+
+async def show_current_task(message: Message, state: FSMContext):
+ """Показать текущее задание"""
+ data = await state.get_data()
+ tasks = data.get('tasks', [])
+ current_index = data.get('current_task_index', 0)
+
+ if current_index >= len(tasks):
+ # Все задания выполнены
+ await finish_tasks(message, state)
+ return
+
+ task = tasks[current_index]
+
+ task_text = (
+ f"📝 Задание {current_index + 1} из {len(tasks)}\n\n"
+ f"{task['question']}\n"
+ )
+
+ if task.get('transcription'):
+ task_text += f"🔊 [{task['transcription']}]\n"
+
+ task_text += f"\n💡 Напиши свой ответ:"
+
+ await state.set_state(TaskStates.waiting_for_answer)
+ await message.answer(task_text)
+
+
+@router.message(TaskStates.waiting_for_answer)
+async def process_answer(message: Message, state: FSMContext):
+ """Обработка ответа пользователя"""
+ user_answer = message.text.strip()
+ data = await state.get_data()
+
+ tasks = data.get('tasks', [])
+ current_index = data.get('current_task_index', 0)
+ correct_count = data.get('correct_count', 0)
+ user_id = data.get('user_id')
+
+ task = tasks[current_index]
+
+ # Показываем индикатор проверки
+ checking_msg = await message.answer("⏳ Проверяю ответ...")
+
+ # Проверяем ответ через AI
+ check_result = await ai_service.check_answer(
+ question=task['question'],
+ correct_answer=task['correct_answer'],
+ user_answer=user_answer
+ )
+
+ await checking_msg.delete()
+
+ is_correct = check_result.get('is_correct', False)
+ feedback = check_result.get('feedback', '')
+
+ # Формируем ответ
+ if is_correct:
+ result_text = f"✅ Правильно!\n\n"
+ correct_count += 1
+ else:
+ result_text = f"❌ Неправильно\n\n"
+
+ result_text += f"Твой ответ: {user_answer}\n"
+ result_text += f"Правильный ответ: {task['correct_answer']}\n\n"
+
+ if feedback:
+ result_text += f"💬 {feedback}\n\n"
+
+ # Сохраняем результат в БД
+ async with async_session_maker() as session:
+ await TaskService.save_task_result(
+ session=session,
+ user_id=user_id,
+ task_type=task['type'],
+ content={
+ 'question': task['question'],
+ 'word': task['word']
+ },
+ user_answer=user_answer,
+ correct_answer=task['correct_answer'],
+ is_correct=is_correct,
+ ai_feedback=feedback
+ )
+
+ # Обновляем статистику слова
+ if 'word_id' in task:
+ await TaskService.update_word_statistics(
+ session=session,
+ word_id=task['word_id'],
+ is_correct=is_correct
+ )
+
+ # Обновляем счетчик
+ await state.update_data(
+ current_task_index=current_index + 1,
+ correct_count=correct_count
+ )
+
+ # Показываем результат и кнопку "Далее"
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text="➡️ Следующее задание", callback_data="next_task")]
+ ])
+
+ await message.answer(result_text, reply_markup=keyboard)
+
+
+@router.callback_query(F.data == "next_task", TaskStates.doing_tasks)
+async def next_task(callback: CallbackQuery, state: FSMContext):
+ """Переход к следующему заданию"""
+ await callback.message.delete()
+ await show_current_task(callback.message, state)
+ await callback.answer()
+
+
+async def finish_tasks(message: Message, state: FSMContext):
+ """Завершение всех заданий"""
+ data = await state.get_data()
+ tasks = data.get('tasks', [])
+ correct_count = data.get('correct_count', 0)
+ total_count = len(tasks)
+
+ accuracy = int((correct_count / total_count) * 100) if total_count > 0 else 0
+
+ # Определяем эмодзи на основе результата
+ if accuracy >= 90:
+ emoji = "🏆"
+ comment = "Отличный результат!"
+ elif accuracy >= 70:
+ emoji = "👍"
+ comment = "Хорошая работа!"
+ elif accuracy >= 50:
+ emoji = "📚"
+ comment = "Неплохо, продолжай практиковаться!"
+ else:
+ emoji = "💪"
+ comment = "Повтори эти слова еще раз!"
+
+ result_text = (
+ f"{emoji} Задание завершено!\n\n"
+ f"Правильных ответов: {correct_count} из {total_count}\n"
+ f"Точность: {accuracy}%\n\n"
+ f"{comment}\n\n"
+ f"Используй /task для нового задания\n"
+ f"Используй /stats для просмотра статистики"
+ )
+
+ await state.clear()
+ await message.answer(result_text)
+
+
+@router.message(Command("stats"))
+async def cmd_stats(message: Message):
+ """Обработчик команды /stats"""
+ async with async_session_maker() as session:
+ user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
+
+ if not user:
+ await message.answer("Сначала запусти бота командой /start")
+ return
+
+ # Получаем статистику
+ stats = await TaskService.get_user_stats(session, user.id)
+
+ stats_text = (
+ f"📊 Твоя статистика\n\n"
+ f"📚 Слов в словаре: {stats['total_words']}\n"
+ f"📖 Слов изучено: {stats['reviewed_words']}\n"
+ f"✍️ Заданий выполнено: {stats['total_tasks']}\n"
+ f"✅ Правильных ответов: {stats['correct_tasks']}\n"
+ f"🎯 Точность: {stats['accuracy']}%\n\n"
+ )
+
+ if stats['total_words'] == 0:
+ stats_text += "Добавь слова командой /add чтобы начать обучение!"
+ elif stats['total_tasks'] == 0:
+ stats_text += "Выполни первое задание командой /task!"
+ else:
+ stats_text += "Продолжай практиковаться! 💪"
+
+ await message.answer(stats_text)
diff --git a/main.py b/main.py
index 66580a8..a700358 100644
--- a/main.py
+++ b/main.py
@@ -6,7 +6,7 @@ from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from config.settings import settings
-from bot.handlers import start, vocabulary
+from bot.handlers import start, vocabulary, tasks
from database.db import init_db
@@ -28,6 +28,7 @@ async def main():
# Регистрация роутеров
dp.include_router(start.router)
dp.include_router(vocabulary.router)
+ dp.include_router(tasks.router)
# Инициализация базы данных
await init_db()
diff --git a/services/task_service.py b/services/task_service.py
new file mode 100644
index 0000000..79a690c
--- /dev/null
+++ b/services/task_service.py
@@ -0,0 +1,183 @@
+import random
+from datetime import datetime
+from typing import List, Dict, Optional
+from sqlalchemy import select
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from database.models import Task, Vocabulary
+
+
+class TaskService:
+ """Сервис для работы с заданиями"""
+
+ @staticmethod
+ async def generate_translation_tasks(
+ session: AsyncSession,
+ user_id: int,
+ count: int = 5
+ ) -> List[Dict]:
+ """
+ Генерация заданий на перевод слов
+
+ Args:
+ session: Сессия базы данных
+ user_id: ID пользователя
+ count: Количество заданий
+
+ Returns:
+ Список заданий
+ """
+ # Получаем слова пользователя
+ result = await session.execute(
+ select(Vocabulary)
+ .where(Vocabulary.user_id == user_id)
+ .order_by(Vocabulary.last_reviewed.asc().nullsfirst())
+ .limit(count * 2) # Берем больше, чтобы было из чего выбрать
+ )
+ words = list(result.scalars().all())
+
+ if not words:
+ return []
+
+ # Выбираем случайные слова
+ selected_words = random.sample(words, min(count, len(words)))
+
+ tasks = []
+ for word in selected_words:
+ # Случайно выбираем направление перевода
+ direction = random.choice(['en_to_ru', 'ru_to_en'])
+
+ if direction == 'en_to_ru':
+ task = {
+ 'type': 'translate_to_ru',
+ 'word_id': word.id,
+ 'question': f"Переведи слово: {word.word_original}",
+ 'word': word.word_original,
+ 'correct_answer': word.word_translation,
+ 'transcription': word.transcription
+ }
+ else:
+ task = {
+ 'type': 'translate_to_en',
+ 'word_id': word.id,
+ 'question': f"Переведи слово: {word.word_translation}",
+ 'word': word.word_translation,
+ 'correct_answer': word.word_original,
+ 'transcription': word.transcription
+ }
+
+ tasks.append(task)
+
+ return tasks
+
+ @staticmethod
+ async def save_task_result(
+ session: AsyncSession,
+ user_id: int,
+ task_type: str,
+ content: Dict,
+ user_answer: str,
+ correct_answer: str,
+ is_correct: bool,
+ ai_feedback: Optional[str] = None
+ ) -> Task:
+ """
+ Сохранение результата выполнения задания
+
+ Args:
+ session: Сессия базы данных
+ user_id: ID пользователя
+ task_type: Тип задания
+ content: Содержимое задания
+ user_answer: Ответ пользователя
+ correct_answer: Правильный ответ
+ is_correct: Правильность ответа
+ ai_feedback: Обратная связь от AI
+
+ Returns:
+ Сохраненное задание
+ """
+ task = Task(
+ user_id=user_id,
+ task_type=task_type,
+ content=content,
+ user_answer=user_answer,
+ correct_answer=correct_answer,
+ is_correct=is_correct,
+ ai_feedback=ai_feedback,
+ completed_at=datetime.utcnow()
+ )
+
+ session.add(task)
+ await session.commit()
+ await session.refresh(task)
+
+ return task
+
+ @staticmethod
+ async def update_word_statistics(
+ session: AsyncSession,
+ word_id: int,
+ is_correct: bool
+ ):
+ """
+ Обновление статистики слова
+
+ Args:
+ session: Сессия базы данных
+ word_id: ID слова
+ is_correct: Правильность ответа
+ """
+ result = await session.execute(
+ select(Vocabulary).where(Vocabulary.id == word_id)
+ )
+ word = result.scalar_one_or_none()
+
+ if word:
+ word.times_reviewed += 1
+ if is_correct:
+ word.correct_answers += 1
+ word.last_reviewed = datetime.utcnow()
+
+ await session.commit()
+
+ @staticmethod
+ async def get_user_stats(session: AsyncSession, user_id: int) -> Dict:
+ """
+ Получение статистики пользователя
+
+ Args:
+ session: Сессия базы данных
+ user_id: ID пользователя
+
+ Returns:
+ Статистика пользователя
+ """
+ # Количество слов
+ words_result = await session.execute(
+ select(Vocabulary).where(Vocabulary.user_id == user_id)
+ )
+ words = list(words_result.scalars().all())
+ total_words = len(words)
+
+ # Количество выполненных заданий
+ tasks_result = await session.execute(
+ select(Task).where(Task.user_id == user_id)
+ )
+ tasks = list(tasks_result.scalars().all())
+ total_tasks = len(tasks)
+
+ # Правильные ответы
+ correct_tasks = len([t for t in tasks if t.is_correct])
+ accuracy = int((correct_tasks / total_tasks * 100)) if total_tasks > 0 else 0
+
+ # Слова с повторениями
+ reviewed_words = len([w for w in words if w.times_reviewed > 0])
+
+ return {
+ 'total_words': total_words,
+ 'reviewed_words': reviewed_words,
+ 'total_tasks': total_tasks,
+ 'correct_tasks': correct_tasks,
+ 'accuracy': accuracy
+ }