Spaces:
Paused
Paused
| // src/session.js — Estado de atendimento por contato (jornada). | |
| // Mantém: saudação, memória de conversa, coleta de lead e modo "falar com humano". | |
| // É agnóstico ao backend de IA (HF router ou Ollama) — só guarda estado e grava leads. | |
| import { appendFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs'; | |
| import { dirname } from 'node:path'; | |
| const TTL_MS = 1000 * 60 * 60 * 6; // 6h sem interação → contato é tratado como "novo" | |
| const MAX_HISTORY = 8; // últimas 8 mensagens (≈4 trocas) lembradas | |
| // Em produção o volume é montado em /data; localmente usa ../data | |
| export const LEADS_PATH = process.env.AUTH_DIR | |
| ? '/data/leads.jsonl' | |
| : new URL('../data/leads.jsonl', import.meta.url).pathname; | |
| const sessions = new Map(); // jid -> sessão | |
| export function getSession(jid) { | |
| const now = Date.now(); | |
| let s = sessions.get(jid); | |
| if (!s || now - s.lastActivity > TTL_MS) { | |
| s = { greeted: false, stage: 'chat', history: [], lead: {}, paused: false, offeredHuman: false, lastActivity: now }; | |
| sessions.set(jid, s); | |
| } | |
| s.lastActivity = now; | |
| return s; | |
| } | |
| export function remember(s, role, content) { | |
| s.history.push({ role, content }); | |
| if (s.history.length > MAX_HISTORY) s.history.splice(0, s.history.length - MAX_HISTORY); | |
| } | |
| // Bloco curto do histórico recente, para dar contexto a perguntas de seguimento | |
| // ("e quanto custa?"). Injetado na pergunta enviada ao RAG. | |
| export function historyBlock(s) { | |
| if (!s.history.length) return ''; | |
| const recent = s.history.slice(-4); | |
| const lines = recent | |
| .map((m) => `${m.role === 'user' ? 'Cliente' : 'Assistente'}: ${m.content}`) | |
| .join('\n'); | |
| return `Conversa anterior (para dar contexto):\n${lines}\n\n`; | |
| } | |
| export function saveLead(jid, lead, extra = {}) { | |
| const rec = { | |
| ts: new Date().toISOString(), | |
| whatsapp: jid.split('@')[0], | |
| nome: lead.name || '', | |
| contato: lead.phone || '', | |
| interesse: lead.interest || '', | |
| ...extra, | |
| }; | |
| try { | |
| mkdirSync(dirname(LEADS_PATH), { recursive: true }); | |
| appendFileSync(LEADS_PATH, JSON.stringify(rec) + '\n'); | |
| console.log('🟢 Lead salvo:', rec.nome, rec.contato); | |
| } catch (e) { | |
| console.error('Falha ao salvar lead:', e.message); | |
| } | |
| return rec; | |
| } | |
| export function readLeads() { | |
| if (!existsSync(LEADS_PATH)) return []; | |
| return readFileSync(LEADS_PATH, 'utf8') | |
| .split('\n') | |
| .filter(Boolean) | |
| .map((l) => { | |
| try { return JSON.parse(l); } catch { return null; } | |
| }) | |
| .filter(Boolean); | |
| } | |