// backfill único: congela o snapshot da IA (Ia*) nos itens do golden set que já estavam // "rotulado" antes do congelamento existir (usa a avaliação atual como aproximação — // não há como recuperar o valor exato de quando cada um foi originalmente rotulado) import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { AtendimentoGoldenLabel } from "../src/models/AtendimentoGoldenLabel.model.js"; import { AtendimentoAvaliacao } from "../src/models/AtendimentoAvaliacao.model.js"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const APLICAR = process.argv.includes("--apply"); const CAMPOS_SNAPSHOT_IA = [ "ScoreAtendente", "JustificativaScore", "Resolvido", "Sentimento", "Resumo", "Sugestoes", "Atendentes", "VisitaAgendada", "HorarioVisitaInformado", "HorarioVisita", "StatusCancelamento", "MotivoCancelamento" ]; async function main() { const alvos = await AtendimentoGoldenLabel.query().where("Status", "rotulado").whereNull("IaSnapshotEm"); console.log(`[backfill-snapshot-golden-set] ${alvos.length} itens rotulados sem snapshot da IA.`); if (alvos.length === 0) { console.log("[backfill-snapshot-golden-set] nada para fazer."); process.exit(0); } const ids = alvos.map((a) => a.AtendimentoId); const avaliacoes = await AtendimentoAvaliacao.query().findByIds(ids); const iaPorId = new Map(avaliacoes.map((a) => [a.AtendimentoId, a])); const semAvaliacaoIa = ids.filter((id) => !iaPorId.has(id)); if (semAvaliacaoIa.length) { console.warn(`[backfill-snapshot-golden-set] ${semAvaliacaoIa.length} atendimento(s) rotulado(s) sem avaliação da IA correspondente (pulados): ${semAvaliacaoIa.join(", ")}`); } const backupDir = path.resolve(__dirname, "logs"); fs.mkdirSync(backupDir, { recursive: true }); const backupPath = path.join(backupDir, `backfill-snapshot-golden-set-${new Date().toISOString().replace(/[:.]/g, "-")}.json`); fs.writeFileSync(backupPath, JSON.stringify(alvos.map((a) => ({ AtendimentoId: a.AtendimentoId })), null, 2)); console.log(`[backfill-snapshot-golden-set] lista de alvos salva em ${backupPath}`); if (!APLICAR) { console.log("[backfill-snapshot-golden-set] dry-run (nenhuma alteração feita). Use --apply para gravar."); process.exit(0); } let feitos = 0; for (const id of ids) { const ia = iaPorId.get(id); if (!ia) continue; const patch = { IaSnapshotEm: new Date() }; for (const campo of CAMPOS_SNAPSHOT_IA) patch[`Ia${campo}`] = ia[campo] ?? null; await AtendimentoGoldenLabel.query().patchAndFetchById(id, patch); feitos += 1; } console.log(`[backfill-snapshot-golden-set] ${feitos} itens com snapshot congelado agora.`); process.exit(0); } main().catch((err) => { console.error("[backfill-snapshot-golden-set] falha fatal:", err); process.exit(1); });