#!/usr/bin/env python3 """ Обработчики команд для переключения AI-пресетов. Доступные пресеты: - off: ИИ отключен, режим CLI команд - qwen: Qwen Code (бесплатно, локально) - giga_auto: GigaChat авто-переключение (Lite/Pro) - giga_lite: GigaChat Lite (дешевле) - giga_pro: GigaChat Pro (максимальное качество) """ import logging from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import CommandHandler, CallbackQueryHandler from bot.models.user_state import ( AI_PRESET_OFF, AI_PRESET_QWEN, AI_PRESET_GIGA_AUTO, AI_PRESET_GIGA_LITE, AI_PRESET_GIGA_PRO, AI_PRESET_GIGA_MAX, AI_PRESET_OPENCODE, ) from bot.config import state_manager logger = logging.getLogger(__name__) # Описание пресетов PRESET_DESCRIPTIONS = { AI_PRESET_OFF: { "name": "❌ ИИ Отключен", "description": "Режим CLI команд. Бот выполняет команды напрямую.", "icon": "⌨️" }, AI_PRESET_QWEN: { "name": "🤖 Qwen Code", "description": "Бесплатно, локально. Лучший для кода и работы с файлами.", "icon": "💻" }, AI_PRESET_GIGA_AUTO: { "name": "🔄 GigaChat Авто", "description": "Умное переключение Lite/Pro. Простые → Lite, сложные → Pro.", "icon": "🧠" }, AI_PRESET_GIGA_LITE: { "name": "⚡ GigaChat Lite", "description": "Быстро и дёшево. Для простых вопросов и чата.", "icon": "🚀" }, AI_PRESET_GIGA_PRO: { "name": "🔥 GigaChat Pro", "description": "Максимальное качество. Для сложных творческих задач.", "icon": "👑" }, AI_PRESET_GIGA_MAX: { "name": "💎 GigaChat Max", "description": "Топовая модель для самых сложных задач.", "icon": "💎" }, AI_PRESET_OPENCODE: { "name": "⚡ Opencode", "description": "Бесплатные модели (minimax, big-pickle, gpt-5-nano).", "icon": "🚀" }, } def get_preset_display_name(preset: str) -> str: """Получить отображаемое имя пресета.""" desc = PRESET_DESCRIPTIONS.get(preset, {}) return f"{desc.get('icon', '❓')} {desc.get('name', preset)}" async def ai_presets_command(update: Update, context): """Показать меню выбора AI-пресета.""" user_id = update.effective_user.id state = state_manager.get(user_id) current_preset = state.ai_preset # Формируем меню - Opencode и GigaChat теперь открывают подменю выбора моделей keyboard = [ [ InlineKeyboardButton( f"{'✅' if current_preset == AI_PRESET_OFF else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_OFF]['icon']} ИИ Отключен", callback_data=f"ai_preset_{AI_PRESET_OFF}" ) ], [ InlineKeyboardButton( f"{'✅' if current_preset == AI_PRESET_QWEN else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_QWEN]['icon']} Qwen Code", callback_data=f"ai_preset_{AI_PRESET_QWEN}" ) ], [ InlineKeyboardButton( f"{'✅' if current_preset == AI_PRESET_GIGA_AUTO else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_AUTO]['icon']} GigaChat Авто", callback_data=f"ai_preset_{AI_PRESET_GIGA_AUTO}" ) ], # Кнопка GigaChat с подменю - убираем Lite и Pro из основного меню [ InlineKeyboardButton( f"{'✅' if current_preset in [AI_PRESET_GIGA_LITE, AI_PRESET_GIGA_PRO, AI_PRESET_GIGA_MAX] else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_LITE]['icon']} GigaChat ▶", callback_data="gigachat_submenu" ) ], # Кнопка Opencode с подменю [ InlineKeyboardButton( f"{'✅' if current_preset == AI_PRESET_OPENCODE else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_OPENCODE]['icon']} Opencode ▶", callback_data="opencode_submenu" ) ], ] reply_markup = InlineKeyboardMarkup(keyboard) current_name = get_preset_display_name(current_preset) output = f"🎛️ **Панель управления AI**\n\n" output += f"**Текущий пресет:** {current_name}\n\n" output += "Выберите AI-провайдер:\n\n" output += "ℹ️ **Описание пресетов:**\n" output += f"• {PRESET_DESCRIPTIONS[AI_PRESET_OFF]['icon']} **ИИ Отключен** — {PRESET_DESCRIPTIONS[AI_PRESET_OFF]['description']}\n" output += f"• {PRESET_DESCRIPTIONS[AI_PRESET_QWEN]['icon']} **Qwen Code** — {PRESET_DESCRIPTIONS[AI_PRESET_QWEN]['description']}\n" output += f"• {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_AUTO]['icon']} **GigaChat Авто** — {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_AUTO]['description']}\n" output += f"• {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_LITE]['icon']} **GigaChat** — {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_LITE]['description']}\n" output += f"• {PRESET_DESCRIPTIONS[AI_PRESET_OPENCODE]['icon']} **Opencode** — {PRESET_DESCRIPTIONS[AI_PRESET_OPENCODE]['description']}" await update.message.reply_text(output, parse_mode="Markdown", reply_markup=reply_markup) async def ai_preset_callback(update: Update, context): """Обработка выбора пресета из инлайн-меню.""" user_id = update.effective_user.id query = update.callback_query await query.answer() # Извлекаем название пресета из callback_data preset = query.data.replace("ai_preset_", "") if preset not in PRESET_DESCRIPTIONS: await query.edit_message_text("❌ Неверный пресет") return state = state_manager.get(user_id) old_preset = state.ai_preset state.ai_preset = preset # Обновляем ai_chat_mode и current_ai_provider для совместимости if preset == AI_PRESET_OFF: state.ai_chat_mode = False state.current_ai_provider = "none" else: state.ai_chat_mode = True # Для совместимости с существующим кодом if preset == AI_PRESET_QWEN: state.current_ai_provider = "qwen" elif preset == AI_PRESET_OPENCODE: state.current_ai_provider = "opencode" else: # Любой GigaChat state.current_ai_provider = "gigachat" preset_name = get_preset_display_name(preset) output = f"✅ **Переключено на:** {preset_name}\n\n" output += f"{PRESET_DESCRIPTIONS[preset]['description']}" # Обновляем инлайн-меню - с подменю для Opencode и GigaChat keyboard = [ [ InlineKeyboardButton( f"{'✅' if preset == AI_PRESET_OFF else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_OFF]['icon']} ИИ Отключен", callback_data=f"ai_preset_{AI_PRESET_OFF}" ) ], [ InlineKeyboardButton( f"{'✅' if preset == AI_PRESET_QWEN else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_QWEN]['icon']} Qwen Code", callback_data=f"ai_preset_{AI_PRESET_QWEN}" ) ], [ InlineKeyboardButton( f"{'✅' if preset == AI_PRESET_GIGA_AUTO else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_AUTO]['icon']} GigaChat Авто", callback_data=f"ai_preset_{AI_PRESET_GIGA_AUTO}" ) ], [ InlineKeyboardButton( f"{'✅' if preset in [AI_PRESET_GIGA_LITE, AI_PRESET_GIGA_PRO, AI_PRESET_GIGA_MAX] else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_GIGA_LITE]['icon']} GigaChat ▶", callback_data="gigachat_submenu" ) ], [ InlineKeyboardButton( f"{'✅' if preset == AI_PRESET_OPENCODE else '⬜'} {PRESET_DESCRIPTIONS[AI_PRESET_OPENCODE]['icon']} Opencode ▶", callback_data="opencode_submenu" ) ], ] reply_markup = InlineKeyboardMarkup(keyboard) await query.edit_message_text(output, parse_mode="Markdown", reply_markup=reply_markup) logger.info(f"Пользователь {user_id} переключил AI-пресет: {old_preset} → {preset}") # Быстрые команды для переключения одним сообщением async def ai_off_command(update: Update, context): """Быстрое переключение на ИИ отключен.""" await switch_preset(update, AI_PRESET_OFF) async def ai_qwen_command(update: Update, context): """Быстрое переключение на Qwen Code.""" await switch_preset(update, AI_PRESET_QWEN) async def ai_giga_auto_command(update: Update, context): """Быстрое переключение на GigaChat Авто.""" await switch_preset(update, AI_PRESET_GIGA_AUTO) async def ai_giga_lite_command(update: Update, context): """Быстрое переключение на GigaChat Lite.""" await switch_preset(update, AI_PRESET_GIGA_LITE) async def ai_giga_pro_command(update: Update, context): """Быстрое переключение на GigaChat Pro.""" await switch_preset(update, AI_PRESET_GIGA_PRO) async def ai_giga_max_command(update: Update, context): """Быстрое переключение на GigaChat Max.""" await switch_preset(update, AI_PRESET_GIGA_MAX) async def ai_opencode_command(update: Update, context): """Быстрое переключение на Opencode.""" await switch_preset(update, AI_PRESET_OPENCODE) async def switch_preset(update: Update, preset: str): """Переключить пресет и показать уведомление.""" user_id = update.effective_user.id state = state_manager.get(user_id) old_preset = state.ai_preset state.ai_preset = preset # Обновляем совместимость if preset == AI_PRESET_OFF: state.ai_chat_mode = False state.current_ai_provider = "none" else: state.ai_chat_mode = True if preset == AI_PRESET_QWEN: state.current_ai_provider = "qwen" elif preset == AI_PRESET_OPENCODE: state.current_ai_provider = "opencode" else: state.current_ai_provider = "gigachat" preset_name = get_preset_display_name(preset) output = f"✅ **AI-пресет переключен**\n\n" output += f"**Текущий:** {preset_name}\n" output += f"_{PRESET_DESCRIPTIONS[preset]['description']}_\n\n" if old_preset != preset: output += f"~{get_preset_display_name(old_preset)}~ → ✅ {preset_name}" await update.message.reply_text(output, parse_mode="Markdown") logger.info(f"Пользователь {user_id} переключил AI-пресет: {old_preset} → {preset}") def register_ai_preset_handlers(dispatcher): """Зарегистрировать обработчики AI-пресетов.""" # Основное меню dispatcher.add_handler(CommandHandler("ai_presets", ai_presets_command)) # Callback для инлайн-меню dispatcher.add_handler(CallbackQueryHandler(ai_preset_callback, pattern="^ai_preset_")) # Быстрые команды dispatcher.add_handler(CommandHandler("ai_off", ai_off_command)) dispatcher.add_handler(CommandHandler("ai_qwen", ai_qwen_command)) dispatcher.add_handler(CommandHandler("ai_giga_auto", ai_giga_auto_command)) dispatcher.add_handler(CommandHandler("ai_giga_lite", ai_giga_lite_command)) dispatcher.add_handler(CommandHandler("ai_giga_pro", ai_giga_pro_command)) dispatcher.add_handler(CommandHandler("ai_giga_max", ai_giga_max_command)) dispatcher.add_handler(CommandHandler("ai_opencode", ai_opencode_command)) logger.info("Обработчики AI-пресетов зарегистрированы")