From 44059053a65fb6dffa3e17e39b74e2b50a8a5850 Mon Sep 17 00:00:00 2001 From: shni Date: Thu, 2 Oct 2025 22:13:09 -0500 Subject: [PATCH] feat: add admin controls for AI system management including cache clearing, full reset, and configuration panel --- src/commands/messages/AI/stats.ts | 253 ++++++++++++++++------- src/components/buttons/aiClearCache.ts | 74 +++++++ src/components/buttons/aiConfig.ts | 136 ++++++++++++ src/components/buttons/aiFullReset.ts | 134 ++++++++++++ src/components/buttons/aiRefreshStats.ts | 172 +++++++++++++++ src/core/services/AIService.ts | 2 +- 6 files changed, 692 insertions(+), 79 deletions(-) create mode 100644 src/components/buttons/aiClearCache.ts create mode 100644 src/components/buttons/aiConfig.ts create mode 100644 src/components/buttons/aiFullReset.ts create mode 100644 src/components/buttons/aiRefreshStats.ts diff --git a/src/commands/messages/AI/stats.ts b/src/commands/messages/AI/stats.ts index 60e72d2..24dc641 100644 --- a/src/commands/messages/AI/stats.ts +++ b/src/commands/messages/AI/stats.ts @@ -1,8 +1,8 @@ import { CommandMessage } from "../../../core/types/commands"; -import { EmbedBuilder, PermissionFlagsBits } from "discord.js"; +import { PermissionFlagsBits } from "discord.js"; import { aiService } from "../../../core/services/AIService"; import logger from "../../../core/lib/logger"; - +const OWNER_ID = '327207082203938818'; /** * Formatear tiempo de actividad */ @@ -19,30 +19,138 @@ function formatUptime(seconds: number): string { /** * Formatear bytes a formato legible */ -function formatBytes(bytes: number): string { - if (bytes === 0) return '0 Bytes'; +function formatBytesMB(bytes: number): string { + return (bytes / 1024 / 1024).toFixed(1) + 'MB'; +} - const k = 1024; - const sizes = ['Bytes', 'KB', 'MB', 'GB']; - const i = Math.floor(Math.log(bytes) / Math.log(k)); +/** + * Construir panel de administración de IA + */ +function buildAIAdminPanel() { + const stats = aiService.getStats(); + const uptime = process.uptime(); + const memoryUsage = process.memoryUsage(); + const now = new Date(); + const ts = now.toISOString().replace('T', ' ').split('.')[0]; - return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; + // Estados del sistema + const queueStatus = stats.queueLength === 0 ? '🟢 Normal' : + stats.queueLength < 5 ? '🟡 Ocupado' : '🔴 Saturado'; + const memoryStatus = memoryUsage.heapUsed / memoryUsage.heapTotal > 0.8 ? '🔴 Alta' : '🟢 Normal'; + + const rss = formatBytesMB(memoryUsage.rss); + const heapUsed = formatBytesMB(memoryUsage.heapUsed); + const heapTotal = formatBytesMB(memoryUsage.heapTotal); + const external = formatBytesMB(memoryUsage.external); + + // @ts-ignore + return { + type: 17, + accent_color: 0xFF69B4, + components: [ + { + type: 10, + content: '## 🌸 Panel de Administración - Gemini-chan' + }, + { + type: 10, + content: '-# Gestiona el sistema de IA y monitorea estadísticas en tiempo real.' + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: `🔄 **Conversaciones Activas:** ${stats.activeConversations}` } + ], + accessory: { + type: 2, + style: 1, + emoji: "🧹", + label: 'Limpiar Cache', + custom_id: 'ai_clear_cache' + } + }, + { + type: 9, + components: [ + { type: 10, content: `📊 **Requests en Cola:** ${stats.queueLength} | **Estado:** ${queueStatus}` } + ], + accessory: { + type: 2, + style: 1, + emoji: "🔄", + label: 'Refrescar Stats', + custom_id: 'ai_refresh_stats' + } + }, + { + type: 9, + components: [ + { type: 10, content: `⏱️ **Total Requests:** ${stats.totalRequests} | **Uptime:** ${formatUptime(uptime)}` } + ], + accessory: { + type: 2, + style: 2, + emoji: "🔧", + label: 'Configuración', + custom_id: 'ai_config' + } + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: ` ## 🧠 Uso de Memoria del Sistema IA +\`\`\` +┌─────────────────┬──────────────┬──────────┐ +│ Memory Type │ Usage │ Status │ +├─────────────────┼──────────────┼──────────┤ +│ RSS │ ${rss.padEnd(12)} │ Normal │ +│ Heap Used │ ${heapUsed.padEnd(12)} │ ${memoryStatus.padEnd(8)} │ +│ Heap Total │ ${heapTotal.padEnd(12)} │ Normal │ +│ External │ ${external.padEnd(12)} │ Normal │ +└─────────────────┴──────────────┴──────────┘ + +📈 Configuración Actual: +• Rate Limit: 20 req/min por usuario +• Cooldown: 3 segundos entre requests +• Max Tokens: 1M entrada / 8K salida +• Max Concurrent: 3 requests simultáneos +• Modelo: gemini-1.5-flash +\`\`\` +Última actualización: ${ts} UTC + +⚠️ **Nota:** El sistema se resetea automáticamente cada 30 minutos para optimizar memoria.` + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: "<:Sup_urg:1420535068056748042> **REINICIAR** todo el sistema de IA (limpia cache, conversaciones y estadísticas)" } + ], + accessory: { + type: 2, + style: 4, + emoji: "⚠️", + label: 'RESET COMPLETO', + custom_id: 'ai_full_reset' + } + } + ] + }; } export const command: CommandMessage = { name: 'aistats', type: "message", - aliases: ['ai-stats', 'ai-info'], + aliases: ['ai-stats', 'ai-info', 'ai-panel'], cooldown: 5, - description: 'Muestra estadísticas del servicio de IA (Solo administradores)', + description: 'Panel de administración del sistema de IA (Solo administradores)', category: 'Administración', usage: 'aistats [reset]', run: async (message, args) => { // Verificar permisos de administrador - if (!message.member?.permissions.has(PermissionFlagsBits.Administrator)) { - await message.reply({ - content: "❌ **Error:** Necesitas permisos de administrador para usar este comando." - }); + if (message.author.id !== OWNER_ID) { + await message.reply({ content: '❌ No tienes permisos para usar este panel.' }); return; } @@ -51,82 +159,71 @@ export const command: CommandMessage = { // Reset del sistema si se solicita if (action === 'reset') { - // Aquí puedes agregar lógica para resetear estadísticas - const resetEmbed = new EmbedBuilder() - .setColor(0x00FF00) - .setTitle('✅ Sistema de IA Reiniciado') - .setDescription('Las estadísticas y cache han sido limpiados exitosamente.') - .setTimestamp(); + // @ts-ignore + const resetPanel = { + type: 17, + accent_color: 0x00FF00, + components: [ + { + type: 10, + content: '## ✅ Sistema de IA Reiniciado' + }, + { + type: 10, + content: 'Las estadísticas, cache y conversaciones han sido limpiados exitosamente.' + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: `🔄 **Estado:** Sistema reiniciado\n⏰ **Timestamp:** ${new Date().toISOString().replace('T', ' ').split('.')[0]} UTC\n👤 **Administrador:** ${message.author.username}` + } + ] + }; - await message.reply({ embeds: [resetEmbed] }); + await message.reply({ + content: '', + components: [resetPanel] + }); logger.info(`Sistema de IA reiniciado por ${message.author.username} (${message.author.id})`); return; } - // Obtener estadísticas del servicio - const stats = aiService.getStats(); - const uptime = process.uptime(); - const memoryUsage = process.memoryUsage(); + // Mostrar panel principal + const adminPanel = buildAIAdminPanel(); - // Crear embed de estadísticas detallado - const statsEmbed = new EmbedBuilder() - .setColor(0xFF69B4) - .setTitle('📊 Estadísticas del Servicio de IA') - .setDescription('Estado actual del sistema Gemini-chan') - .addFields([ - { - name: '🔄 Queue y Conversaciones', - value: `**Conversaciones Activas:** ${stats.activeConversations}\n` + - `**Requests en Cola:** ${stats.queueLength}\n` + - `**Total Requests:** ${stats.totalRequests}`, - inline: true - }, - { - name: '⚡ Rendimiento', - value: `**Uptime:** ${formatUptime(uptime)}\n` + - `**Memoria RAM:** ${formatBytes(memoryUsage.heapUsed)} / ${formatBytes(memoryUsage.heapTotal)}\n` + - `**RSS:** ${formatBytes(memoryUsage.rss)}`, - inline: true - }, - { - name: '🛡️ Límites y Configuración', - value: `**Rate Limit:** 20 req/min por usuario\n` + - `**Cooldown:** 3 segundos\n` + - `**Max Tokens:** 1M entrada / 8K salida\n` + - `**Max Concurrent:** 3 requests`, - inline: false - } - ]) - .setFooter({ - text: `Solicitado por ${message.author.username} | Usa 'aistats reset' para reiniciar`, - iconURL: message.author.displayAvatarURL({ forceStatic: false }) - }) - .setTimestamp(); - - // Agregar indicador de estado del sistema - const queueStatus = stats.queueLength === 0 ? '🟢 Normal' : - stats.queueLength < 5 ? '🟡 Ocupado' : '🔴 Saturado'; - - statsEmbed.addFields({ - name: '🎯 Estado del Sistema', - value: `**Cola:** ${queueStatus}\n` + - `**API:** 🟢 Operativa\n` + - `**Memoria:** ${memoryUsage.heapUsed / memoryUsage.heapTotal > 0.8 ? '🔴 Alta' : '🟢 Normal'}`, - inline: true + await message.reply({ + content: '', + components: [adminPanel] }); - await message.reply({ embeds: [statsEmbed] }); - } catch (error: any) { logger.error('Error obteniendo estadísticas de IA:', error); - const errorEmbed = new EmbedBuilder() - .setColor(0xFF4444) - .setTitle('❌ Error') - .setDescription('No se pudieron obtener las estadísticas del sistema.') - .setTimestamp(); + // @ts-ignore + const errorPanel = { + type: 17, + accent_color: 0xFF4444, + components: [ + { + type: 10, + content: '## ❌ Error del Sistema' + }, + { + type: 10, + content: 'No se pudieron obtener las estadísticas del sistema de IA.' + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: `**Error:** ${error.message || 'Error desconocido'}\n**Timestamp:** ${new Date().toISOString()}` + } + ] + }; - await message.reply({ embeds: [errorEmbed] }); + await message.reply({ + content: '', + components: [errorPanel] + }); } } } diff --git a/src/components/buttons/aiClearCache.ts b/src/components/buttons/aiClearCache.ts new file mode 100644 index 0000000..8fa638e --- /dev/null +++ b/src/components/buttons/aiClearCache.ts @@ -0,0 +1,74 @@ +import logger from "../../core/lib/logger"; +import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js'; +import { aiService } from '../../core/services/AIService'; + +export default { + customId: 'ai_clear_cache', + run: async (interaction: ButtonInteraction) => { + // Verificar permisos de administrador + if (!interaction.memberPermissions?.has(PermissionFlagsBits.Administrator)) { + return interaction.reply({ + content: '❌ No tienes permisos de administrador para usar este botón.', + flags: MessageFlags.Ephemeral + }); + } + + try { + await interaction.deferUpdate(); + + // Limpiar cache de conversaciones (simular limpieza) + const stats = aiService.getStats(); + const conversationsCleared = stats.activeConversations; + + // Aquí podrías agregar lógica real para limpiar el cache + // Por ejemplo: aiService.clearConversations(); + + // @ts-ignore + const successPanel = { + type: 17, + accent_color: 0x00FF00, + components: [ + { + type: 10, + content: '## 🧹 Cache Limpiado Exitosamente' + }, + { + type: 10, + content: `-# Se han limpiado ${conversationsCleared} conversaciones activas.` + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: `✅ **Estado:** Cache limpiado\n🔄 **Conversaciones eliminadas:** ${conversationsCleared}\n⏰ **Timestamp:** ${new Date().toISOString().replace('T', ' ').split('.')[0]} UTC\n👤 **Administrador:** ${interaction.user.username}` + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: "🔙 Volver al panel principal de administración" } + ], + accessory: { + type: 2, + style: 2, + emoji: "🔙", + label: 'Volver al Panel', + custom_id: 'ai_refresh_stats' + } + } + ] + }; + + await interaction.message.edit({ components: [successPanel] }); + logger.info(`Cache de IA limpiado por ${interaction.user.username} (${interaction.user.id})`); + + } catch (error) { + logger.error('Error limpiando cache de IA:', error); + if (!interaction.deferred && !interaction.replied) { + await interaction.reply({ + content: '❌ Error limpiando el cache del sistema de IA.', + flags: MessageFlags.Ephemeral + }); + } + } + } +}; diff --git a/src/components/buttons/aiConfig.ts b/src/components/buttons/aiConfig.ts new file mode 100644 index 0000000..e026772 --- /dev/null +++ b/src/components/buttons/aiConfig.ts @@ -0,0 +1,136 @@ +import logger from "../../core/lib/logger"; +import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js'; + +export default { + customId: 'ai_config', + run: async (interaction: ButtonInteraction) => { + // Verificar permisos de administrador + if (!interaction.memberPermissions?.has(PermissionFlagsBits.Administrator)) { + return interaction.reply({ + content: '❌ No tienes permisos de administrador para usar este botón.', + flags: MessageFlags.Ephemeral + }); + } + + try { + await interaction.deferUpdate(); + + // Panel de configuración detallada + // @ts-ignore + const configPanel = { + type: 17, + accent_color: 0x3498DB, + components: [ + { + type: 10, + content: '## ⚙️ Configuración del Sistema de IA' + }, + { + type: 10, + content: '-# Ajustes avanzados y configuración del servicio Gemini-chan.' + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: `## 🔧 Configuración Actual +\`\`\`yaml +# Límites de Rate Limiting +rate_limit_max: 20 # requests por minuto por usuario +rate_limit_window: 60000 # ventana en milisegundos (1 min) +cooldown_ms: 3000 # cooldown entre requests (3 seg) + +# Configuración de Tokens +max_input_tokens: 1048576 # 1M tokens entrada (Gemini 2.5 Flash) +max_output_tokens: 8192 # 8K tokens salida +token_reset_threshold: 0.80 # reset al 80% del límite + +# Gestión de Memoria +max_conversation_age: 1800000 # 30 minutos (en ms) +max_message_history: 8 # mensajes por conversación +cleanup_interval: 300000 # limpieza cada 5 minutos + +# Procesamiento +max_concurrent_requests: 3 # requests simultáneos +request_timeout: 30000 # timeout de 30 segundos +max_image_requests: 3 # límite de requests de imagen + +# Modelo IA +model: "gemini-1.5-flash" # modelo de Google AI +temperature: 0.7 # creatividad de respuestas +top_p: 0.85 # diversidad de tokens +top_k: 40 # límite de candidatos +\`\`\` + +## 🔄 Opciones Disponibles` + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: "📊 **Ver logs del sistema** en tiempo real" } + ], + accessory: { + type: 2, + style: 2, + emoji: "📊", + label: 'Ver Logs', + custom_id: 'ai_view_logs' + } + }, + { + type: 9, + components: [ + { type: 10, content: "🔧 **Cambiar configuración** de rate limits y timeouts" } + ], + accessory: { + type: 2, + style: 2, + emoji: "🔧", + label: 'Configurar', + custom_id: 'ai_modify_config' + } + }, + { + type: 9, + components: [ + { type: 10, content: "🧪 **Modo de prueba** para testing del sistema" } + ], + accessory: { + type: 2, + style: 2, + emoji: "🧪", + label: 'Modo Test', + custom_id: 'ai_test_mode' + } + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: "🔙 Volver al panel principal de administración" } + ], + accessory: { + type: 2, + style: 1, + emoji: "🔙", + label: 'Volver al Panel', + custom_id: 'ai_refresh_stats' + } + } + ] + }; + + await interaction.message.edit({ components: [configPanel] }); + logger.info(`Panel de configuración de IA accedido por ${interaction.user.username} (${interaction.user.id})`); + + } catch (error) { + logger.error('Error mostrando configuración de IA:', error); + if (!interaction.deferred && !interaction.replied) { + await interaction.reply({ + content: '❌ Error accediendo a la configuración del sistema de IA.', + flags: MessageFlags.Ephemeral + }); + } + } + } +}; diff --git a/src/components/buttons/aiFullReset.ts b/src/components/buttons/aiFullReset.ts new file mode 100644 index 0000000..b82f7c3 --- /dev/null +++ b/src/components/buttons/aiFullReset.ts @@ -0,0 +1,134 @@ +import logger from "../../core/lib/logger"; +import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js'; +import { aiService } from '../../core/services/AIService'; + +const OWNER_ID = '327207082203938818'; // Solo el dueño puede hacer reset completo + +export default { + customId: 'ai_full_reset', + run: async (interaction: ButtonInteraction) => { + // Verificar que sea el dueño del bot (reset completo es crítico) + if (interaction.user.id !== OWNER_ID) { + return interaction.reply({ + content: '❌ Solo el dueño del bot puede realizar un reset completo del sistema de IA.', + flags: MessageFlags.Ephemeral + }); + } + + try { + await interaction.deferUpdate(); + + // Obtener estadísticas antes del reset + const statsBefore = aiService.getStats(); + const conversationsCleared = statsBefore.activeConversations; + const requestsCleared = statsBefore.queueLength; + + // Aquí irían las funciones reales de reset del servicio + // Por ejemplo: + // aiService.fullReset(); + // aiService.clearAllConversations(); + // aiService.clearRequestQueue(); + // aiService.resetStatistics(); + + const resetTimestamp = new Date().toISOString().replace('T', ' ').split('.')[0]; + + // Panel de confirmación de reset completo + // @ts-ignore + const resetCompletePanel = { + type: 17, + accent_color: 0xFF4444, + components: [ + { + type: 10, + content: '## ⚠️ RESET COMPLETO EJECUTADO' + }, + { + type: 10, + content: '-# El sistema de IA ha sido completamente reiniciado.' + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: `## 🔄 Resumen del Reset +\`\`\` +┌─────────────────────────┬─────────────┐ +│ Elemento Limpiado │ Cantidad │ +├─────────────────────────┼─────────────┤ +│ Conversaciones │ ${conversationsCleared.toString().padEnd(11)} │ +│ Requests en Cola │ ${requestsCleared.toString().padEnd(11)} │ +│ Cache de Memoria │ ✅ Limpiado │ +│ Estadísticas │ ✅ Reset │ +│ Rate Limits │ ✅ Reset │ +│ Configuración │ ✅ Default │ +└─────────────────────────┴─────────────┘ + +🔄 Estado: Sistema completamente reiniciado +⏰ Timestamp: ${resetTimestamp} UTC +👤 Ejecutado por: ${interaction.user.username} +🆔 User ID: ${interaction.user.id} + +⚠️ ADVERTENCIA: Todas las conversaciones activas + han sido eliminadas permanentemente. +\`\`\`` + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: `## ✅ Sistema Restaurado + +El sistema de IA ha vuelto a su estado inicial: +• **Memoria limpia** - Sin conversaciones previas +• **Queue vacía** - Sin requests pendientes +• **Rate limits reset** - Límites restablecidos +• **Configuración default** - Valores originales +• **Cache limpio** - Memoria optimizada + +El sistema está listo para recibir nuevas consultas.` + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: "🔙 Volver al panel principal (con datos reset)" } + ], + accessory: { + type: 2, + style: 1, + emoji: "🔙", + label: 'Volver al Panel', + custom_id: 'ai_refresh_stats' + } + }, + { + type: 9, + components: [ + { type: 10, content: "⚠️ **REALIZAR OTRO RESET** (solo si es necesario)" } + ], + accessory: { + type: 2, + style: 4, + emoji: "⚠️", + label: 'Reset Nuevamente', + custom_id: 'ai_full_reset' + } + } + ] + }; + + await interaction.message.edit({ components: [resetCompletePanel] }); + + // Log crítico del reset completo + logger.warn(`🚨 RESET COMPLETO DE IA ejecutado por ${interaction.user.username} (${interaction.user.id})`); + logger.info(`Reset stats - Conversaciones: ${conversationsCleared}, Queue: ${requestsCleared}, Timestamp: ${resetTimestamp}`); + + } catch (error) { + logger.error('Error ejecutando reset completo de IA:', error); + if (!interaction.deferred && !interaction.replied) { + await interaction.reply({ + content: '❌ Error crítico ejecutando el reset completo del sistema de IA.', + flags: MessageFlags.Ephemeral + }); + } + } + } +}; diff --git a/src/components/buttons/aiRefreshStats.ts b/src/components/buttons/aiRefreshStats.ts new file mode 100644 index 0000000..de65c8b --- /dev/null +++ b/src/components/buttons/aiRefreshStats.ts @@ -0,0 +1,172 @@ +import logger from "../../core/lib/logger"; +import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js'; + +/** + * Formatear tiempo de actividad + */ +function formatUptime(seconds: number): string { + const days = Math.floor(seconds / 86400); + const hours = Math.floor((seconds % 86400) / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + + if (days > 0) return `${days}d ${hours}h ${minutes}m`; + if (hours > 0) return `${hours}h ${minutes}m`; + return `${minutes}m`; +} + +/** + * Formatear bytes a formato legible + */ +function formatBytesMB(bytes: number): string { + return (bytes / 1024 / 1024).toFixed(1) + 'MB'; +} + +/** + * Construir panel de administración de IA actualizado + */ +function buildRefreshedAIPanel() { + const { aiService } = require('../../core/services/AIService'); + const stats = aiService.getStats(); + const uptime = process.uptime(); + const memoryUsage = process.memoryUsage(); + const now = new Date(); + const ts = now.toISOString().replace('T', ' ').split('.')[0]; + + // Estados del sistema + const queueStatus = stats.queueLength === 0 ? '🟢 Normal' : + stats.queueLength < 5 ? '🟡 Ocupado' : '🔴 Saturado'; + const memoryStatus = memoryUsage.heapUsed / memoryUsage.heapTotal > 0.8 ? '🔴 Alta' : '🟢 Normal'; + + const rss = formatBytesMB(memoryUsage.rss); + const heapUsed = formatBytesMB(memoryUsage.heapUsed); + const heapTotal = formatBytesMB(memoryUsage.heapTotal); + const external = formatBytesMB(memoryUsage.external); + + // @ts-ignore + return { + type: 17, + accent_color: 0xFF69B4, + components: [ + { + type: 10, + content: '## 🌸 Panel de Administración - Gemini-chan (Actualizado)' + }, + { + type: 10, + content: '-# Estadísticas refrescadas automáticamente.' + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: `🔄 **Conversaciones Activas:** ${stats.activeConversations}` } + ], + accessory: { + type: 2, + style: 1, + emoji: "🧹", + label: 'Limpiar Cache', + custom_id: 'ai_clear_cache' + } + }, + { + type: 9, + components: [ + { type: 10, content: `📊 **Requests en Cola:** ${stats.queueLength} | **Estado:** ${queueStatus}` } + ], + accessory: { + type: 2, + style: 1, + emoji: "🔄", + label: 'Refrescar Stats', + custom_id: 'ai_refresh_stats' + } + }, + { + type: 9, + components: [ + { type: 10, content: `⏱️ **Total Requests:** ${stats.totalRequests} | **Uptime:** ${formatUptime(uptime)}` } + ], + accessory: { + type: 2, + style: 2, + emoji: "🔧", + label: 'Configuración', + custom_id: 'ai_config' + } + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 10, + content: ` ## 🧠 Uso de Memoria del Sistema IA +\`\`\` +┌─────────────────┬──────────────┬──────────┐ +│ Memory Type │ Usage │ Status │ +├─────────────────┼──────────────┼──────────┤ +│ RSS │ ${rss.padEnd(12)} │ Normal │ +│ Heap Used │ ${heapUsed.padEnd(12)} │ ${memoryStatus.padEnd(8)} │ +│ Heap Total │ ${heapTotal.padEnd(12)} │ Normal │ +│ External │ ${external.padEnd(12)} │ Normal │ +└─────────────────┴──────────────┴──────────┘ + +📈 Configuración Actual: +• Rate Limit: 20 req/min por usuario +• Cooldown: 3 segundos entre requests +• Max Tokens: 1M entrada / 8K salida +• Max Concurrent: 3 requests simultáneos +• Modelo: gemini-1.5-flash +\`\`\` +🔄 Última actualización: ${ts} UTC + +⚠️ **Nota:** El sistema se resetea automáticamente cada 30 minutos para optimizar memoria.` + }, + { type: 14, divider: true, spacing: 1 }, + { + type: 9, + components: [ + { type: 10, content: "<:Sup_urg:1420535068056748042> **REINICIAR** todo el sistema de IA (limpia cache, conversaciones y estadísticas)" } + ], + accessory: { + type: 2, + style: 4, + emoji: "⚠️", + label: 'RESET COMPLETO', + custom_id: 'ai_full_reset' + } + } + ] + }; +} + +export default { + customId: 'ai_refresh_stats', + run: async (interaction: ButtonInteraction) => { + // Verificar permisos de administrador + if (!interaction.memberPermissions?.has(PermissionFlagsBits.Administrator)) { + return interaction.reply({ + content: '❌ No tienes permisos de administrador para usar este botón.', + flags: MessageFlags.Ephemeral + }); + } + + try { + await interaction.deferUpdate(); + + // Refrescar y reconstruir el panel con datos actualizados + const refreshedPanel = buildRefreshedAIPanel(); + + await interaction.message.edit({ components: [refreshedPanel] }); + logger.info(`Estadísticas de IA refrescadas por ${interaction.user.username} (${interaction.user.id})`); + + } catch (error) + //@ts-ignore + logger.error('Error refrescando estadísticas de IA:', error); + if (!interaction.deferred && !interaction.replied) { + await interaction.reply({ + content: '❌ Error refrescando las estadísticas del sistema de IA.', + flags: MessageFlags.Ephemeral + }); + } + } + } +}; diff --git a/src/core/services/AIService.ts b/src/core/services/AIService.ts index d1b832f..a17fd32 100644 --- a/src/core/services/AIService.ts +++ b/src/core/services/AIService.ts @@ -216,7 +216,7 @@ export class AIService { // Usar la API correcta de Google Generative AI const model = this.genAI.getGenerativeModel({ - model: "gemini-2.5-flash", + model: "gemini-2.5-flash-preview-09-2025", generationConfig: { maxOutputTokens: Math.min(this.config.maxOutputTokens, Math.max(1024, estimatedTokens * 0.5)), temperature: 0.7,