84 lines
2.5 KiB
JavaScript
84 lines
2.5 KiB
JavaScript
// handlers.js
|
|
import fs from 'fs/promises';
|
|
import { log } from './logger.js';
|
|
import {
|
|
sendText,
|
|
fetchChatMessages,
|
|
setTypingStatus
|
|
} from './whatsapp.js';
|
|
import { askGemini } from './gemini.js';
|
|
import { processMessage } from './utils/processMessage.js';
|
|
import { saveMedia } from './utils/saveMedia.js'; // ← NUEVO
|
|
|
|
/* carpeta raíz donde saveMedia deja todo */
|
|
const MEDIA_DIR = '/media';
|
|
await fs.mkdir(MEDIA_DIR, { recursive: true });
|
|
|
|
/* Quita campos pesados antes de mandar a Gemini */
|
|
const cleanForGemini = ({ media, reactions, preview, ...rest }) => rest;
|
|
|
|
export async function processIncoming(raw) {
|
|
if (raw.type !== 'chat') await saveMedia(raw);
|
|
|
|
const msg = processMessage(raw);
|
|
const text = msg.text || '';
|
|
|
|
/* ----- comando @nucleo ----- */
|
|
if (/^@nucleo(\s|$)/i.test(text)) {
|
|
setTypingStatus(msg.chatId, true);
|
|
log('info', '🧠 Generando respuesta…');
|
|
|
|
/* 1) historial completo del chat */
|
|
const allraw = await fetchChatMessages(msg.chatId);
|
|
const allMsgs = allraw.map(processMessage);
|
|
|
|
/* 2) recorta contexto a ≤100 kB */
|
|
const context = allMsgs.map(cleanForGemini);
|
|
let json = JSON.stringify(context);
|
|
while (json.length > 100_000 && context.length) {
|
|
context.shift();
|
|
json = JSON.stringify(context);
|
|
}
|
|
|
|
/* 3) prompt */
|
|
const prompt = [
|
|
`Eres el asistente del grupo "${context[0]?.chatName ?? 'chat'}".`,
|
|
`Pregunta del usuario: ${text}`
|
|
, ...context];
|
|
|
|
/* 4) procesa medias y respeta el límite de 20 MB */
|
|
const medias = allraw.filter(m => m.type !== 'chat');
|
|
const settled = await Promise.allSettled(medias.map(saveMedia));
|
|
|
|
const MAX = 20 * 1024 * 1024; // 20 MB
|
|
let total = 0;
|
|
const files = {};
|
|
|
|
for (const r of settled) {
|
|
if (r.status !== 'fulfilled' || !r.value) continue;
|
|
|
|
const [msgId, obj] = Object.entries(r.value)[0];
|
|
let size = Number(obj.sizeBytes || 0);
|
|
|
|
if (!size && obj.filePath) {
|
|
try { size = (await fs.stat(obj.filePath)).size; }
|
|
catch { size = 0; }
|
|
}
|
|
|
|
if (total + size > MAX && total > 0) break;
|
|
|
|
total += size;
|
|
files[msgId] = { uri: obj.uri || obj.filePath, mimeType: obj.mimeType };
|
|
}
|
|
|
|
// log('info', '🧠 Enviando a Gemini...', { files });
|
|
|
|
/* 5) llama a Gemini y responde */
|
|
const respuesta = await askGemini(prompt, files );
|
|
await sendText(msg.chatId, respuesta);
|
|
|
|
setTypingStatus(msg.chatId, false);
|
|
log('info', '🧠 Respuesta enviada');
|
|
}
|
|
}
|