rag-whatsapp / src /conversations.js
DHEIVER's picture
feat: salva conversas em log gzip de streaming (~9 bytes/mensagem)
04c5faf
Raw
History Blame Contribute Delete
1.91 kB
// src/conversations.js — Log de conversas comprimido (gzip streaming), ocupa pouquíssimo espaço.
// Um arquivo por dia: AAAA-MM-DD.log.gz. Cada linha: epoch \t telefone \t u|b \t texto.
// Usa um único stream gzip por dia com Z_SYNC_FLUSH: mantém o dicionário de
// compressão entre mensagens (ótima taxa) e grava na hora (sem perder em queda).
import { createWriteStream, mkdirSync } from 'node:fs';
import zlib from 'node:zlib';
const DIR = process.env.AUTH_DIR
? '/data/conversations'
: new URL('../data/conversations', import.meta.url).pathname;
let gz = null; // stream gzip atual
let day = null; // dia (YYYY-MM-DD) do stream aberto
function today() {
return new Date().toISOString().slice(0, 10);
}
function ensureStream() {
const d = today();
if (gz && d === day) return;
if (gz) gz.end(); // vira o dia → fecha o gzip anterior (flush final)
day = d;
mkdirSync(DIR, { recursive: true });
const out = createWriteStream(`${DIR}/${d}.log.gz`, { flags: 'a' }); // append: membros gzip concatenados
gz = zlib.createGzip({ level: 9 });
gz.on('error', (e) => console.error('conv gzip erro:', e.message));
gz.pipe(out);
}
// dir: 'u' (usuário) ou 'b' (bot)
export function logMessage(jid, dir, text) {
try {
ensureStream();
const ts = Math.floor(Date.now() / 1000);
const phone = String(jid).split('@')[0];
const clean = String(text).replace(/\s+/g, ' ').trim();
if (!clean) return;
gz.write(`${ts}\t${phone}\t${dir}\t${clean}\n`);
gz.flush(zlib.constants.Z_SYNC_FLUSH); // grava já, sem resetar o dicionário
} catch (e) {
console.error('log conversa falhou:', e.message);
}
}
export function conversationsDir() {
return DIR;
}
function close() {
try { gz?.end(); } catch { /* noop */ }
}
process.on('SIGTERM', () => { close(); process.exit(0); });
process.on('SIGINT', () => { close(); process.exit(0); });