feat: refactor admin panel interactions to use Discord.js 14.22.1 API with enhanced ownership checks and updated UI components
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
import { CommandMessage } from "../../../core/types/commands";
|
import { CommandMessage } from "../../../core/types/commands";
|
||||||
import { PermissionFlagsBits } from "discord.js";
|
import { ContainerBuilder, TextDisplayBuilder, SectionBuilder, ButtonBuilder, ButtonStyle, MessageFlags } from "discord.js";
|
||||||
import { aiService } from "../../../core/services/AIService";
|
import { aiService } from "../../../core/services/AIService";
|
||||||
import logger from "../../../core/lib/logger";
|
import logger from "../../../core/lib/logger";
|
||||||
|
|
||||||
const OWNER_ID = '327207082203938818';
|
const OWNER_ID = '327207082203938818';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formatear tiempo de actividad
|
* Formatear tiempo de actividad
|
||||||
*/
|
*/
|
||||||
@@ -24,7 +26,7 @@ function formatBytesMB(bytes: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construir panel de administración de IA
|
* Construir panel de administración de IA usando la API REAL de Discord.js 14.22.1
|
||||||
*/
|
*/
|
||||||
function buildAIAdminPanel() {
|
function buildAIAdminPanel() {
|
||||||
const stats = aiService.getStats();
|
const stats = aiService.getStats();
|
||||||
@@ -43,63 +45,53 @@ function buildAIAdminPanel() {
|
|||||||
const heapTotal = formatBytesMB(memoryUsage.heapTotal);
|
const heapTotal = formatBytesMB(memoryUsage.heapTotal);
|
||||||
const external = formatBytesMB(memoryUsage.external);
|
const external = formatBytesMB(memoryUsage.external);
|
||||||
|
|
||||||
// @ts-ignore
|
// Crear texto de header
|
||||||
return {
|
const headerText = new TextDisplayBuilder()
|
||||||
type: 17,
|
.setContent('## 🌸 Panel de Administración - Gemini-chan\n-# Gestiona el sistema de IA y monitorea estadísticas en tiempo real.');
|
||||||
accent_color: 0xFF69B4,
|
|
||||||
components: [
|
// Crear secciones con estadísticas
|
||||||
{
|
const statsSection1 = new SectionBuilder()
|
||||||
type: 10,
|
.addTextDisplayComponents(
|
||||||
content: '## 🌸 Panel de Administración - Gemini-chan'
|
new TextDisplayBuilder()
|
||||||
},
|
.setContent(`🔄 **Conversaciones Activas:** ${stats.activeConversations}`)
|
||||||
{
|
)
|
||||||
type: 10,
|
.setButtonAccessory(
|
||||||
content: '-# Gestiona el sistema de IA y monitorea estadísticas en tiempo real.'
|
new ButtonBuilder()
|
||||||
},
|
.setCustomId('ai_clear_cache')
|
||||||
{ type: 14, divider: true, spacing: 1 },
|
.setLabel('Limpiar Cache')
|
||||||
{
|
.setEmoji('🧹')
|
||||||
type: 9,
|
.setStyle(ButtonStyle.Primary)
|
||||||
components: [
|
);
|
||||||
{ type: 10, content: `🔄 **Conversaciones Activas:** ${stats.activeConversations}` }
|
|
||||||
],
|
const statsSection2 = new SectionBuilder()
|
||||||
accessory: {
|
.addTextDisplayComponents(
|
||||||
type: 2,
|
new TextDisplayBuilder()
|
||||||
style: 1,
|
.setContent(`📊 **Requests en Cola:** ${stats.queueLength} | **Estado:** ${queueStatus}`)
|
||||||
emoji: "🧹",
|
)
|
||||||
label: 'Limpiar Cache',
|
.setButtonAccessory(
|
||||||
custom_id: 'ai_clear_cache'
|
new ButtonBuilder()
|
||||||
}
|
.setCustomId('ai_refresh_stats')
|
||||||
},
|
.setLabel('Refrescar Stats')
|
||||||
{
|
.setEmoji('🔄')
|
||||||
type: 9,
|
.setStyle(ButtonStyle.Primary)
|
||||||
components: [
|
);
|
||||||
{ type: 10, content: `📊 **Requests en Cola:** ${stats.queueLength} | **Estado:** ${queueStatus}` }
|
|
||||||
],
|
const configSection = new SectionBuilder()
|
||||||
accessory: {
|
.addTextDisplayComponents(
|
||||||
type: 2,
|
new TextDisplayBuilder()
|
||||||
style: 1,
|
.setContent(`⏱️ **Total Requests:** ${stats.totalRequests} | **Uptime:** ${formatUptime(uptime)}`)
|
||||||
emoji: "🔄",
|
)
|
||||||
label: 'Refrescar Stats',
|
.setButtonAccessory(
|
||||||
custom_id: 'ai_refresh_stats'
|
new ButtonBuilder()
|
||||||
}
|
.setCustomId('ai_config')
|
||||||
},
|
.setLabel('Configuración')
|
||||||
{
|
.setEmoji('🔧')
|
||||||
type: 9,
|
.setStyle(ButtonStyle.Secondary)
|
||||||
components: [
|
);
|
||||||
{ type: 10, content: `⏱️ **Total Requests:** ${stats.totalRequests} | **Uptime:** ${formatUptime(uptime)}` }
|
|
||||||
],
|
// Texto de memoria
|
||||||
accessory: {
|
const memoryText = new TextDisplayBuilder()
|
||||||
type: 2,
|
.setContent(`## 🧠 Uso de Memoria del Sistema IA
|
||||||
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 │
|
│ Memory Type │ Usage │ Status │
|
||||||
@@ -110,33 +102,32 @@ function buildAIAdminPanel() {
|
|||||||
│ External │ ${external.padEnd(12)} │ Normal │
|
│ External │ ${external.padEnd(12)} │ Normal │
|
||||||
└─────────────────┴──────────────┴──────────┘
|
└─────────────────┴──────────────┴──────────┘
|
||||||
|
|
||||||
📈 Configuración Actual:
|
📈 Configuración: 20 req/min | 3s cooldown | 1M/8K tokens | 3 concurrent
|
||||||
• 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
|
🔄 Última actualización: ${ts} UTC`);
|
||||||
|
|
||||||
⚠️ **Nota:** El sistema se resetea automáticamente cada 30 minutos para optimizar memoria.`
|
// Sección de reset
|
||||||
},
|
const resetSection = new SectionBuilder()
|
||||||
{ type: 14, divider: true, spacing: 1 },
|
.addTextDisplayComponents(
|
||||||
{
|
new TextDisplayBuilder()
|
||||||
type: 9,
|
.setContent("**REINICIAR** todo el sistema de IA")
|
||||||
components: [
|
)
|
||||||
{ type: 10, content: "<:Sup_urg:1420535068056748042> **REINICIAR** todo el sistema de IA (limpia cache, conversaciones y estadísticas)" }
|
.setButtonAccessory(
|
||||||
],
|
new ButtonBuilder()
|
||||||
accessory: {
|
.setCustomId('ai_full_reset')
|
||||||
type: 2,
|
.setLabel('RESET COMPLETO')
|
||||||
style: 4,
|
.setEmoji('⚠️')
|
||||||
emoji: "⚠️",
|
.setStyle(ButtonStyle.Danger)
|
||||||
label: 'RESET COMPLETO',
|
);
|
||||||
custom_id: 'ai_full_reset'
|
|
||||||
}
|
// Construir container principal
|
||||||
}
|
const container = new ContainerBuilder()
|
||||||
]
|
.addTextDisplayComponents(headerText)
|
||||||
};
|
.addSectionComponents(statsSection1, statsSection2, configSection)
|
||||||
|
.addTextDisplayComponents(memoryText)
|
||||||
|
.addSectionComponents(resetSection);
|
||||||
|
|
||||||
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const command: CommandMessage = {
|
export const command: CommandMessage = {
|
||||||
@@ -144,13 +135,13 @@ export const command: CommandMessage = {
|
|||||||
type: "message",
|
type: "message",
|
||||||
aliases: ['ai-stats', 'ai-info', 'ai-panel'],
|
aliases: ['ai-stats', 'ai-info', 'ai-panel'],
|
||||||
cooldown: 5,
|
cooldown: 5,
|
||||||
description: 'Panel de administración del sistema de IA (Solo administradores)',
|
description: 'Panel de administración del sistema de IA (Solo el dueño)',
|
||||||
category: 'Administración',
|
category: 'Administración',
|
||||||
usage: 'aistats [reset]',
|
usage: 'aistats [reset]',
|
||||||
run: async (message, args) => {
|
run: async (message, args) => {
|
||||||
// Verificar permisos de administrador
|
// Verificar que sea el dueño del bot (MUY CRÍTICO)
|
||||||
if (message.author.id !== OWNER_ID) {
|
if (message.author.id !== OWNER_ID) {
|
||||||
await message.reply({ content: '❌ No tienes permisos para usar este panel.' });
|
await message.reply({ content: '❌ Solo el dueño del bot puede usar este panel administrativo.' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,32 +150,17 @@ export const command: CommandMessage = {
|
|||||||
|
|
||||||
// Reset del sistema si se solicita
|
// Reset del sistema si se solicita
|
||||||
if (action === 'reset') {
|
if (action === 'reset') {
|
||||||
// @ts-ignore
|
const resetContainer = new ContainerBuilder()
|
||||||
const resetPanel = {
|
.addTextDisplayComponents(
|
||||||
type: 17,
|
new TextDisplayBuilder()
|
||||||
accent_color: 0x00FF00,
|
.setContent('## ✅ Sistema de IA Reiniciado\nLas estadísticas, cache y conversaciones han sido limpiados exitosamente.\n\n🔄 **Estado:** Sistema reiniciado\n⏰ **Timestamp:** ' + new Date().toISOString().replace('T', ' ').split('.')[0] + ' UTC\n👤 **Dueño:** ' + message.author.username)
|
||||||
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({
|
await message.reply({
|
||||||
flags: 32768,
|
components: [resetContainer],
|
||||||
components: [resetPanel]
|
flags: MessageFlags.IsComponentsV2
|
||||||
});
|
});
|
||||||
logger.info(`Sistema de IA reiniciado por ${message.author.username} (${message.author.id})`);
|
logger.info(`Sistema de IA reiniciado por el dueño ${message.author.username} (${message.author.id})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,38 +168,26 @@ export const command: CommandMessage = {
|
|||||||
const adminPanel = buildAIAdminPanel();
|
const adminPanel = buildAIAdminPanel();
|
||||||
|
|
||||||
await message.reply({
|
await message.reply({
|
||||||
flags: 32768,
|
components: [adminPanel],
|
||||||
components: [adminPanel]
|
flags: MessageFlags.IsComponentsV2
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.error('Error obteniendo estadísticas de IA:', error);
|
logger.error('Error obteniendo estadísticas de IA:', error);
|
||||||
|
|
||||||
// @ts-ignore
|
const errorContainer = new ContainerBuilder()
|
||||||
const errorPanel = {
|
.addTextDisplayComponents(
|
||||||
type: 17,
|
new TextDisplayBuilder()
|
||||||
accent_color: 0xFF4444,
|
.setContent('## ❌ Error del Sistema\nNo se pudieron obtener las estadísticas del sistema de IA.\n\n**Error:** ' + (error.message || 'Error desconocido') + '\n**Timestamp:** ' + new Date().toISOString())
|
||||||
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({
|
await message.reply({
|
||||||
flags: 32768,
|
components: [errorContainer],
|
||||||
components: [errorPanel]
|
flags: MessageFlags.IsComponentsV2
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exportar función para reutilizar en botones
|
||||||
|
export { buildAIAdminPanel };
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import logger from "../../core/lib/logger";
|
import logger from "../../core/lib/logger";
|
||||||
import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js';
|
import { ButtonInteraction, MessageFlags, ContainerBuilder, TextDisplayBuilder, SectionBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||||
import { aiService } from '../../core/services/AIService';
|
import { aiService } from '../../core/services/AIService';
|
||||||
|
|
||||||
|
const OWNER_ID = '327207082203938818'; // Solo el dueño puede usar este panel
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
customId: 'ai_clear_cache',
|
customId: 'ai_clear_cache',
|
||||||
run: async (interaction: ButtonInteraction) => {
|
run: async (interaction: ButtonInteraction) => {
|
||||||
// Verificar permisos de administrador
|
// Verificar que sea el dueño del bot (CRÍTICO)
|
||||||
if (!interaction.memberPermissions?.has(PermissionFlagsBits.Administrator)) {
|
if (interaction.user.id !== OWNER_ID) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: '❌ No tienes permisos de administrador para usar este botón.',
|
content: '❌ Solo el dueño del bot puede usar este panel administrativo.',
|
||||||
flags: MessageFlags.Ephemeral
|
flags: MessageFlags.Ephemeral
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -16,52 +18,42 @@ export default {
|
|||||||
try {
|
try {
|
||||||
await interaction.deferUpdate();
|
await interaction.deferUpdate();
|
||||||
|
|
||||||
// Limpiar cache de conversaciones (simular limpieza)
|
// Limpiar cache de conversaciones
|
||||||
const stats = aiService.getStats();
|
const stats = aiService.getStats();
|
||||||
const conversationsCleared = stats.activeConversations;
|
const conversationsCleared = stats.activeConversations;
|
||||||
|
|
||||||
// Aquí podrías agregar lógica real para limpiar el cache
|
// Aquí iría la lógica real de limpieza:
|
||||||
// Por ejemplo: aiService.clearConversations();
|
// aiService.clearAllConversations();
|
||||||
|
|
||||||
// @ts-ignore
|
// Crear container de éxito usando la API real
|
||||||
const successPanel = {
|
const successContainer = new ContainerBuilder()
|
||||||
type: 17,
|
.addTextDisplayComponents(
|
||||||
accent_color: 0x00FF00,
|
new TextDisplayBuilder()
|
||||||
components: [
|
.setContent('## 🧹 Cache Limpiado Exitosamente\n-# Se han limpiado ' + conversationsCleared + ' conversaciones activas.\n\n✅ **Estado:** Cache limpiado\n🔄 **Conversaciones eliminadas:** ' + conversationsCleared + '\n⏰ **Timestamp:** ' + new Date().toISOString().replace('T', ' ').split('.')[0] + ' UTC\n👤 **Dueño:** ' + interaction.user.username)
|
||||||
{
|
)
|
||||||
type: 10,
|
.addSectionComponents(
|
||||||
content: '## 🧹 Cache Limpiado Exitosamente'
|
new SectionBuilder()
|
||||||
},
|
.addTextDisplayComponents(
|
||||||
{
|
new TextDisplayBuilder()
|
||||||
type: 10,
|
.setContent("🔙 Volver al panel principal de administración")
|
||||||
content: `-# Se han limpiado ${conversationsCleared} conversaciones activas.`
|
)
|
||||||
},
|
.setButtonAccessory(
|
||||||
{ type: 14, divider: true, spacing: 1 },
|
new ButtonBuilder()
|
||||||
{
|
.setCustomId('ai_refresh_stats')
|
||||||
type: 10,
|
.setLabel('Volver al Panel')
|
||||||
content: `✅ **Estado:** Cache limpiado\n🔄 **Conversaciones eliminadas:** ${conversationsCleared}\n⏰ **Timestamp:** ${new Date().toISOString().replace('T', ' ').split('.')[0]} UTC\n👤 **Administrador:** ${interaction.user.username}`
|
.setEmoji('🔙')
|
||||||
},
|
.setStyle(ButtonStyle.Primary)
|
||||||
{ 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] });
|
await interaction.message.edit({
|
||||||
logger.info(`Cache de IA limpiado por ${interaction.user.username} (${interaction.user.id})`);
|
components: [successContainer],
|
||||||
|
flags: MessageFlags.IsComponentsV2
|
||||||
|
});
|
||||||
|
logger.info(`Cache de IA limpiado por el dueño ${interaction.user.username} (${interaction.user.id})`);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
//@ts-ignore
|
||||||
logger.error('Error limpiando cache de IA:', error);
|
logger.error('Error limpiando cache de IA:', error);
|
||||||
if (!interaction.deferred && !interaction.replied) {
|
if (!interaction.deferred && !interaction.replied) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import logger from "../../core/lib/logger";
|
import logger from "../../core/lib/logger";
|
||||||
import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js';
|
import { ButtonInteraction, MessageFlags, ContainerBuilder, TextDisplayBuilder, SectionBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||||
|
|
||||||
|
const OWNER_ID = '327207082203938818'; // Solo el dueño puede usar este panel
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
customId: 'ai_config',
|
customId: 'ai_config',
|
||||||
run: async (interaction: ButtonInteraction) => {
|
run: async (interaction: ButtonInteraction) => {
|
||||||
// Verificar permisos de administrador
|
// Verificar que sea el dueño del bot (CRÍTICO)
|
||||||
if (!interaction.memberPermissions?.has(PermissionFlagsBits.Administrator)) {
|
if (interaction.user.id !== OWNER_ID) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: '❌ No tienes permisos de administrador para usar este botón.',
|
content: '❌ Solo el dueño del bot puede usar este panel administrativo.',
|
||||||
flags: MessageFlags.Ephemeral
|
flags: MessageFlags.Ephemeral
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -15,24 +17,14 @@ export default {
|
|||||||
try {
|
try {
|
||||||
await interaction.deferUpdate();
|
await interaction.deferUpdate();
|
||||||
|
|
||||||
// Panel de configuración detallada
|
// Panel de configuración usando la API real de Discord.js 14.22.1
|
||||||
// @ts-ignore
|
const configContainer = new ContainerBuilder()
|
||||||
const configPanel = {
|
.addTextDisplayComponents(
|
||||||
type: 17,
|
new TextDisplayBuilder()
|
||||||
accent_color: 0x3498DB,
|
.setContent(`## ⚙️ Configuración del Sistema de IA
|
||||||
components: [
|
-# Ajustes avanzados y configuración del servicio Gemini-chan.
|
||||||
{
|
|
||||||
type: 10,
|
## 🔧 Configuración Actual
|
||||||
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
|
\`\`\`yaml
|
||||||
# Límites de Rate Limiting
|
# Límites de Rate Limiting
|
||||||
rate_limit_max: 20 # requests por minuto por usuario
|
rate_limit_max: 20 # requests por minuto por usuario
|
||||||
@@ -59,71 +51,31 @@ model: "gemini-1.5-flash" # modelo de Google AI
|
|||||||
temperature: 0.7 # creatividad de respuestas
|
temperature: 0.7 # creatividad de respuestas
|
||||||
top_p: 0.85 # diversidad de tokens
|
top_p: 0.85 # diversidad de tokens
|
||||||
top_k: 40 # límite de candidatos
|
top_k: 40 # límite de candidatos
|
||||||
\`\`\`
|
\`\`\``)
|
||||||
|
)
|
||||||
|
.addSectionComponents(
|
||||||
|
new SectionBuilder()
|
||||||
|
.addTextDisplayComponents(
|
||||||
|
new TextDisplayBuilder()
|
||||||
|
.setContent("🔙 Volver al panel principal de administración")
|
||||||
|
)
|
||||||
|
.setButtonAccessory(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId('ai_refresh_stats')
|
||||||
|
.setLabel('Volver al Panel')
|
||||||
|
.setEmoji('🔙')
|
||||||
|
.setStyle(ButtonStyle.Primary)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
## 🔄 Opciones Disponibles`
|
await interaction.message.edit({
|
||||||
},
|
components: [configContainer],
|
||||||
{ type: 14, divider: true, spacing: 1 },
|
flags: MessageFlags.IsComponentsV2
|
||||||
{
|
});
|
||||||
type: 9,
|
logger.info(`Panel de configuración de IA accedido por el dueño ${interaction.user.username} (${interaction.user.id})`);
|
||||||
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) {
|
} catch (error) {
|
||||||
|
//@ts-ignore
|
||||||
logger.error('Error mostrando configuración de IA:', error);
|
logger.error('Error mostrando configuración de IA:', error);
|
||||||
if (!interaction.deferred && !interaction.replied) {
|
if (!interaction.deferred && !interaction.replied) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import logger from "../../core/lib/logger";
|
import logger from "../../core/lib/logger";
|
||||||
import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js';
|
import { ButtonInteraction, MessageFlags, ContainerBuilder, TextDisplayBuilder, SectionBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||||
import { aiService } from '../../core/services/AIService';
|
import { aiService } from '../../core/services/AIService';
|
||||||
|
|
||||||
const OWNER_ID = '327207082203938818'; // Solo el dueño puede hacer reset completo
|
const OWNER_ID = '327207082203938818'; // Solo el dueño puede hacer reset completo
|
||||||
@@ -7,7 +7,7 @@ const OWNER_ID = '327207082203938818'; // Solo el dueño puede hacer reset compl
|
|||||||
export default {
|
export default {
|
||||||
customId: 'ai_full_reset',
|
customId: 'ai_full_reset',
|
||||||
run: async (interaction: ButtonInteraction) => {
|
run: async (interaction: ButtonInteraction) => {
|
||||||
// Verificar que sea el dueño del bot (reset completo es crítico)
|
// Verificar que sea el dueño del bot (reset completo es CRÍTICO)
|
||||||
if (interaction.user.id !== OWNER_ID) {
|
if (interaction.user.id !== OWNER_ID) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: '❌ Solo el dueño del bot puede realizar un reset completo del sistema de IA.',
|
content: '❌ Solo el dueño del bot puede realizar un reset completo del sistema de IA.',
|
||||||
@@ -23,8 +23,7 @@ export default {
|
|||||||
const conversationsCleared = statsBefore.activeConversations;
|
const conversationsCleared = statsBefore.activeConversations;
|
||||||
const requestsCleared = statsBefore.queueLength;
|
const requestsCleared = statsBefore.queueLength;
|
||||||
|
|
||||||
// Aquí irían las funciones reales de reset del servicio
|
// Aquí irían las funciones reales de reset del servicio:
|
||||||
// Por ejemplo:
|
|
||||||
// aiService.fullReset();
|
// aiService.fullReset();
|
||||||
// aiService.clearAllConversations();
|
// aiService.clearAllConversations();
|
||||||
// aiService.clearRequestQueue();
|
// aiService.clearRequestQueue();
|
||||||
@@ -32,24 +31,14 @@ export default {
|
|||||||
|
|
||||||
const resetTimestamp = new Date().toISOString().replace('T', ' ').split('.')[0];
|
const resetTimestamp = new Date().toISOString().replace('T', ' ').split('.')[0];
|
||||||
|
|
||||||
// Panel de confirmación de reset completo
|
// Panel de confirmación de reset completo usando la API real
|
||||||
// @ts-ignore
|
const resetCompleteContainer = new ContainerBuilder()
|
||||||
const resetCompletePanel = {
|
.addTextDisplayComponents(
|
||||||
type: 17,
|
new TextDisplayBuilder()
|
||||||
accent_color: 0xFF4444,
|
.setContent(`## ⚠️ RESET COMPLETO EJECUTADO
|
||||||
components: [
|
-# El sistema de IA ha sido completamente reiniciado.
|
||||||
{
|
|
||||||
type: 10,
|
## 🔄 Resumen del Reset
|
||||||
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 │
|
│ Elemento Limpiado │ Cantidad │
|
||||||
@@ -69,12 +58,9 @@ export default {
|
|||||||
|
|
||||||
⚠️ ADVERTENCIA: Todas las conversaciones activas
|
⚠️ ADVERTENCIA: Todas las conversaciones activas
|
||||||
han sido eliminadas permanentemente.
|
han sido eliminadas permanentemente.
|
||||||
\`\`\``
|
\`\`\`
|
||||||
},
|
|
||||||
{ type: 14, divider: true, spacing: 1 },
|
## ✅ Sistema Restaurado
|
||||||
{
|
|
||||||
type: 10,
|
|
||||||
content: `## ✅ Sistema Restaurado
|
|
||||||
|
|
||||||
El sistema de IA ha vuelto a su estado inicial:
|
El sistema de IA ha vuelto a su estado inicial:
|
||||||
• **Memoria limpia** - Sin conversaciones previas
|
• **Memoria limpia** - Sin conversaciones previas
|
||||||
@@ -83,45 +69,46 @@ El sistema de IA ha vuelto a su estado inicial:
|
|||||||
• **Configuración default** - Valores originales
|
• **Configuración default** - Valores originales
|
||||||
• **Cache limpio** - Memoria optimizada
|
• **Cache limpio** - Memoria optimizada
|
||||||
|
|
||||||
El sistema está listo para recibir nuevas consultas.`
|
El sistema está listo para recibir nuevas consultas.`)
|
||||||
},
|
)
|
||||||
{ type: 14, divider: true, spacing: 1 },
|
.addSectionComponents(
|
||||||
{
|
new SectionBuilder()
|
||||||
type: 9,
|
.addTextDisplayComponents(
|
||||||
components: [
|
new TextDisplayBuilder()
|
||||||
{ type: 10, content: "🔙 Volver al panel principal (con datos reset)" }
|
.setContent("🔙 Volver al panel principal (con datos reset)")
|
||||||
],
|
)
|
||||||
accessory: {
|
.setButtonAccessory(
|
||||||
type: 2,
|
new ButtonBuilder()
|
||||||
style: 1,
|
.setCustomId('ai_refresh_stats')
|
||||||
emoji: "🔙",
|
.setLabel('Volver al Panel')
|
||||||
label: 'Volver al Panel',
|
.setEmoji('🔙')
|
||||||
custom_id: 'ai_refresh_stats'
|
.setStyle(ButtonStyle.Primary)
|
||||||
}
|
),
|
||||||
},
|
new SectionBuilder()
|
||||||
{
|
.addTextDisplayComponents(
|
||||||
type: 9,
|
new TextDisplayBuilder()
|
||||||
components: [
|
.setContent("⚠️ **REALIZAR OTRO RESET** (solo si es necesario)")
|
||||||
{ type: 10, content: "⚠️ **REALIZAR OTRO RESET** (solo si es necesario)" }
|
)
|
||||||
],
|
.setButtonAccessory(
|
||||||
accessory: {
|
new ButtonBuilder()
|
||||||
type: 2,
|
.setCustomId('ai_full_reset')
|
||||||
style: 4,
|
.setLabel('Reset Nuevamente')
|
||||||
emoji: "⚠️",
|
.setEmoji('⚠️')
|
||||||
label: 'Reset Nuevamente',
|
.setStyle(ButtonStyle.Danger)
|
||||||
custom_id: 'ai_full_reset'
|
)
|
||||||
}
|
);
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
await interaction.message.edit({ components: [resetCompletePanel] });
|
await interaction.message.edit({
|
||||||
|
components: [resetCompleteContainer],
|
||||||
|
flags: MessageFlags.IsComponentsV2
|
||||||
|
});
|
||||||
|
|
||||||
// Log crítico del reset completo
|
// Log crítico del reset completo
|
||||||
logger.warn(`🚨 RESET COMPLETO DE IA ejecutado por ${interaction.user.username} (${interaction.user.id})`);
|
logger.warn(`🚨 RESET COMPLETO DE IA ejecutado por el dueño ${interaction.user.username} (${interaction.user.id})`);
|
||||||
logger.info(`Reset stats - Conversaciones: ${conversationsCleared}, Queue: ${requestsCleared}, Timestamp: ${resetTimestamp}`);
|
logger.info(`Reset stats - Conversaciones: ${conversationsCleared}, Queue: ${requestsCleared}, Timestamp: ${resetTimestamp}`);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
//@ts-ignore
|
||||||
logger.error('Error ejecutando reset completo de IA:', error);
|
logger.error('Error ejecutando reset completo de IA:', error);
|
||||||
if (!interaction.deferred && !interaction.replied) {
|
if (!interaction.deferred && !interaction.replied) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
|
|||||||
@@ -1,150 +1,16 @@
|
|||||||
import logger from "../../core/lib/logger";
|
import logger from "../../core/lib/logger";
|
||||||
import { ButtonInteraction, MessageFlags, PermissionFlagsBits } from 'discord.js';
|
import { ButtonInteraction, MessageFlags, ContainerBuilder, TextDisplayBuilder, SectionBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||||
|
import { buildAIAdminPanel } from '../../commands/messages/AI/stats';
|
||||||
|
|
||||||
/**
|
const OWNER_ID = '327207082203938818'; // Solo el dueño puede usar este panel
|
||||||
* 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 {
|
export default {
|
||||||
customId: 'ai_refresh_stats',
|
customId: 'ai_refresh_stats',
|
||||||
run: async (interaction: ButtonInteraction) => {
|
run: async (interaction: ButtonInteraction) => {
|
||||||
// Verificar permisos de administrador
|
// Verificar que sea el dueño del bot (CRÍTICO)
|
||||||
if (!interaction.memberPermissions?.has(PermissionFlagsBits.Administrator)) {
|
if (interaction.user.id !== OWNER_ID) {
|
||||||
return interaction.reply({
|
return interaction.reply({
|
||||||
content: '❌ No tienes permisos de administrador para usar este botón.',
|
content: '❌ Solo el dueño del bot puede usar este panel administrativo.',
|
||||||
flags: MessageFlags.Ephemeral
|
flags: MessageFlags.Ephemeral
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -152,13 +18,16 @@ export default {
|
|||||||
try {
|
try {
|
||||||
await interaction.deferUpdate();
|
await interaction.deferUpdate();
|
||||||
|
|
||||||
// Refrescar y reconstruir el panel con datos actualizados
|
// Reconstruir panel principal con datos actualizados
|
||||||
const refreshedPanel = buildRefreshedAIPanel();
|
const refreshedPanel = buildAIAdminPanel();
|
||||||
|
|
||||||
await interaction.message.edit({ components: [refreshedPanel] });
|
await interaction.message.edit({
|
||||||
logger.info(`Estadísticas de IA refrescadas por ${interaction.user.username} (${interaction.user.id})`);
|
components: [refreshedPanel],
|
||||||
|
flags: MessageFlags.IsComponentsV2
|
||||||
|
});
|
||||||
|
logger.info(`Estadísticas de IA refrescadas por el dueño ${interaction.user.username} (${interaction.user.id})`);
|
||||||
|
|
||||||
} catch (error)
|
} catch (error) {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
logger.error('Error refrescando estadísticas de IA:', error);
|
logger.error('Error refrescando estadísticas de IA:', error);
|
||||||
if (!interaction.deferred && !interaction.replied) {
|
if (!interaction.deferred && !interaction.replied) {
|
||||||
|
|||||||
Reference in New Issue
Block a user