feat: integrate modern GenAI SDK for image generation and enhance image handling in AI requests
This commit is contained in:
@@ -227,56 +227,23 @@ export const command: CommandMessage = {
|
||||
|
||||
// Verificar si hay imágenes adjuntas
|
||||
const attachments = Array.from(message.attachments.values());
|
||||
const hasImages = attachments.length > 0 && aiService.hasImageAttachments?.(attachments);
|
||||
const hasImages = attachments.length > 0 && aiService.hasImageAttachments(attachments);
|
||||
|
||||
// Usar el nuevo método con memoria persistente y soporte para imágenes
|
||||
if (hasImages) {
|
||||
// Agregar información sobre las imágenes a los metadatos
|
||||
const imageInfo = attachments
|
||||
.filter(att => att.contentType?.startsWith('image/') ||
|
||||
['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'].some(ext =>
|
||||
att.name?.toLowerCase().endsWith(ext)))
|
||||
.map(att => `${att.name} (${att.contentType || 'imagen'})`)
|
||||
.join(', ');
|
||||
|
||||
const enhancedMeta = messageMeta + (imageInfo ? ` | Imágenes adjuntas: ${imageInfo}` : '');
|
||||
|
||||
// Usar método específico para imágenes
|
||||
const request = {
|
||||
userId,
|
||||
guildId,
|
||||
channelId: message.channel.id,
|
||||
prompt: prompt.trim(),
|
||||
priority: 'normal' as const,
|
||||
timestamp: Date.now(),
|
||||
aiRolePrompt: undefined,
|
||||
meta: enhancedMeta,
|
||||
messageId: message.id,
|
||||
referencedMessageId,
|
||||
attachments: attachments,
|
||||
client: message.client
|
||||
};
|
||||
|
||||
// Procesar con imágenes
|
||||
aiResponse = await new Promise((resolve, reject) => {
|
||||
request.resolve = resolve;
|
||||
request.reject = reject;
|
||||
aiService.requestQueue.push(request as any);
|
||||
});
|
||||
} else {
|
||||
// Método normal sin imágenes
|
||||
aiResponse = await aiService.processAIRequestWithMemory(
|
||||
userId,
|
||||
prompt,
|
||||
guildId,
|
||||
message.channel.id,
|
||||
message.id,
|
||||
referencedMessageId,
|
||||
message.client,
|
||||
'normal',
|
||||
{ meta: messageMeta }
|
||||
);
|
||||
}
|
||||
// Usar el método unificado con memoria persistente y soporte para imágenes
|
||||
aiResponse = await aiService.processAIRequestWithMemory(
|
||||
userId,
|
||||
prompt,
|
||||
guildId,
|
||||
message.channel.id,
|
||||
message.id,
|
||||
referencedMessageId,
|
||||
message.client,
|
||||
'normal',
|
||||
{
|
||||
meta: messageMeta + (hasImages ? ` | Tiene ${attachments.length} imagen(es) adjunta(s)` : ''),
|
||||
attachments: hasImages ? attachments : undefined
|
||||
}
|
||||
);
|
||||
|
||||
// Reemplazar :nombre: por el tag real del emoji, evitando bloques de código
|
||||
if (emojiNames.length > 0) {
|
||||
|
||||
62
src/commands/messages/AI/image.ts
Normal file
62
src/commands/messages/AI/image.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { CommandMessage } from "../../../core/types/commands";
|
||||
import { aiService } from "../../../core/services/AIService";
|
||||
import logger from "../../../core/lib/logger";
|
||||
|
||||
function parseSizeArg(arg?: string): 'square' | 'portrait' | 'landscape' {
|
||||
if (!arg) return 'square';
|
||||
const v = arg.toLowerCase();
|
||||
if (v === 'square' || v === 'cuadrado' || v === '1:1') return 'square';
|
||||
if (v === 'portrait' || v === 'vertical' || v === '9:16') return 'portrait';
|
||||
if (v === 'landscape' || v === 'horizontal' || v === '16:9') return 'landscape';
|
||||
return 'square';
|
||||
}
|
||||
|
||||
export const command: CommandMessage = {
|
||||
name: 'aiimg',
|
||||
type: 'message',
|
||||
aliases: ['img', 'imagen'],
|
||||
cooldown: 5,
|
||||
description: 'Genera una imagen con Gemini (gemini-2.5-flash-image).',
|
||||
category: 'IA',
|
||||
usage: 'aiimg [square|portrait|landscape] <prompt>',
|
||||
run: async (message, args) => {
|
||||
try {
|
||||
if (!args || args.length === 0) {
|
||||
await message.reply({
|
||||
content: 'Uso: aiimg [square|portrait|landscape] <prompt>\nEjemplo: aiimg portrait un gato astronauta'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let size: 'square' | 'portrait' | 'landscape' = 'square';
|
||||
let prompt = args.join(' ').trim();
|
||||
|
||||
// Si el primer arg es un tamaño válido, usarlo y quitarlo del prompt
|
||||
const maybeSize = parseSizeArg(args[0]);
|
||||
if (maybeSize !== 'square' || ['square', 'cuadrado', '1:1'].includes(args[0]?.toLowerCase?.() ?? '')) {
|
||||
// Detect explicit size keyword; if first arg matches any known size token, shift it
|
||||
if (['square','cuadrado','1:1','portrait','vertical','9:16','landscape','horizontal','16:9'].includes(args[0].toLowerCase())) {
|
||||
size = maybeSize;
|
||||
prompt = args.slice(1).join(' ').trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (!prompt) {
|
||||
await message.reply({ content: 'El prompt no puede estar vacío.' });
|
||||
return;
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
await message.channel.sendTyping().catch(() => {});
|
||||
const result = await aiService.generateImage(prompt, { size });
|
||||
|
||||
await message.reply({
|
||||
content: `✅ Imagen generada (${size}).`,
|
||||
files: [{ attachment: result.data, name: result.fileName }]
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error('Error generando imagen:', error);
|
||||
await message.reply({ content: `❌ Error generando imagen: ${error?.message || 'Error desconocido'}` });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -172,7 +172,7 @@ export const command: CommandMessage = {
|
||||
]
|
||||
};
|
||||
|
||||
const panelMessage = await message.reply({ flags: 32768, components: [helpPanel, categorySelectRow, exportRow] });
|
||||
const panelMessage = await message.reply({ flags: 32768, components: [helpPanel, categorySelectRow] });
|
||||
|
||||
const collector = panelMessage.createMessageComponentCollector({
|
||||
time: 600000,
|
||||
|
||||
Reference in New Issue
Block a user