#!/usr/bin/env python3 """Построитель многоуровневого меню.""" import logging from typing import Dict, List, Optional, Callable from dataclasses import dataclass, field from telegram import InlineKeyboardButton, InlineKeyboardMarkup # Импортируем модели и утилиты from bot.models.user_state import UserState logger = logging.getLogger(__name__) @dataclass class MenuItem: """Элемент меню.""" label: str callback: str # callback_data для кнопки description: str = "" icon: str = "" children: List["MenuItem"] = field(default_factory=list) command: Optional[str] = None # CLI команда для выполнения is_command: bool = False class MenuBuilder: """Построитель InlineKeyboard для меню.""" def __init__(self): self._menus: Dict[str, List[MenuItem]] = {} def add_menu(self, menu_name: str, items: List[MenuItem]): self._menus[menu_name] = items def get_menu(self, menu_name: str) -> List[MenuItem]: return self._menus.get(menu_name, []) def get_keyboard(self, menu_name: str, user_id: int = None, state: UserState = None) -> InlineKeyboardMarkup: """Создает InlineKeyboard для меню.""" items = self._menus.get(menu_name, []) keyboard = [] # Для главного меню — динамически меняем кнопку ИИ if menu_name == "main" and state: # Используем переданное состояние logger.info(f"get_keyboard: user_id={user_id}, ai_chat_mode={state.ai_chat_mode}") for item in items: # Проверяем базовый callback и его варианты с _on/_off is_ai_toggle = item.callback in ["toggle_ai_chat", "toggle_ai_chat_on", "toggle_ai_chat_off"] if is_ai_toggle: # Меняем текст кнопки и callback_data в зависимости от статуса if state.ai_chat_mode: label = f"✅ Выключить чат с ИИ" callback = "toggle_ai_chat_off" else: label = f"❌ Включить чат с ИИ" callback = "toggle_ai_chat_on" logger.info(f"get_keyboard: label={label}, callback={callback}") button = InlineKeyboardButton(label, callback_data=callback) else: button = InlineKeyboardButton(item.label, callback_data=item.callback) keyboard.append([button]) else: for item in items: button = InlineKeyboardButton( item.label, callback_data=item.callback ) keyboard.append([button]) return InlineKeyboardMarkup(keyboard) class CommandRegistry: """Реестр команд для легкого добавления.""" def __init__(self): self._commands: Dict[str, Callable] = {} def register(self, name: str): """Декоратор для регистрации команды.""" def decorator(func: Callable): self._commands[name] = func return func return decorator def get(self, name: str) -> Optional[Callable]: return self._commands.get(name) def list_commands(self) -> List[str]: return list(self._commands.keys()) def init_menus(menu_builder: MenuBuilder): """Инициализация структуры меню.""" # Главное меню main_menu = [ MenuItem("🖥️ Выбор сервера", "server_menu", icon="🖥️"), MenuItem("📋 Предустановленные команды", "preset_menu", icon="📋"), MenuItem("🎛️ AI-пресеты", "ai_presets", icon="🎛️"), MenuItem("💬 Чат с ИИ агентом", "toggle_ai_chat", icon="💬"), MenuItem("⚙️ Настройки бота", "settings_menu", icon="⚙️"), MenuItem("ℹ️ О боте", "about", icon="ℹ️"), ] menu_builder.add_menu("main", main_menu) # Меню серверов server_menu = [ MenuItem("💻 local (localhost)", "server_select_local", icon="💻"), MenuItem("➕ Добавить сервер", "server_add", icon="➕"), MenuItem("⬅️ Назад", "main", icon="⬅️"), ] menu_builder.add_menu("server", server_menu) # Меню предустановленных команд preset_menu = [ MenuItem("📁 Файловая система", "fs_menu", icon="📁"), MenuItem("🔍 Поиск", "search_menu", icon="🔍"), MenuItem("📊 Система", "system_menu", icon="📊"), MenuItem("🌐 Сеть", "network_menu", icon="🌐"), MenuItem("⬅️ Назад", "main", icon="⬅️"), ] menu_builder.add_menu("preset", preset_menu) # Файловая система fs_menu = [ MenuItem("ls -la", "cmd_ls_la", command="ls -la", icon="📄"), MenuItem("pwd", "cmd_pwd", command="pwd", icon="📍"), MenuItem("df -h", "cmd_df", command="df -h", icon="💾"), MenuItem("du -sh *", "cmd_du", command="du -sh * 2>/dev/null | sort -hr | head -20", icon="📊"), MenuItem("⬅️ Назад", "preset", icon="⬅️"), ] menu_builder.add_menu("fs", fs_menu) # Поиск search_menu = [ MenuItem("find . -name", "cmd_find_name", command="find . -maxdepth 3 -name '*.txt' 2>/dev/null", icon="🔎"), MenuItem("grep пример", "cmd_grep", command="grep -r 'example' . 2>/dev/null | head -20", icon="🔍"), MenuItem("which command", "cmd_which", command="which python3 bash git", icon="📍"), MenuItem("⬅️ Назад", "preset", icon="⬅️"), ] menu_builder.add_menu("search", search_menu) # Система system_menu = [ MenuItem("top -n 1", "cmd_top", command="top -bn1 | head -20", icon="📈"), MenuItem("ps aux", "cmd_ps", command="ps aux | head -20", icon="🔄"), MenuItem("free -h", "cmd_free", command="free -h", icon="💾"), MenuItem("uname -a", "cmd_uname", command="uname -a", icon="ℹ️"), MenuItem("uptime", "cmd_uptime", command="uptime", icon="⏱️"), MenuItem("⬅️ Назад", "preset", icon="⬅️"), ] menu_builder.add_menu("system", system_menu) # Сеть network_menu = [ MenuItem("ip addr", "cmd_ip", command="ip addr 2>/dev/null || ifconfig 2>/dev/null", icon="🌐"), MenuItem("ping google", "cmd_ping", command="ping -c 4 google.com 2>&1 | head -10", icon="📡"), MenuItem("netstat", "cmd_netstat", command="ss -tuln 2>/dev/null || netstat -tuln 2>/dev/null | head -20", icon="🔌"), MenuItem("curl ifconfig.me", "cmd_curl_ip", command="curl -s ifconfig.me 2>&1", icon="📍"), MenuItem("⬅️ Назад", "preset", icon="⬅️"), ] menu_builder.add_menu("network", network_menu) # Настройки settings_menu = [ MenuItem("📝 Изменить имя бота", "set_name", icon="📝"), MenuItem("📄 Изменить описание", "set_description", icon="📄"), MenuItem("🎨 Изменить иконку", "set_icon", icon="🎨"), MenuItem("🧠 Память ИИ", "memory_menu", icon="🧠"), MenuItem("⬅️ Назад", "main", icon="⬅️"), ] menu_builder.add_menu("settings", settings_menu) # Меню AI-провайдера ai_provider_menu = [ MenuItem("🔄 Переключить AI-провайдер", "ai_provider_toggle", icon="🔄"), MenuItem("ℹ️ Информация о провайдерах", "ai_provider_info", icon="ℹ️"), MenuItem("⬅️ Назад", "settings", icon="⬅️"), ] menu_builder.add_menu("ai_provider", ai_provider_menu) # Память ИИ memory_menu = [ MenuItem("📋 Мой профиль", "memory_profile", icon="📋"), MenuItem("📊 Статистика", "memory_stats", icon="📊"), MenuItem("🗑️ Очистить историю", "memory_clear", icon="🗑️"), MenuItem("🔄 Компактификация", "memory_compact", icon="🔄"), MenuItem("⬅️ Назад", "settings", icon="⬅️"), ] menu_builder.add_menu("memory", memory_menu) # Доступ access_menu = [ MenuItem("📋 Показать разрешённых", "show_access", icon="📋"), MenuItem("➕ Добавить пользователя", "add_access", icon="➕"), MenuItem("➖ Удалить пользователя", "remove_access", icon="➖"), MenuItem("⬅️ Назад", "settings", icon="⬅️"), ] menu_builder.add_menu("access", access_menu)