bhcto.com

content_round3.js

// Round 3 — Editorial polish. Prompt = round2/<slug>.md + editorial mandate.
// Writes final/<slug>.md and a final/index.md.  node content_round3.js [--slug s] [--limit N]

const fs = require("fs");
const path = require("path");
const { parseBriefs } = require("./lib/briefs");
const { probeModel, runRound } = require("./lib/batch");
const P = require("./lib/prompts");
const { cleanArticle } = require("./lib/clean");

const R2 = path.join(__dirname, "round2");
const OUT = path.join(__dirname, "final");

function arg(name) {
  const i = process.argv.indexOf(`--${name}`);
  return i >= 0 ? process.argv[i + 1] : null;
}
function readMaybe(p) {
  try {
    return fs.readFileSync(p, "utf8");
  } catch {
    return null;
  }
}

async function main() {
  fs.mkdirSync(OUT, { recursive: true });
  const { standingRules, briefs } = parseBriefs();
  let items = briefs;
  if (arg("slug")) items = briefs.filter((b) => b.slug === arg("slug"));
  else if (arg("limit")) items = briefs.slice(0, Number(arg("limit")));

  items = items.filter((b) => {
    const has = fs.existsSync(path.join(R2, `${b.slug}.md`));
    if (!has) console.warn(`  (skip ${b.slug}: no round2 draft)`);
    return has;
  });
  if (!items.length) {
    console.error("No round-2 drafts found. Run content_round2.js first.");
    process.exit(1);
  }

  const model = await probeModel();
  console.log(`Round 3: polishing ${items.length} post(s) with ${model}`);

  const sys3 = P.round3System(standingRules);
  const results = await runRound(model, items, (brief) => ({
    system: sys3,
    userContent: P.round3User(readMaybe(path.join(R2, `${brief.slug}.md`))),
    max_tokens: 16000,
  }));

  let ok = 0;
  const index = ["# Northern Illinois Recovery Tier A — Final Posts", ""];
  for (const b of items) {
    const r = results.get(b.slug);
    if (r && r.ok) {
      fs.writeFileSync(path.join(OUT, `${b.slug}.md`), cleanArticle(r.text));
      index.push(`- [${b.workingTitle}](${b.slug}.md) — \`${b.targetKeyword}\``);
      console.log(`  ✓ ${b.slug} (${r.model})`);
      ok++;
    } else {
      console.warn(`  ✗ ${b.slug} — ${r ? r.error || r.stop_reason : "no result"}`);
    }
  }
  fs.writeFileSync(path.join(OUT, "index.md"), index.join("\n") + "\n");
  console.log(`\nRound 3 done: ${ok}/${items.length} final posts written to final/ (+ index.md).`);
}

main().catch((e) => {
  console.error("FATAL:", e.stack || e);
  process.exit(1);
});