Files
tg_bot_language/bot/handlers/start.py

274 lines
12 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 CommandStart, Command
from aiogram.types import (
Message,
InlineKeyboardMarkup,
InlineKeyboardButton,
CallbackQuery,
ReplyKeyboardMarkup,
KeyboardButton,
)
from aiogram.fsm.context import FSMContext
from database.db import async_session_maker
from services.user_service import UserService
router = Router()
# Тексты кнопок главного меню
BTN_ADD = " Добавить слово"
BTN_VOCAB = "📚 Словарь"
BTN_TASK = "🧠 Задание"
BTN_PRACTICE = "💬 Практика"
BTN_WORDS = "🎯 Тематические слова"
BTN_IMPORT = "📖 Импорт из текста"
BTN_STATS = "📊 Статистика"
BTN_SETTINGS = "⚙️ Настройки"
def main_menu_keyboard() -> ReplyKeyboardMarkup:
"""Клавиатура с основными командами (кнопки отправляют команды)."""
return ReplyKeyboardMarkup(
resize_keyboard=True,
keyboard=[
[
KeyboardButton(text=BTN_ADD),
KeyboardButton(text=BTN_VOCAB),
],
[
KeyboardButton(text=BTN_TASK),
KeyboardButton(text=BTN_PRACTICE),
],
[
KeyboardButton(text=BTN_WORDS),
KeyboardButton(text=BTN_IMPORT),
],
[
KeyboardButton(text=BTN_STATS),
KeyboardButton(text=BTN_SETTINGS),
],
],
)
@router.message(CommandStart())
async def cmd_start(message: Message, state: FSMContext):
"""Обработчик команды /start"""
async with async_session_maker() as session:
# Проверяем, существует ли пользователь
existing_user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
is_new_user = existing_user is None
# Создаём или получаем пользователя
user = await UserService.get_or_create_user(
session,
telegram_id=message.from_user.id,
username=message.from_user.username
)
if is_new_user:
# Новый пользователь
await message.answer(
f"👋 Привет, {message.from_user.first_name}!\n\n"
f"Я бот для изучения английского языка. Помогу тебе:\n"
f"📚 Пополнять словарный запас (ручное/тематическое/из текста)\n"
f"✍️ Выполнять интерактивные задания\n"
f"💬 Практиковать язык в диалоге с AI\n"
f"📊 Отслеживать свой прогресс\n\n"
f"<b>Команды:</b>\n"
f"• /add [слово] - добавить слово\n"
f"• /words [тема] - тематическая подборка\n"
f"• /import - импорт из текста\n"
f"• /vocabulary - мой словарь\n"
f"• /task - задания\n"
f"• /practice - диалог с AI\n"
f"• /stats - статистика\n"
f"• /settings - настройки\n"
f"• /reminder - напоминания\n"
f"• /help - полная справка",
reply_markup=main_menu_keyboard(),
)
# Предлагаем пройти тест уровня
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="📊 Пройти тест уровня", callback_data="offer_level_test")],
[InlineKeyboardButton(text="➡️ Пропустить", callback_data="skip_level_test")]
])
await message.answer(
"🎯 <b>Определим твой уровень?</b>\n\n"
"Короткий тест (7 вопросов) поможет подобрать задания под твой уровень.\n"
"Это займёт 2-3 минуты.\n\n"
"Или можешь пропустить и установить уровень вручную позже в /settings",
reply_markup=keyboard
)
else:
# Существующий пользователь
await message.answer(
f"С возвращением, {message.from_user.first_name}! 👋\n\n"
f"Готов продолжить обучение?\n\n"
f"<b>Быстрый доступ:</b>\n"
f"• /vocabulary - посмотреть словарь\n"
f"• /task - получить задание\n"
f"• /practice - практика диалога\n"
f"• /words [тема] - тематическая подборка\n"
f"• /stats - статистика\n"
f"• /help - все команды",
reply_markup=main_menu_keyboard(),
)
@router.message(Command("menu"))
async def cmd_menu(message: Message):
"""Показать клавиатуру с основными командами."""
await message.answer("Главное меню доступно ниже ⤵️", reply_markup=main_menu_keyboard())
# Обработчики кнопок главного меню (по тексту)
@router.message(F.text == BTN_ADD)
async def btn_add_pressed(message: Message, state: FSMContext):
from bot.handlers.vocabulary import AddWordStates
await message.answer(
"Отправь слово, которое хочешь добавить:\n"
"Например: <code>/add elephant</code>\n\n"
"Или просто отправь слово без команды!"
)
await state.set_state(AddWordStates.waiting_for_word)
@router.message(F.text == BTN_VOCAB)
async def btn_vocab_pressed(message: Message):
from bot.handlers.vocabulary import cmd_vocabulary
await cmd_vocabulary(message)
@router.message(F.text == BTN_TASK)
async def btn_task_pressed(message: Message, state: FSMContext):
from bot.handlers.tasks import cmd_task
await cmd_task(message, state)
@router.message(F.text == BTN_PRACTICE)
async def btn_practice_pressed(message: Message, state: FSMContext):
from bot.handlers.practice import cmd_practice
await cmd_practice(message, state)
@router.message(F.text == BTN_IMPORT)
async def btn_import_pressed(message: Message, state: FSMContext):
from bot.handlers.import_text import cmd_import
await cmd_import(message, state)
@router.message(F.text == BTN_STATS)
async def btn_stats_pressed(message: Message):
from bot.handlers.tasks import cmd_stats
await cmd_stats(message)
@router.message(F.text == BTN_SETTINGS)
async def btn_settings_pressed(message: Message):
from bot.handlers.settings import cmd_settings
await cmd_settings(message)
@router.message(F.text == BTN_WORDS)
async def btn_words_pressed(message: Message, state: FSMContext):
"""Подсказать про тематические слова и показать быстрые темы."""
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
text = (
"📚 <b>Тематические подборки слов</b>\n\n"
"Используй: <code>/words [тема]</code>\n\n"
"Популярные темы:"
)
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="✈️ Путешествия", callback_data="menu_theme_travel")],
[InlineKeyboardButton(text="🍔 Еда", callback_data="menu_theme_food")],
[InlineKeyboardButton(text="💼 Работа", callback_data="menu_theme_work")],
[InlineKeyboardButton(text="🌿 Природа", callback_data="menu_theme_nature")],
[InlineKeyboardButton(text="💻 Технологии", callback_data="menu_theme_technology")],
])
await message.answer(text, reply_markup=keyboard)
@router.callback_query(F.data.startswith("menu_theme_"))
async def pick_theme_from_menu(callback: CallbackQuery, state: FSMContext):
"""Сгенерировать слова по выбранной теме из меню и показать список."""
from database.db import async_session_maker
from services.user_service import UserService
from services.ai_service import ai_service
from bot.handlers.words import show_words_list, WordsStates
theme = callback.data.split("menu_theme_")[-1]
async with async_session_maker() as session:
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
if not user:
await callback.answer("Сначала /start", show_alert=True)
return
generating = await callback.message.answer(f"🔄 Генерирую подборку слов по теме '{theme}'...")
words = await ai_service.generate_thematic_words(theme=theme, level=user.level.value, count=10)
await generating.delete()
if not words:
await callback.message.answer("Не удалось сгенерировать подборку. Попробуй позже.")
await callback.answer()
return
# Сохраняем в состояние как в /words
await state.update_data(theme=theme, words=words, user_id=user.id, level=user.level.name)
await state.set_state(WordsStates.viewing_words)
await show_words_list(callback.message, words, theme)
await callback.answer()
@router.message(Command("help"))
async def cmd_help(message: Message):
"""Обработчик команды /help"""
await message.answer(
"<b>📖 Справка по командам:</b>\n\n"
"<b>Управление словарём:</b>\n"
"• /add [слово] - добавить слово в словарь\n"
"• /vocabulary - просмотр словаря\n"
"• /words [тема] - тематическая подборка слов\n"
"• /import - импортировать слова из текста\n\n"
"<b>Обучение:</b>\n"
"• /task - задание (перевод, заполнение пропусков)\n"
"• /practice - диалог с ИИ (6 сценариев)\n"
"• /level_test - тест определения уровня\n\n"
"<b>Статистика:</b>\n"
"• /stats - твой прогресс\n\n"
"<b>Настройки:</b>\n"
"• /settings - уровень и язык\n"
"• /reminder - ежедневные напоминания\n\n"
"💡 Ты также можешь просто отправить мне слово, и я предложу добавить его в словарь!"
)
@router.callback_query(F.data == "offer_level_test")
async def offer_level_test_callback(callback: CallbackQuery, state: FSMContext):
"""Начать тест уровня из приветствия"""
from bot.handlers.level_test import start_level_test
await callback.message.delete()
await start_level_test(callback.message, state)
await callback.answer()
@router.callback_query(F.data == "skip_level_test")
async def skip_level_test_callback(callback: CallbackQuery):
"""Пропустить тест уровня"""
await callback.message.edit_text(
"✅ Хорошо!\n\n"
"Ты можешь пройти тест позже командой /level_test\n"
"или установить уровень вручную в /settings\n\n"
"Давай начнём! Попробуй:\n"
"• /words travel - тематическая подборка\n"
"• /practice - диалог с AI\n"
"• /add hello - добавить слово"
)
await callback.answer()