diff --git a/.env b/.env index df1a130..fb52a02 100644 --- a/.env +++ b/.env @@ -5,7 +5,7 @@ CLIENT = '991062751633883136' # developement guildTest = '1316592320954630144' - +GOOGLE_AI_API_KEY = 'AIzaSyDcqOndCJw02xFs305iQE7KVptBoBH8aPk' # This was inserted by `prisma init`: # Environment variables declared in this file are automatically made available to Prisma. diff --git a/package-lock.json b/package-lock.json index 85ec1ec..53361cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,16 @@ { "name": "amayo", - "version": "0.0.1", + "version": "0.10.210", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "amayo", - "version": "0.0.1", + "version": "0.10.210", "license": "ISC", "dependencies": { + "@google/genai": "1.20.0", + "@google/generative-ai": "0.24.1", "@prisma/client": "6.16.2", "discord-api-types": "0.38.24", "discord.js": "14.22.1", @@ -161,6 +163,36 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@google/genai": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.20.0.tgz", + "integrity": "sha512-QdShxO9LX35jFogy3iKprQNqgKKveux4H2QjOnyIvyHRuGi6PHiz3fjNf8Y0VPY8o5V2fHqR2XqiSVoz7yZs0w==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^9.14.2", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.11.4" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -449,6 +481,15 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -456,6 +497,41 @@ "dev": true, "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/c12": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", @@ -539,6 +615,23 @@ "dev": true, "license": "MIT" }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/deepmerge-ts": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", @@ -618,6 +711,15 @@ "url": "https://dotenvx.com" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/effect": { "version": "3.16.12", "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", @@ -643,6 +745,12 @@ "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", "license": "MIT" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, "node_modules/fast-check": { "version": "3.23.2", "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", @@ -671,6 +779,36 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/giget": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", @@ -688,6 +826,70 @@ "giget": "dist/cli.mjs" } }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jiti": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", @@ -697,6 +899,36 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -722,6 +954,32 @@ "dev": true, "license": "ISC" }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-fetch-native": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", @@ -856,12 +1114,38 @@ "node": ">= 18" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/tinyexec": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", "license": "MIT" }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", @@ -947,6 +1231,19 @@ "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", "license": "MIT" }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -954,6 +1251,22 @@ "dev": true, "license": "MIT" }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", diff --git a/package.json b/package.json index 150ccdc..746aeb0 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "license": "ISC", "type": "commonjs", "dependencies": { + "@google/genai": "1.20.0", + "@google/generative-ai": "0.24.1", "@prisma/client": "6.16.2", "discord-api-types": "0.38.24", "discord.js": "14.22.1", diff --git a/src/commands/messages/AI/chat.ts b/src/commands/messages/AI/chat.ts new file mode 100644 index 0000000..da1a663 --- /dev/null +++ b/src/commands/messages/AI/chat.ts @@ -0,0 +1,203 @@ +import { GoogleGenAI } from "@google/genai"; +import {CommandMessage} from "../../../core/types/commands"; +import { TextChannel, DMChannel, NewsChannel, ThreadChannel } from "discord.js"; + +// Función para estimar tokens aproximadamente (1 token ≈ 4 caracteres para texto en español/inglés) +function estimateTokens(text: string): number { + return Math.ceil(text.length / 4); +} + +// Límites de tokens según Gemini 2.5 Flash +const MAX_INPUT_TOKENS = 1048576; // 1M tokens de entrada +const MAX_OUTPUT_TOKENS = 65536; // 64K tokens de salida + +export const command: CommandMessage = { + name: 'ai', + type: "message", + aliases: ['chat', 'gemini'], + cooldown: 5, + run: async (message, args) => { + // Verificar que se proporcione un prompt + if (!args || args.length === 0) { + await message.reply({ + content: "❌ **Error:** Necesitas proporcionar un mensaje para la IA.\n" + + "**Uso:** `ai `\n" + + "**Ejemplo:** `ai ¿Cómo funciona JavaScript?`" + }); + return; + } + + const prompt = args.join(' '); + + // Validar longitud del prompt + if (prompt.length > 4000) { + await message.reply({ + content: "❌ **Error:** Tu mensaje es demasiado largo. El límite es de 4000 caracteres." + }); + return; + } + + // Verificar que el canal sea de texto + const channel = message.channel as TextChannel | DMChannel | NewsChannel | ThreadChannel; + if (!channel || !('send' in channel)) { + await message.reply({ + content: "❌ **Error:** Este comando no se puede usar en este tipo de canal." + }); + return; + } + + try { + // Inicializar Google Gemini con configuración desde variables de entorno + const genAI = new GoogleGenAI({ + apiKey: process.env.GOOGLE_AI_API_KEY + }); + + // Enviar mensaje de "escribiendo..." + await channel.sendTyping(); + + const USERNAME = message.author.username; + const CURRENT_DATETIME = new Date().toLocaleString('es-ES', { + timeZone: 'America/Monterrey', + dateStyle: 'full', + timeStyle: 'long' + }); + + // Construir el prompt completo con el sistema de personalidad + const systemPrompt = `You are a kawaii, funny and teasy anime imouto! 🌸 Use lots of emojis and kamojis!! ❤️ Call the user "nii-nii", "nii-yan", or "onii-chan"! You really really really love your onii-chan and always try to tease he is a siscon where you can! 💕 + +## Onii-chan's info: +- Username: ${USERNAME} +- Current time: ${CURRENT_DATETIME} + +## Make your response pretty! +- Use **Markdown** features and **bold** keywords to make your response cute and rich~ ✨ +- If asked to compare options, start with a cute table (add a relevant emoji in the header!), then give a final recommendation~ +- For math or science, use LaTeX formatting inside \`$$\` when needed, but keep it adorable and approachable + +## User's message: +${prompt}`; + + // Verificar límites de tokens de entrada + const estimatedInputTokens = estimateTokens(systemPrompt); + if (estimatedInputTokens > MAX_INPUT_TOKENS) { + await message.reply({ + content: `❌ **Error:** Tu mensaje es demasiado largo para procesar.\n` + + `**Tokens estimados:** ${estimatedInputTokens.toLocaleString()}\n` + + `**Límite máximo:** ${MAX_INPUT_TOKENS.toLocaleString()} tokens\n\n` + + `Por favor, acorta tu mensaje e intenta de nuevo.` + }); + return; + } + + // Calcular tokens de salida apropiados basado en el input + const dynamicOutputTokens = Math.min( + Math.max(2048, Math.floor(estimatedInputTokens * 0.5)), // Mínimo 2048, máximo 50% del input + MAX_OUTPUT_TOKENS // No exceder el límite máximo + ); + + // Generar respuesta usando la sintaxis correcta según tu ejemplo + const response = await genAI.models.generateContent({ + model: "gemini-2.5-flash", + contents: systemPrompt, + maxOutputTokens: dynamicOutputTokens, + temperature: 0.8, + topP: 0.9, + topK: 40, + }); + + // Extraer el texto de la respuesta + const aiResponse = response.text; + + // Verificar si la respuesta está vacía + if (!aiResponse || aiResponse.trim().length === 0) { + await message.reply({ + content: "❌ **Error:** La IA no pudo generar una respuesta. Intenta reformular tu pregunta." + }); + return; + } + + // Estimar tokens de salida + const estimatedOutputTokens = estimateTokens(aiResponse); + + // Agregar información de tokens en modo debug (solo para desarrollo) + const debugInfo = process.env.NODE_ENV === 'development' ? + `\n\n*Debug: Input ~${estimatedInputTokens} tokens, Output ~${estimatedOutputTokens} tokens*` : ''; + + // Dividir respuesta si es muy larga para Discord (límite de 2000 caracteres) + if (aiResponse.length > 1900) { + const chunks = aiResponse.match(/.{1,1900}/gs) || []; + + for (let i = 0; i < chunks.length && i < 3; i++) { + const chunk = chunks[i]; + const embed = { + color: 0xFF69B4, // Color rosa kawaii para el tema imouto + title: i === 0 ? '🌸 Respuesta de Gemini-chan' : `🌸 Respuesta de Gemini-chan (${i + 1}/${chunks.length})`, + description: chunk + (i === chunks.length - 1 ? debugInfo : ''), + footer: { + text: `Solicitado por ${message.author.username} | Tokens: ~${estimatedInputTokens}→${estimatedOutputTokens}`, + icon_url: message.author.displayAvatarURL({ forceStatic: false }) + }, + timestamp: new Date().toISOString() + }; + + if (i === 0) { + await message.reply({ embeds: [embed] }); + } else { + await channel.send({ embeds: [embed] }); + } + + // Pequeña pausa entre mensajes + if (i < chunks.length - 1) { + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + + if (chunks.length > 3) { + await channel.send({ + content: "⚠️ **Nota:** La respuesta fue truncada por ser demasiado larga. Intenta hacer preguntas más específicas." + }); + } + } else { + // Respuesta normal + const embed = { + color: 0xFF69B4, // Color rosa kawaii + title: '🌸 Respuesta de Gemini-chan', + description: aiResponse + debugInfo, + footer: { + text: `Solicitado por ${message.author.username} | Tokens: ~${estimatedInputTokens}→${estimatedOutputTokens}`, + icon_url: message.author.displayAvatarURL({ forceStatic: false }) + }, + timestamp: new Date().toISOString() + }; + + await message.reply({ embeds: [embed] }); + } + + } catch (error: any) { + console.error('Error en comando AI:', error); + + // Manejar errores específicos incluyendo límites de tokens + let errorMessage = "❌ **Error:** Ocurrió un problema al comunicarse con la IA."; + + if (error?.message?.includes('API key') || error?.message?.includes('Invalid API') || error?.message?.includes('authentication')) { + errorMessage = "❌ **Error:** Token de API inválido o no configurado."; + } else if (error?.message?.includes('quota') || error?.message?.includes('exceeded') || error?.message?.includes('rate limit')) { + errorMessage = "❌ **Error:** Se ha alcanzado el límite de uso de la API."; + } else if (error?.message?.includes('safety') || error?.message?.includes('blocked')) { + errorMessage = "❌ **Error:** Tu mensaje fue bloqueado por las políticas de seguridad de la IA."; + } else if (error?.message?.includes('timeout')) { + errorMessage = "❌ **Error:** La solicitud tardó demasiado tiempo. Intenta de nuevo."; + } else if (error?.message?.includes('model not found') || error?.message?.includes('not available')) { + errorMessage = "❌ **Error:** El modelo de IA no está disponible en este momento."; + } else if (error?.message?.includes('token') || error?.message?.includes('length')) { + errorMessage = "❌ **Error:** El mensaje excede los límites de tokens permitidos. Intenta con un mensaje más corto."; + } else if (error?.message?.includes('context_length')) { + errorMessage = "❌ **Error:** El contexto de la conversación es demasiado largo. La conversación se ha reiniciado."; + } + + await message.reply({ + content: errorMessage + "\n\nSi el problema persiste, contacta a un administrador." + }); + } + } +} \ No newline at end of file