Files
tg_bot_language/bot/handlers/admin.py
mamonov.ep f2c4f7031e refactor: обновлена админ-панель с меню и просмотром слов дня
- Главное меню: настройка модели, генерация слов дня, просмотр слов
- Кнопка "Слова дня (сегодня)" показывает все сгенерированные слова
- Навигация между разделами

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 11:05:11 +03:00

258 lines
9.7 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, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
from config.settings import settings
from database.db import async_session_maker
from database.models import AIProvider
from services.ai_model_service import AIModelService
router = Router()
def get_admin_ids() -> set:
"""Получить множество ID админов"""
if not settings.admin_ids:
return set()
return set(int(x.strip()) for x in settings.admin_ids.split(",") if x.strip())
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:
models = await AIModelService.get_all_models(session)
keyboard = []
for model in models:
marker = "" if model.is_active else ""
provider_emoji = "🟢" if model.provider == AIProvider.openai else "🔵"
keyboard.append([InlineKeyboardButton(
text=f"{marker}{provider_emoji} {model.display_name}",
callback_data=f"admin_model_{model.id}"
)])
keyboard.append([InlineKeyboardButton(text="⬅️ Назад", callback_data="admin_back")])
return InlineKeyboardMarkup(inline_keyboard=keyboard)
@router.message(Command("admin"))
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)
active_name = active_model.display_name if active_model else "Не выбрана"
text = (
"🔧 <b>Админ-панель</b>\n\n"
f"🤖 Текущая AI модель: <b>{active_name}</b>"
)
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 = (
"🔧 <b>Админ-панель</b>\n\n"
f"🤖 Текущая AI модель: <b>{active_name}</b>"
)
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 = (
"🤖 <b>Настройка AI модели</b>\n\n"
f"Текущая модель: <b>{active_name}</b>\n\n"
"Выберите модель:"
)
keyboard = await get_model_keyboard()
await callback.message.edit_text(text, reply_markup=keyboard)
await callback.answer()
@router.callback_query(F.data.startswith("admin_model_"))
async def set_admin_model(callback: CallbackQuery):
"""Установить AI модель"""
if not is_admin(callback.from_user.id):
await callback.answer("⛔ Доступ запрещен", show_alert=True)
return
model_id = int(callback.data.split("_")[-1])
async with async_session_maker() as session:
success = await AIModelService.set_active_model(session, model_id)
if success:
active_model = await AIModelService.get_active_model(session)
await callback.answer(f"✅ Модель изменена: {active_model.display_name}")
text = (
"🤖 <b>Настройка AI модели</b>\n\n"
f"Текущая модель: <b>{active_model.display_name}</b>\n\n"
"Выберите модель:"
)
else:
await callback.answer("❌ Ошибка при смене модели", show_alert=True)
text = "🤖 <b>Настройка AI модели</b>\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 = (
"✅ <b>Генерация завершена</b>\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 = "📋 <b>Слова дня</b>\n\n❌ Слова на сегодня ещё не сгенерированы"
else:
text = f"📋 <b>Слова дня</b> ({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} <b>{current_lang.upper()}</b>\n"
text += f"• <b>{wod.level}</b>: {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):
"""Закрыть админ-панель"""
if not is_admin(callback.from_user.id):
return
await callback.message.delete()
await callback.answer()
@router.message(Command("generate_wod"))
async def cmd_generate_wod(message: Message):
"""Принудительная генерация слов дня (команда)"""
if not is_admin(message.from_user.id):
return
from services.wordofday_service import wordofday_service
await message.answer("⏳ Запускаю генерацию слов дня...")
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 = (
"✅ <b>Генерация завершена</b>\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}"
await message.answer(text)