telegram-cli-bot/bot/keyboards/menus.py

201 lines
8.7 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

#!/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, StateManager
logger = logging.getLogger(__name__)
# Глобальный state_manager для кнопки ИИ
state_manager = StateManager()
@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 user_id:
# Используем переданное состояние или получаем из менеджера
if state is None:
state = state_manager.get(user_id)
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("💬 Чат с ИИ агентом", "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("👥 Управление доступом", "access_menu", icon="👥"),
MenuItem("🧠 Память ИИ", "memory_menu", icon="🧠"),
MenuItem("⬅️ Назад", "main", icon="⬅️"),
]
menu_builder.add_menu("settings", settings_menu)
# Память ИИ
memory_menu = [
MenuItem("📋 Мой профиль", "memory_profile", icon="📋"),
MenuItem("📊 Статистика", "memory_stats", icon="📊"),
MenuItem("🗑️ Очистить историю", "memory_clear", 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)