diff --git a/bot/handlers/admin.py b/bot/handlers/admin.py
index f3c7224..9461e27 100644
--- a/bot/handlers/admin.py
+++ b/bot/handlers/admin.py
@@ -22,6 +22,16 @@ def is_admin(user_id: int) -> bool:
return user_id in get_admin_ids()
+def get_admin_main_keyboard() -> InlineKeyboardMarkup:
+ """Главное меню админки"""
+ return InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text="🤖 Настройка AI модели", callback_data="admin_models")],
+ [InlineKeyboardButton(text="🌅 Генерация слов дня", callback_data="admin_generate_wod")],
+ [InlineKeyboardButton(text="📋 Слова дня (сегодня)", callback_data="admin_view_wod")],
+ [InlineKeyboardButton(text="❌ Закрыть", callback_data="admin_close")]
+ ])
+
+
async def get_model_keyboard() -> InlineKeyboardMarkup:
"""Создать клавиатуру выбора AI модели"""
async with async_session_maker() as session:
@@ -36,7 +46,7 @@ async def get_model_keyboard() -> InlineKeyboardMarkup:
callback_data=f"admin_model_{model.id}"
)])
- keyboard.append([InlineKeyboardButton(text="❌ Закрыть", callback_data="admin_close")])
+ keyboard.append([InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_back")])
return InlineKeyboardMarkup(inline_keyboard=keyboard)
@@ -46,7 +56,6 @@ async def cmd_admin(message: Message):
if not is_admin(message.from_user.id):
return
- # Убеждаемся что дефолтные модели созданы
async with async_session_maker() as session:
await AIModelService.ensure_default_models(session)
active_model = await AIModelService.get_active_model(session)
@@ -55,12 +64,53 @@ async def cmd_admin(message: Message):
text = (
"🔧 Админ-панель\n\n"
- f"🤖 Текущая AI модель: {active_name}\n\n"
- "Выберите модель для генерации:"
+ f"🤖 Текущая AI модель: {active_name}"
+ )
+
+ await message.answer(text, reply_markup=get_admin_main_keyboard())
+
+
+@router.callback_query(F.data == "admin_back")
+async def admin_back(callback: CallbackQuery):
+ """Вернуться в главное меню админки"""
+ if not is_admin(callback.from_user.id):
+ return
+
+ async with async_session_maker() as session:
+ active_model = await AIModelService.get_active_model(session)
+
+ active_name = active_model.display_name if active_model else "Не выбрана"
+
+ text = (
+ "🔧 Админ-панель\n\n"
+ f"🤖 Текущая AI модель: {active_name}"
+ )
+
+ await callback.message.edit_text(text, reply_markup=get_admin_main_keyboard())
+ await callback.answer()
+
+
+@router.callback_query(F.data == "admin_models")
+async def admin_models(callback: CallbackQuery):
+ """Показать список моделей"""
+ if not is_admin(callback.from_user.id):
+ await callback.answer("⛔ Доступ запрещен", show_alert=True)
+ return
+
+ async with async_session_maker() as session:
+ active_model = await AIModelService.get_active_model(session)
+
+ active_name = active_model.display_name if active_model else "Не выбрана"
+
+ text = (
+ "🤖 Настройка AI модели\n\n"
+ f"Текущая модель: {active_name}\n\n"
+ "Выберите модель:"
)
keyboard = await get_model_keyboard()
- await message.answer(text, reply_markup=keyboard)
+ await callback.message.edit_text(text, reply_markup=keyboard)
+ await callback.answer()
@router.callback_query(F.data.startswith("admin_model_"))
@@ -80,18 +130,95 @@ async def set_admin_model(callback: CallbackQuery):
await callback.answer(f"✅ Модель изменена: {active_model.display_name}")
text = (
- "🔧 Админ-панель\n\n"
- f"🤖 Текущая AI модель: {active_model.display_name}\n\n"
- "Выберите модель для генерации:"
+ "🤖 Настройка AI модели\n\n"
+ f"Текущая модель: {active_model.display_name}\n\n"
+ "Выберите модель:"
)
else:
await callback.answer("❌ Ошибка при смене модели", show_alert=True)
- text = "🔧 Админ-панель\n\n❌ Ошибка при смене модели"
+ text = "🤖 Настройка AI модели\n\n❌ Ошибка при смене модели"
keyboard = await get_model_keyboard()
await callback.message.edit_text(text, reply_markup=keyboard)
+@router.callback_query(F.data == "admin_generate_wod")
+async def admin_generate_wod(callback: CallbackQuery):
+ """Генерация слов дня через кнопку"""
+ if not is_admin(callback.from_user.id):
+ await callback.answer("⛔ Доступ запрещен", show_alert=True)
+ return
+
+ await callback.answer()
+ await callback.message.edit_text("⏳ Генерирую слова дня...")
+
+ from services.wordofday_service import wordofday_service
+
+ try:
+ results = await wordofday_service.generate_all_words_for_today()
+ total = results.get("en", 0) + results.get("ja", 0)
+ errors = results.get("errors", 0)
+
+ text = (
+ "✅ Генерация завершена\n\n"
+ f"📊 Всего сгенерировано: {total}\n"
+ f"🇬🇧 Английский: {results.get('en', 0)}\n"
+ f"🇯🇵 Японский: {results.get('ja', 0)}\n"
+ f"❌ Ошибок: {errors}"
+ )
+ except Exception as e:
+ text = f"❌ Ошибка генерации: {e}"
+
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_back")]
+ ])
+ await callback.message.edit_text(text, reply_markup=keyboard)
+
+
+@router.callback_query(F.data == "admin_view_wod")
+async def admin_view_wod(callback: CallbackQuery):
+ """Просмотр всех слов дня за сегодня"""
+ if not is_admin(callback.from_user.id):
+ await callback.answer("⛔ Доступ запрещен", show_alert=True)
+ return
+
+ await callback.answer()
+
+ from datetime import datetime
+ from sqlalchemy import select
+ from database.models import WordOfDay
+
+ today = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
+
+ async with async_session_maker() as session:
+ result = await session.execute(
+ select(WordOfDay).where(WordOfDay.date == today).order_by(WordOfDay.learning_lang, WordOfDay.level)
+ )
+ words = result.scalars().all()
+
+ if not words:
+ text = "📋 Слова дня\n\n❌ Слова на сегодня ещё не сгенерированы"
+ else:
+ text = f"📋 Слова дня ({today.strftime('%d.%m.%Y')})\n\n"
+
+ current_lang = None
+ for wod in words:
+ if wod.learning_lang != current_lang:
+ current_lang = wod.learning_lang
+ lang_emoji = "🇬🇧" if current_lang == "en" else "🇯🇵"
+ text += f"\n{lang_emoji} {current_lang.upper()}\n"
+
+ text += f"• {wod.level}: {wod.word}"
+ if wod.transcription:
+ text += f" [{wod.transcription}]"
+ text += f" — {wod.translation}\n"
+
+ keyboard = InlineKeyboardMarkup(inline_keyboard=[
+ [InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_back")]
+ ])
+ await callback.message.edit_text(text, reply_markup=keyboard)
+
+
@router.callback_query(F.data == "admin_close")
async def admin_close(callback: CallbackQuery):
"""Закрыть админ-панель"""
@@ -104,7 +231,7 @@ async def admin_close(callback: CallbackQuery):
@router.message(Command("generate_wod"))
async def cmd_generate_wod(message: Message):
- """Принудительная генерация слов дня"""
+ """Принудительная генерация слов дня (команда)"""
if not is_admin(message.from_user.id):
return