import { config } from "../config/index.js"; import { chatCompletion } from "../services/ollamaClient.js"; import { searchDocs } from "./searchChat.js"; import fs from "node:fs"; function buildContextBlock(hits) { const lines = []; hits.forEach((h, i) => { const header = `# Fonte ${i + 1}${h.source ? ` (${h.source})` : ""}`; lines.push(header); lines.push(h.text); lines.push(""); }); return lines.join("\n").trim(); } export async function answerWithContext({ message, sessionId }) { const hits = await searchDocs({ query: message, topK: config.rag.topK }); const context = buildContextBlock(hits); // #region debug-point D:image-rag-context (() => { let u = "http://127.0.0.1:7777/event"; let s = "image-rag-miss"; try { const e = fs.readFileSync(".dbg/image-rag-miss.env", "utf8"); u = e.match(/DEBUG_SERVER_URL=(.+)/)?.[1] || u; s = e.match(/DEBUG_SESSION_ID=(.+)/)?.[1] || s; } catch {} fetch(u, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ sessionId: s, runId: "post", hypothesisId: "D", location: "api/chat/chatChain.js", msg: "[DEBUG] answerWithContext context built", data: { questionHead: String(message ?? "").slice(0, 140), hits: Array.isArray(hits) ? hits.length : null, contextChars: context.length, topScore: hits?.[0]?.score ?? null, topSource: hits?.[0]?.source ?? null }, ts: Date.now() }) }).catch(() => {}); })(); // #endregion const system = [ "Você é um assistente de atendimento interno de uma empresa.", "Responda apenas com base no CONTEXTO quando ele estiver disponível.", "Se o CONTEXTO não tiver a informação, diga que não encontrou na base da empresa e sugira o que solicitar ao time responsável.", "Seja direto e em português." ].join("\n"); const messages = [ { role: "system", content: system }, ...(context ? [{ role: "system", content: `CONTEXTO:\n${context}` }] : []), ...(sessionId ? [{ role: "system", content: `session_id:${sessionId}` }] : []), { role: "user", content: message } ]; const completion = await chatCompletion({ messages }); return { answer: completion.content, sources: hits.map((h) => ({ id: h.id, source: h.source, score: h.score, chunkIndex: h.chunkIndex, metadata: h.metadata })) }; }