Новые команды: - /words [тема] - AI-генерация тематических подборок слов (10 слов по теме с учётом уровня) - /import - извлечение до 15 ключевых слов из текста (книги, статьи, песни) - /practice - диалоговая практика с AI в 6 сценариях (ресторан, магазин, путешествие, работа, врач, общение) - /reminder - настройка ежедневных напоминаний по расписанию - /level_test - тест из 7 вопросов для определения уровня английского (A1-C2) Основные изменения: - AI сервис: добавлены методы generate_thematic_words, extract_words_from_text, start_conversation, continue_conversation, generate_level_test - Диалоговая практика: исправление ошибок в реальном времени, подсказки, перевод реплик - Напоминания: APScheduler для ежедневной отправки напоминаний в выбранное время - Тест уровня: автоматическое определение уровня при регистрации, можно пропустить - База данных: добавлены поля reminders_enabled, last_reminder_sent - Vocabulary service: метод get_word_by_original для проверки дубликатов - Зависимости: apscheduler==3.10.4 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
173 lines
6.5 KiB
Python
173 lines
6.5 KiB
Python
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
|
||
|
||
router = Router()
|
||
|
||
|
||
class ReminderStates(StatesGroup):
|
||
"""Состояния для настройки напоминаний"""
|
||
waiting_for_time = State()
|
||
|
||
|
||
@router.message(Command("reminder"))
|
||
async def cmd_reminder(message: Message):
|
||
"""Обработчик команды /reminder"""
|
||
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
|
||
|
||
# Формируем текст
|
||
status = "✅ Включены" if user.reminders_enabled else "❌ Выключены"
|
||
time_text = user.daily_task_time if user.daily_task_time else "Не установлено"
|
||
|
||
text = (
|
||
f"⏰ <b>Напоминания</b>\n\n"
|
||
f"Статус: {status}\n"
|
||
f"Время: {time_text} UTC\n\n"
|
||
f"Напоминания помогут не забывать о ежедневной практике.\n"
|
||
f"Бот будет присылать сообщение в выбранное время каждый день."
|
||
)
|
||
|
||
# Создаем кнопки
|
||
keyboard = []
|
||
|
||
if user.reminders_enabled:
|
||
keyboard.append([
|
||
InlineKeyboardButton(text="❌ Выключить", callback_data="reminder_disable")
|
||
])
|
||
else:
|
||
keyboard.append([
|
||
InlineKeyboardButton(text="✅ Включить", callback_data="reminder_enable")
|
||
])
|
||
|
||
keyboard.append([
|
||
InlineKeyboardButton(text="⏰ Изменить время", callback_data="reminder_set_time")
|
||
])
|
||
|
||
reply_markup = InlineKeyboardMarkup(inline_keyboard=keyboard)
|
||
await message.answer(text, reply_markup=reply_markup)
|
||
|
||
|
||
@router.callback_query(F.data == "reminder_enable")
|
||
async def enable_reminders(callback: CallbackQuery):
|
||
"""Включить напоминания"""
|
||
async with async_session_maker() as session:
|
||
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
|
||
|
||
if not user.daily_task_time:
|
||
await callback.answer(
|
||
"Сначала установи время напоминаний!",
|
||
show_alert=True
|
||
)
|
||
return
|
||
|
||
user.reminders_enabled = True
|
||
await session.commit()
|
||
|
||
await callback.answer("✅ Напоминания включены!")
|
||
await callback.message.edit_text(
|
||
f"✅ <b>Напоминания включены!</b>\n\n"
|
||
f"Время: {user.daily_task_time} UTC\n\n"
|
||
f"Ты будешь получать ежедневные напоминания о практике."
|
||
)
|
||
|
||
|
||
@router.callback_query(F.data == "reminder_disable")
|
||
async def disable_reminders(callback: CallbackQuery):
|
||
"""Выключить напоминания"""
|
||
async with async_session_maker() as session:
|
||
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
|
||
|
||
user.reminders_enabled = False
|
||
await session.commit()
|
||
|
||
await callback.answer("❌ Напоминания выключены")
|
||
await callback.message.edit_text(
|
||
"❌ <b>Напоминания выключены</b>\n\n"
|
||
"Используй /reminder чтобы включить их снова."
|
||
)
|
||
|
||
|
||
@router.callback_query(F.data == "reminder_set_time")
|
||
async def set_reminder_time_prompt(callback: CallbackQuery, state: FSMContext):
|
||
"""Запросить время для напоминаний"""
|
||
await state.set_state(ReminderStates.waiting_for_time)
|
||
|
||
await callback.message.edit_text(
|
||
"⏰ <b>Установка времени напоминаний</b>\n\n"
|
||
"Отправь время в формате <b>HH:MM</b> (UTC)\n\n"
|
||
"Примеры:\n"
|
||
"• <code>09:00</code> - 9 утра по UTC\n"
|
||
"• <code>18:30</code> - 18:30 по UTC\n"
|
||
"• <code>20:00</code> - 8 вечера по UTC\n\n"
|
||
"💡 UTC = МСК - 3 часа\n"
|
||
"(если хочешь 12:00 по МСК, введи 09:00)\n\n"
|
||
"Отправь /cancel для отмены"
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
@router.message(Command("cancel"), ReminderStates.waiting_for_time)
|
||
async def cancel_set_time(message: Message, state: FSMContext):
|
||
"""Отменить установку времени"""
|
||
await state.clear()
|
||
await message.answer("❌ Установка времени отменена")
|
||
|
||
|
||
@router.message(ReminderStates.waiting_for_time)
|
||
async def process_reminder_time(message: Message, state: FSMContext):
|
||
"""Обработать введённое время"""
|
||
time_str = message.text.strip()
|
||
|
||
# Валидация формата HH:MM
|
||
try:
|
||
parts = time_str.split(':')
|
||
if len(parts) != 2:
|
||
raise ValueError()
|
||
|
||
hour, minute = int(parts[0]), int(parts[1])
|
||
|
||
if not (0 <= hour <= 23 and 0 <= minute <= 59):
|
||
raise ValueError()
|
||
|
||
# Формат OK
|
||
formatted_time = f"{hour:02d}:{minute:02d}"
|
||
|
||
except:
|
||
await message.answer(
|
||
"❌ Неверный формат времени!\n\n"
|
||
"Используй формат <b>HH:MM</b> (например, 09:00 или 18:30)\n"
|
||
"Или отправь /cancel для отмены"
|
||
)
|
||
return
|
||
|
||
# Сохраняем время
|
||
async with async_session_maker() as session:
|
||
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
|
||
|
||
user.daily_task_time = formatted_time
|
||
|
||
# Автоматически включаем напоминания
|
||
user.reminders_enabled = True
|
||
|
||
await session.commit()
|
||
|
||
await state.clear()
|
||
|
||
await message.answer(
|
||
f"✅ <b>Время установлено!</b>\n\n"
|
||
f"Напоминания: <b>{formatted_time} UTC</b>\n"
|
||
f"Статус: <b>Включены</b>\n\n"
|
||
f"Ты будешь получать ежедневные напоминания о практике.\n"
|
||
f"Используй /reminder для изменения настроек."
|
||
)
|