backfillSnapshotGoldenSet.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // backfill único: congela o snapshot da IA (Ia*) nos itens do golden set que já estavam
  2. // "rotulado" antes do congelamento existir (usa a avaliação atual como aproximação —
  3. // não há como recuperar o valor exato de quando cada um foi originalmente rotulado)
  4. import fs from "node:fs";
  5. import path from "node:path";
  6. import { fileURLToPath } from "node:url";
  7. import { AtendimentoGoldenLabel } from "../src/models/AtendimentoGoldenLabel.model.js";
  8. import { AtendimentoAvaliacao } from "../src/models/AtendimentoAvaliacao.model.js";
  9. const __dirname = path.dirname(fileURLToPath(import.meta.url));
  10. const APLICAR = process.argv.includes("--apply");
  11. const CAMPOS_SNAPSHOT_IA = [
  12. "ScoreAtendente",
  13. "JustificativaScore",
  14. "Resolvido",
  15. "Sentimento",
  16. "Resumo",
  17. "Sugestoes",
  18. "Atendentes",
  19. "VisitaAgendada",
  20. "HorarioVisitaInformado",
  21. "HorarioVisita",
  22. "StatusCancelamento",
  23. "MotivoCancelamento"
  24. ];
  25. async function main() {
  26. const alvos = await AtendimentoGoldenLabel.query().where("Status", "rotulado").whereNull("IaSnapshotEm");
  27. console.log(`[backfill-snapshot-golden-set] ${alvos.length} itens rotulados sem snapshot da IA.`);
  28. if (alvos.length === 0) {
  29. console.log("[backfill-snapshot-golden-set] nada para fazer.");
  30. process.exit(0);
  31. }
  32. const ids = alvos.map((a) => a.AtendimentoId);
  33. const avaliacoes = await AtendimentoAvaliacao.query().findByIds(ids);
  34. const iaPorId = new Map(avaliacoes.map((a) => [a.AtendimentoId, a]));
  35. const semAvaliacaoIa = ids.filter((id) => !iaPorId.has(id));
  36. if (semAvaliacaoIa.length) {
  37. console.warn(`[backfill-snapshot-golden-set] ${semAvaliacaoIa.length} atendimento(s) rotulado(s) sem avaliação da IA correspondente (pulados): ${semAvaliacaoIa.join(", ")}`);
  38. }
  39. const backupDir = path.resolve(__dirname, "logs");
  40. fs.mkdirSync(backupDir, { recursive: true });
  41. const backupPath = path.join(backupDir, `backfill-snapshot-golden-set-${new Date().toISOString().replace(/[:.]/g, "-")}.json`);
  42. fs.writeFileSync(backupPath, JSON.stringify(alvos.map((a) => ({ AtendimentoId: a.AtendimentoId })), null, 2));
  43. console.log(`[backfill-snapshot-golden-set] lista de alvos salva em ${backupPath}`);
  44. if (!APLICAR) {
  45. console.log("[backfill-snapshot-golden-set] dry-run (nenhuma alteração feita). Use --apply para gravar.");
  46. process.exit(0);
  47. }
  48. let feitos = 0;
  49. for (const id of ids) {
  50. const ia = iaPorId.get(id);
  51. if (!ia) continue;
  52. const patch = { IaSnapshotEm: new Date() };
  53. for (const campo of CAMPOS_SNAPSHOT_IA) patch[`Ia${campo}`] = ia[campo] ?? null;
  54. await AtendimentoGoldenLabel.query().patchAndFetchById(id, patch);
  55. feitos += 1;
  56. }
  57. console.log(`[backfill-snapshot-golden-set] ${feitos} itens com snapshot congelado agora.`);
  58. process.exit(0);
  59. }
  60. main().catch((err) => {
  61. console.error("[backfill-snapshot-golden-set] falha fatal:", err);
  62. process.exit(1);
  63. });