feat: refactor AI admin panel to use plain objects for improved structure and compatibility with Discord API V2
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { CommandMessage } from "../../../core/types/commands";
|
import { CommandMessage } from "../../../core/types/commands";
|
||||||
import { ContainerBuilder, TextDisplayBuilder, SectionBuilder, ButtonBuilder, ButtonStyle, MessageFlags } from "discord.js";
|
import { ComponentType, ButtonStyle } from "discord-api-types/v10";
|
||||||
import { aiService } from "../../../core/services/AIService";
|
import { aiService } from "../../../core/services/AIService";
|
||||||
import logger from "../../../core/lib/logger";
|
import logger from "../../../core/lib/logger";
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ function formatBytesMB(bytes: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construir panel de administración de IA usando la API REAL de Discord.js 14.22.1
|
* Construir panel de administración de IA usando formato de objetos planos
|
||||||
*/
|
*/
|
||||||
function buildAIAdminPanel() {
|
function buildAIAdminPanel() {
|
||||||
const stats = aiService.getStats();
|
const stats = aiService.getStats();
|
||||||
@@ -45,53 +45,53 @@ function buildAIAdminPanel() {
|
|||||||
const heapTotal = formatBytesMB(memoryUsage.heapTotal);
|
const heapTotal = formatBytesMB(memoryUsage.heapTotal);
|
||||||
const external = formatBytesMB(memoryUsage.external);
|
const external = formatBytesMB(memoryUsage.external);
|
||||||
|
|
||||||
// Crear texto de header
|
// Construir panel usando Display Components V2 (objetos planos)
|
||||||
const headerText = new TextDisplayBuilder()
|
return {
|
||||||
.setContent('## 🌸 Panel de Administración - Gemini-chan\n-# Gestiona el sistema de IA y monitorea estadísticas en tiempo real.');
|
type: ComponentType.Container,
|
||||||
|
components: [
|
||||||
// Crear secciones con estadísticas
|
{ type: ComponentType.TextDisplay, content: '## 🌸 Panel de Administración - Gemini-chan\n-# Gestiona el sistema de IA y monitorea estadísticas en tiempo real.' },
|
||||||
const statsSection1 = new SectionBuilder()
|
{
|
||||||
.addTextDisplayComponents(
|
type: ComponentType.Section,
|
||||||
new TextDisplayBuilder()
|
components: [
|
||||||
.setContent(`🔄 **Conversaciones Activas:** ${stats.activeConversations}`)
|
{ type: ComponentType.TextDisplay, content: `🔄 **Conversaciones Activas:** ${stats.activeConversations}` }
|
||||||
)
|
],
|
||||||
.setButtonAccessory(
|
accessory: {
|
||||||
new ButtonBuilder()
|
type: ComponentType.Button,
|
||||||
.setCustomId('ai_clear_cache')
|
custom_id: 'ai_clear_cache',
|
||||||
.setLabel('Limpiar Cache')
|
label: 'Limpiar Cache',
|
||||||
.setEmoji('🧹')
|
emoji: { name: '🧹' },
|
||||||
.setStyle(ButtonStyle.Primary)
|
style: ButtonStyle.Primary
|
||||||
);
|
}
|
||||||
|
},
|
||||||
const statsSection2 = new SectionBuilder()
|
{
|
||||||
.addTextDisplayComponents(
|
type: ComponentType.Section,
|
||||||
new TextDisplayBuilder()
|
components: [
|
||||||
.setContent(`📊 **Requests en Cola:** ${stats.queueLength} | **Estado:** ${queueStatus}`)
|
{ type: ComponentType.TextDisplay, content: `📊 **Requests en Cola:** ${stats.queueLength} | **Estado:** ${queueStatus}` }
|
||||||
)
|
],
|
||||||
.setButtonAccessory(
|
accessory: {
|
||||||
new ButtonBuilder()
|
type: ComponentType.Button,
|
||||||
.setCustomId('ai_refresh_stats')
|
custom_id: 'ai_refresh_stats',
|
||||||
.setLabel('Refrescar Stats')
|
label: 'Refrescar Stats',
|
||||||
.setEmoji('🔄')
|
emoji: { name: '🔄' },
|
||||||
.setStyle(ButtonStyle.Primary)
|
style: ButtonStyle.Primary
|
||||||
);
|
}
|
||||||
|
},
|
||||||
const configSection = new SectionBuilder()
|
{
|
||||||
.addTextDisplayComponents(
|
type: ComponentType.Section,
|
||||||
new TextDisplayBuilder()
|
components: [
|
||||||
.setContent(`⏱️ **Total Requests:** ${stats.totalRequests} | **Uptime:** ${formatUptime(uptime)}`)
|
{ type: ComponentType.TextDisplay, content: `⏱️ **Total Requests:** ${stats.totalRequests} | **Uptime:** ${formatUptime(uptime)}` }
|
||||||
)
|
],
|
||||||
.setButtonAccessory(
|
accessory: {
|
||||||
new ButtonBuilder()
|
type: ComponentType.Button,
|
||||||
.setCustomId('ai_config')
|
custom_id: 'ai_config',
|
||||||
.setLabel('Configuración')
|
label: 'Configuración',
|
||||||
.setEmoji('🔧')
|
emoji: { name: '🔧' },
|
||||||
.setStyle(ButtonStyle.Secondary)
|
style: ButtonStyle.Secondary
|
||||||
);
|
}
|
||||||
|
},
|
||||||
// Texto de memoria
|
{
|
||||||
const memoryText = new TextDisplayBuilder()
|
type: ComponentType.TextDisplay,
|
||||||
.setContent(`## 🧠 Uso de Memoria del Sistema IA
|
content: `## 🧠 Uso de Memoria del Sistema IA
|
||||||
\`\`\`
|
\`\`\`
|
||||||
┌─────────────────┬──────────────┬──────────┐
|
┌─────────────────┬──────────────┬──────────┐
|
||||||
│ Memory Type │ Usage │ Status │
|
│ Memory Type │ Usage │ Status │
|
||||||
@@ -104,30 +104,23 @@ function buildAIAdminPanel() {
|
|||||||
|
|
||||||
📈 Configuración: 20 req/min | 3s cooldown | 1M/8K tokens | 3 concurrent
|
📈 Configuración: 20 req/min | 3s cooldown | 1M/8K tokens | 3 concurrent
|
||||||
\`\`\`
|
\`\`\`
|
||||||
🔄 Última actualización: ${ts} UTC`);
|
🔄 Última actualización: ${ts} UTC`
|
||||||
|
},
|
||||||
// Sección de reset
|
{
|
||||||
const resetSection = new SectionBuilder()
|
type: ComponentType.Section,
|
||||||
.addTextDisplayComponents(
|
components: [
|
||||||
new TextDisplayBuilder()
|
{ type: ComponentType.TextDisplay, content: "**REINICIAR** todo el sistema de IA" }
|
||||||
.setContent("**REINICIAR** todo el sistema de IA")
|
],
|
||||||
)
|
accessory: {
|
||||||
.setButtonAccessory(
|
type: ComponentType.Button,
|
||||||
new ButtonBuilder()
|
custom_id: 'ai_full_reset',
|
||||||
.setCustomId('ai_full_reset')
|
label: 'RESET COMPLETO',
|
||||||
.setLabel('RESET COMPLETO')
|
emoji: { name: '⚠️' },
|
||||||
.setEmoji('⚠️')
|
style: ButtonStyle.Danger
|
||||||
.setStyle(ButtonStyle.Danger)
|
}
|
||||||
);
|
}
|
||||||
|
]
|
||||||
// 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 = {
|
||||||
@@ -150,15 +143,20 @@ export const command: CommandMessage = {
|
|||||||
|
|
||||||
// Reset del sistema si se solicita
|
// Reset del sistema si se solicita
|
||||||
if (action === 'reset') {
|
if (action === 'reset') {
|
||||||
const resetContainer = new ContainerBuilder()
|
const resetPanel = {
|
||||||
.addTextDisplayComponents(
|
type: ComponentType.Container,
|
||||||
new TextDisplayBuilder()
|
components: [
|
||||||
.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)
|
{
|
||||||
);
|
type: ComponentType.TextDisplay,
|
||||||
|
content: '## ✅ 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
await message.reply({
|
await message.reply({
|
||||||
components: [resetContainer],
|
// @ts-ignore - Flag de componentes V2
|
||||||
flags: MessageFlags.IsComponentsV2
|
flags: 32768,
|
||||||
|
components: [resetPanel]
|
||||||
});
|
});
|
||||||
logger.info(`Sistema de IA reiniciado por el dueño ${message.author.username} (${message.author.id})`);
|
logger.info(`Sistema de IA reiniciado por el dueño ${message.author.username} (${message.author.id})`);
|
||||||
return;
|
return;
|
||||||
@@ -168,22 +166,28 @@ export const command: CommandMessage = {
|
|||||||
const adminPanel = buildAIAdminPanel();
|
const adminPanel = buildAIAdminPanel();
|
||||||
|
|
||||||
await message.reply({
|
await message.reply({
|
||||||
components: [adminPanel],
|
// @ts-ignore - Flag de componentes V2
|
||||||
flags: MessageFlags.IsComponentsV2
|
flags: 32768,
|
||||||
|
components: [adminPanel]
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.error('Error obteniendo estadísticas de IA:', error);
|
logger.error('Error obteniendo estadísticas de IA:', error);
|
||||||
|
|
||||||
const errorContainer = new ContainerBuilder()
|
const errorPanel = {
|
||||||
.addTextDisplayComponents(
|
type: ComponentType.Container,
|
||||||
new TextDisplayBuilder()
|
components: [
|
||||||
.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())
|
{
|
||||||
);
|
type: ComponentType.TextDisplay,
|
||||||
|
content: '## ❌ 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()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
await message.reply({
|
await message.reply({
|
||||||
components: [errorContainer],
|
// @ts-ignore - Flag de componentes V2
|
||||||
flags: MessageFlags.IsComponentsV2
|
flags: 32768,
|
||||||
|
components: [errorPanel]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,16 @@ const getGuildIcon = (g?: Guild) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Construye datos de invite similares a la versión previa
|
// Construye datos de invite similares a la versión previa
|
||||||
const getInviteObject = (invite?: Invite) => invite?.guild ? {
|
const getInviteObject = (invite?: Invite) => {
|
||||||
name: invite.guild.name,
|
// En discord.js dev, necesitamos verificar si es GuildInvite
|
||||||
icon: invite.guild.icon ? `https://cdn.discordapp.com/icons/${invite.guild.id}/${invite.guild.icon}.webp?size=256` : ''
|
if (invite && 'guild' in invite && invite.guild) {
|
||||||
} : null;
|
return {
|
||||||
|
name: invite.guild.name,
|
||||||
|
icon: invite.guild.icon ? `https://cdn.discordapp.com/icons/${invite.guild.id}/${invite.guild.icon}.webp?size=256` : ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
// Helper: calcula el rank dentro del servidor para un campo (weeklyPoints / monthlyPoints / totalPoints)
|
// Helper: calcula el rank dentro del servidor para un campo (weeklyPoints / monthlyPoints / totalPoints)
|
||||||
async function computeRankInGuild(
|
async function computeRankInGuild(
|
||||||
|
|||||||
Reference in New Issue
Block a user