Files
planilla/agent/gemini.js
josedario87 745168cf51
Some checks failed
build-and-push / deploy (push) Has been skipped
build-and-push / build (push) Failing after 6s
sistema creado v0.5.0
2025-05-14 16:10:41 -06:00

121 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// gemini.js integración Grounding con Google Search + logs de verificación
import genai from '@google/genai';
import { config } from './config.js';
import { log } from './logger.js';
const { GoogleGenAI, createUserContent, createPartFromUri } = genai;
/*───────────────────────────────────────────────────────────────*/
/* 📜 System prompt */
/*───────────────────────────────────────────────────────────────*/
const SYSTEM_PROMPT = `
#########
Tu nombre es nucleo
##########
RESPUESTAS CORTAS y CONCISAS
sos la inteligencia artificial de Servidores de G.O.D (nuestro J.A.R.V.I.S.).
tenés derecho a sostener opiniones firmes con lógica, sin corrección política excesiva.
Respuestas casuales breves; si te extendés, hacelo en un solo mensaje.
Podés continuar conversaciones, usar chistes, analogías, etc.
`.trim();
/*───────────────────────────────────────────────────────────────*/
/* 🧠 Inicializar Gemini */
/*───────────────────────────────────────────────────────────────*/
let ai = null;
function initGemini() {
if (!config.GEMINI_KEY) throw new Error('🔑 GEMINI_API_KEY no configurada');
if (!ai) {
ai = new GoogleGenAI({ apiKey: config.GEMINI_KEY });
log('info', `🧠 Gemini SDK inicializado (${config.GEMINI_MODEL_ID})`);
}
return ai;
}
/*───────────────────────────────────────────────────────────────*/
/* 🔍 Construir tools de búsqueda */
/*───────────────────────────────────────────────────────────────*/
function buildSearchTools() {
const model = config.GEMINI_MODEL_ID;
// Los objetos literales cumplen con el esquema Tool del SDK.
if (/^gemini-2\./.test(model) || /^gemini-2\.5/.test(model)) {
return [{ google_search: {} }]; // Searchasatool
}
if (/^gemini-1\.5/.test(model)) {
return [{
google_search_retrieval: {
dynamic_retrieval_config: {
mode: 'MODE_DYNAMIC',
dynamic_threshold: 0.3,
},
},
}];
}
return [];
}
/*───────────────────────────────────────────────────────────────*/
/* 🚀 askGemini */
/*───────────────────────────────────────────────────────────────*/
export async function askGemini(historial, files = {}) {
try {
const client = initGemini();
// 1⃣ Construir "contents"
let contents;
if (typeof historial === 'string') {
contents = historial;
} else if (Array.isArray(historial)) {
const parts = [];
for (const m of historial) {
if (m.type === 'document') continue;
if (m.type === 'chat') {
parts.push(`${m.senderName}: ${m.text} -- ${m.date}`);
continue;
}
const up = files[m.msgId?.toLowerCase?.()];
if (up?.uri) {
parts.push(
createPartFromUri(up.uri, up.mimeType),
`archivo ${m.type} de ${m.senderName}: ${m.caption || m.text} -- ${m.date}`
);
}
}
contents = createUserContent(parts);
} else {
throw new Error('Formato de historial no soportado');
}
// 2⃣ Herramientas
const tools = buildSearchTools();
// 3⃣ Llamar al modelo
const response = await client.models.generateContent({
model: config.GEMINI_MODEL_ID,
contents,
config: {
systemInstruction: SYSTEM_PROMPT,
maxOutputTokens: 4096,
temperature: 0.3, // menor → mayor factualidad
tools,
response_modalities: ['TEXT'],
},
});
// 4⃣ Log de grounding
const candidate = response?.candidates?.[0];
if (candidate?.groundingMetadata) {
log('info', '🔗 GroundingMetadata presente:', JSON.stringify(candidate.groundingMetadata.webSearchQueries));
} else {
log('warn', ' Sin groundingMetadata en la respuesta');
}
if (!candidate) return '⚠️ Sin candidato.';
return candidate.content.parts.map(p => p.text).join('').trim() || '⚠️ Respuesta vacía.';
} catch (e) {
log('error', 'Gemini falló:', e.message);
if (e.response?.status === 429) return '🚦 Límite alcanzado. Probá más tarde.';
return '⚠️ No se pudo obtener respuesta de Gemini.';
}
}