Files
tg_bot_language/bot/handlers/tasks.py
mamonov.ep 44f4f61fce Реализованы настройки пользователя и новые типы заданий
Создано:
- bot/handlers/settings.py - обработчик команды /settings

Реализовано:
 /settings - настройки пользователя
  - Выбор уровня английского (A1-C2)
  - Выбор языка интерфейса (RU/EN)
  - Интерактивные inline-кнопки

 Новый тип заданий - заполнение пропусков
  - AI генерирует предложение с пропуском
  - Показывает перевод для контекста
  - Проверка ответа через AI

 Смешанные задания
  - Случайное чередование типов (переводы + fill-in)
  - Более разнообразная практика

Изменено:
- services/ai_service.py - метод generate_fill_in_sentence()
- services/task_service.py - метод generate_mixed_tasks()
- services/user_service.py - методы обновления настроек
- bot/handlers/tasks.py - использование смешанных заданий
- main.py - регистрация роутера настроек

Теперь бот предлагает:
- Перевод EN→RU
- Перевод RU→EN
- Заполнение пропусков в предложениях

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 14:46:30 +03:00

234 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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_mixed_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"📝 <b>Задание {current_index + 1} из {len(tasks)}</b>\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"✅ <b>Правильно!</b>\n\n"
correct_count += 1
else:
result_text = f"❌ <b>Неправильно</b>\n\n"
result_text += f"Твой ответ: <i>{user_answer}</i>\n"
result_text += f"Правильный ответ: <b>{task['correct_answer']}</b>\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} <b>Задание завершено!</b>\n\n"
f"Правильных ответов: <b>{correct_count}</b> из {total_count}\n"
f"Точность: <b>{accuracy}%</b>\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"📊 <b>Твоя статистика</b>\n\n"
f"📚 Слов в словаре: <b>{stats['total_words']}</b>\n"
f"📖 Слов изучено: <b>{stats['reviewed_words']}</b>\n"
f"✍️ Заданий выполнено: <b>{stats['total_tasks']}</b>\n"
f"✅ Правильных ответов: <b>{stats['correct_tasks']}</b>\n"
f"🎯 Точность: <b>{stats['accuracy']}%</b>\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)