← back to Ventura Corridor

src/jobs/regen_thin.ts

46 lines

/**
 * Identify magazine_features with thin editorial (<MIN_LEN chars) and
 * call /api/magazine/:id/regen to refresh them via Mac1 Ollama.
 *
 *   $ npx tsx src/jobs/regen_thin.ts          # rescue all thin features
 *   $ npx tsx src/jobs/regen_thin.ts 20       # max 20
 */
import 'dotenv/config';
import { pool, query } from '../../db/pool.ts';

const N_MAX = parseInt(process.argv.find(a => /^\d+$/.test(a)) || '50', 10);
const MIN_LEN = parseInt(process.env.MIN_LEN || '200', 10);
const SERVER = process.env.VC_URL || 'http://127.0.0.1:9780';
const AUTH = 'Basic ' + Buffer.from('admin:DWSecure2024!').toString('base64');

async function main() {
  const r = await query(
    `SELECT id, length(editorial) AS len, headline FROM magazine_features
     WHERE editorial IS NULL OR length(editorial) < $1
     ORDER BY generated_at ASC
     LIMIT $2`,
    [MIN_LEN, N_MAX]
  );
  console.log(`[regen_thin] ${r.rowCount} features below ${MIN_LEN} chars to refresh`);
  let ok = 0, fail = 0;
  for (const row of r.rows) {
    try {
      const t0 = Date.now();
      const resp = await fetch(`${SERVER}/api/magazine/${row.id}/regen`, {
        method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: AUTH }
      });
      if (!resp.ok) throw new Error(`${resp.status}: ${(await resp.text()).slice(0, 100)}`);
      const j = await resp.json();
      console.log(`  ✓ ${row.id} (${row.len || 0}ch → fresh, ${Date.now() - t0}ms) "${(j.headline || '').slice(0, 50)}"`);
      ok++;
    } catch (e: any) {
      console.log(`  ✕ ${row.id} (${row.len || 0}ch) — ${e.message.slice(0, 80)}`);
      fail++;
    }
  }
  console.log(`[regen_thin] ok=${ok} fail=${fail}`);
  await pool.end();
}

main().catch(e => { console.error(e); process.exit(1); });