refactor: обновлена админ-панель с меню и просмотром слов дня
- Главное меню: настройка модели, генерация слов дня, просмотр слов - Кнопка "Слова дня (сегодня)" показывает все сгенерированные слова - Навигация между разделами 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,16 @@ def is_admin(user_id: int) -> bool:
|
|||||||
return user_id in get_admin_ids()
|
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:
|
async def get_model_keyboard() -> InlineKeyboardMarkup:
|
||||||
"""Создать клавиатуру выбора AI модели"""
|
"""Создать клавиатуру выбора AI модели"""
|
||||||
async with async_session_maker() as session:
|
async with async_session_maker() as session:
|
||||||
@@ -36,7 +46,7 @@ async def get_model_keyboard() -> InlineKeyboardMarkup:
|
|||||||
callback_data=f"admin_model_{model.id}"
|
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)
|
return InlineKeyboardMarkup(inline_keyboard=keyboard)
|
||||||
|
|
||||||
|
|
||||||
@@ -46,7 +56,6 @@ async def cmd_admin(message: Message):
|
|||||||
if not is_admin(message.from_user.id):
|
if not is_admin(message.from_user.id):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Убеждаемся что дефолтные модели созданы
|
|
||||||
async with async_session_maker() as session:
|
async with async_session_maker() as session:
|
||||||
await AIModelService.ensure_default_models(session)
|
await AIModelService.ensure_default_models(session)
|
||||||
active_model = await AIModelService.get_active_model(session)
|
active_model = await AIModelService.get_active_model(session)
|
||||||
@@ -55,12 +64,53 @@ async def cmd_admin(message: Message):
|
|||||||
|
|
||||||
text = (
|
text = (
|
||||||
"🔧 <b>Админ-панель</b>\n\n"
|
"🔧 <b>Админ-панель</b>\n\n"
|
||||||
f"🤖 Текущая AI модель: <b>{active_name}</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()
|
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_"))
|
@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}")
|
await callback.answer(f"✅ Модель изменена: {active_model.display_name}")
|
||||||
|
|
||||||
text = (
|
text = (
|
||||||
"🔧 <b>Админ-панель</b>\n\n"
|
"🤖 <b>Настройка AI модели</b>\n\n"
|
||||||
f"🤖 Текущая AI модель: <b>{active_model.display_name}</b>\n\n"
|
f"Текущая модель: <b>{active_model.display_name}</b>\n\n"
|
||||||
"Выберите модель для генерации:"
|
"Выберите модель:"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await callback.answer("❌ Ошибка при смене модели", show_alert=True)
|
await callback.answer("❌ Ошибка при смене модели", show_alert=True)
|
||||||
text = "🔧 <b>Админ-панель</b>\n\n❌ Ошибка при смене модели"
|
text = "🤖 <b>Настройка AI модели</b>\n\n❌ Ошибка при смене модели"
|
||||||
|
|
||||||
keyboard = await get_model_keyboard()
|
keyboard = await get_model_keyboard()
|
||||||
await callback.message.edit_text(text, reply_markup=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")
|
@router.callback_query(F.data == "admin_close")
|
||||||
async def admin_close(callback: CallbackQuery):
|
async def admin_close(callback: CallbackQuery):
|
||||||
"""Закрыть админ-панель"""
|
"""Закрыть админ-панель"""
|
||||||
@@ -104,7 +231,7 @@ async def admin_close(callback: CallbackQuery):
|
|||||||
|
|
||||||
@router.message(Command("generate_wod"))
|
@router.message(Command("generate_wod"))
|
||||||
async def cmd_generate_wod(message: Message):
|
async def cmd_generate_wod(message: Message):
|
||||||
"""Принудительная генерация слов дня"""
|
"""Принудительная генерация слов дня (команда)"""
|
||||||
if not is_admin(message.from_user.id):
|
if not is_admin(message.from_user.id):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user