# -*- coding: utf-8 -*- """ Административные команды: !stats, !status, !clean. - !stats – статистика работы бота (сообщения, файлы, AI-запросы, ошибки, uptime). - !status – проверка состояния сервисов (GigaChat, PostgreSQL, Qdrant, диск). - !clean – очистка временной директории. Изменения для PostgreSQL: - Замена `conn.ping()` на `conn.execute("SELECT 1")` в команде !status. - Обновлены тексты сообщений (MariaDB → PostgreSQL). """ import os import shutil import logging from datetime import datetime from core.commands.base import Command logger = logging.getLogger(__name__) class StatsCommand(Command): """Показывает статистику работы бота (только для администраторов).""" name = "!stats" aliases = ["/stats", "!статистика", "/статистика", "!стат", "/стат"] permission = "admin" async def execute(self, msg, args: str, user_jid: str, room_jid: str = None): """ Выводит: - uptime бота - количество обработанных сообщений - количество AI-запросов - количество обработанных файлов - количество ошибок - количество документов в базе знаний (с учётом контекста) """ if not self.check_permission(user_jid): reply = msg.reply("⛔ Нет прав.") if reply: reply.send() # исправлено else: logger.error("Не удалось отправить сообщение о недостатке прав (stats)") return # Время работы бота uptime = datetime.now() - self.bot.start_time # Получение метрик из MetricsHandler stats = self.bot.metrics_handler.get() # Количество доступных документов в БЗ (личные/комнатные + глобальные) sources = await self.bot.kb.get_available_sources(user_jid, room_jid) response = ( f"📊 **Статистика бота {self.bot.config.name}**\n" f"⏱ Uptime: {str(uptime).split('.')[0]}\n" f"💬 Сообщений: {stats.get('messages_total', 0)}\n" f"🤖 AI запросов: {stats.get('ai_requests', 0)}\n" f"📁 Файлов обработано: {stats.get('files_processed', 0)}\n" f"❌ Ошибок: {stats.get('errors_total', 0)}\n" f"📚 Документов в БЗ: {len(sources)}" ) reply = msg.reply(response) if reply: reply.send() # исправлено else: logger.error("Не удалось отправить статистику") def get_help(self) -> str: return "Показывает статистику работы бота (админ)." class StatusCommand(Command): """Проверяет состояние всех внешних сервисов (административная команда).""" name = "!status" aliases = ["/status", "!статус", "/статус"] permission = "admin" async def execute(self, msg, args: str, user_jid: str, room_jid: str = None): if not self.check_permission(user_jid): reply = msg.reply("⛔ Нет прав.") if reply: reply.send() # исправлено else: logger.error("Не удалось отправить сообщение о недостатке прав (stats)") return # --- GigaChat --- try: # Простой запрос для проверки доступности API await self.bot.giga.chat([], "ping", system_prompt=None, file_id=None, temperature=0.1) ai_status = "✅ GigaChat Online" except Exception as e: ai_status = f"❌ GigaChat Offline: {e}" # --- PostgreSQL (asyncpg) --- try: async with self.bot.db.pool.acquire() as conn: # В asyncpg нет метода ping(), используем SELECT 1 await conn.execute("SELECT 1") db_status = "✅ PostgreSQL Online" except Exception as e: db_status = f"❌ PostgreSQL Error: {e}" # --- Qdrant --- try: self.bot.qdrant.client.get_collection(self.bot.qdrant.collection_name) qd_status = "✅ Qdrant Online" except Exception as e: qd_status = f"❌ Qdrant Error: {e}" # --- Дисковое пространство (временная директория) --- total, used, free = shutil.disk_usage(self.bot.config.temp_dir) disk_info = f"💾 Диск: {used // (2**20)}MB / {total // (2**20)}MB" full_status = f"🛰 **СТАТУС БОТА**\n{ai_status}\n{db_status}\n{qd_status}\n{disk_info}" reply = msg.reply(full_status) if reply: reply.send() # исправлено else: logger.error("Не удалось отправить статус") def get_help(self) -> str: return "Проверяет состояние сервисов (GigaChat, PostgreSQL, Qdrant, диск) – админ." class CleanCommand(Command): """Очищает временную директорию бота (temp_dir).""" name = "!clean" aliases = ["/clean", "!очистка", "/очистка"] permission = "admin" async def execute(self, msg, args: str, user_jid: str, room_jid: str = None): if not self.check_permission(user_jid): reply = msg.reply("⛔ Нет прав.") if reply: reply.send() # исправлено else: logger.error("Не удалось отправить сообщение о недостатке прав (stats)") return count = 0 temp_dir = self.bot.config.temp_dir for f in os.listdir(temp_dir): try: p = os.path.join(temp_dir, f) if os.path.isfile(p): os.unlink(p) elif os.path.isdir(p): shutil.rmtree(p) count += 1 except Exception: pass reply = msg.reply(f"🧹 Удалено объектов из temp_dir: {count}") if reply: reply.send() # исправлено else: logger.error("Не удалось отправить отчёт об очистке") def get_help(self) -> str: return "Очищает временную директорию бота (админ)."