// One-off script: pull every Validation Set image that had at least one // mismatched field (or failed to scan entirely) out of // sources/product-test-images-fixed/ into sources/product-test-images-undetected/, // renamed to show which field(s) missed, plus a manifest.md with // expected-vs-predicted per field — so a human can tell at a glance whether // a miss is an OCR problem, a classification problem, or the photo itself // lacking the data (e.g. expiry code out of frame). // Usage: node scripts/build-undetected-set.mjs import fs from "fs"; import path from "path"; const detailPath = process.argv[2]; if (!detailPath) { console.error("Usage: node scripts/build-undetected-set.mjs "); process.exit(1); } const FIXED_DIR = path.join("sources", "product-test-images-fixed"); const OUT_DIR = path.join("sources", "product-test-images-undetected"); const detail = JSON.parse(fs.readFileSync(detailPath, "utf8")); if (fs.existsSync(OUT_DIR)) fs.rmSync(OUT_DIR, { recursive: true }); fs.mkdirSync(OUT_DIR, { recursive: true }); const manifestRows = []; let copied = 0; for (const item of detail.validation) { const failedFields = item.checks.filter((c) => !c.match); if (!failedFields.length) continue; const ext = path.extname(item.filename); const base = path.basename(item.filename, ext); const tag = failedFields.map((c) => c.field).join(","); const destName = `${base} [FAIL ${tag}]${ext}`; fs.copyFileSync(path.join(FIXED_DIR, item.filename), path.join(OUT_DIR, destName)); copied++; for (const c of item.checks) { manifestRows.push({ image: destName, field: c.field, match: c.match, expected: c.expected || "(empty)", predicted: c.predicted || "(empty — not detected)" }); } } for (const f of detail.failed) { const srcPath = path.join(FIXED_DIR, f.filename); if (!fs.existsSync(srcPath)) continue; const ext = path.extname(f.filename); const base = path.basename(f.filename, ext); const destName = `${base} [FAILED-scan]${ext}`; fs.copyFileSync(srcPath, path.join(OUT_DIR, destName)); copied++; manifestRows.push({ image: destName, field: "(entire scan)", match: false, expected: "-", predicted: `ERROR: ${f.error}` }); } const lines = [ "# Undetected / mismatched images", "", `Generated ${detail.timestamp} from the accuracy-check-scan.mts detail dump.`, `${copied} of ${detail.validation.length + detail.failed.length} Validation Set images had at least one wrong/missing field or failed to scan.`, "", "| Image | Field | OK? | Expected | Predicted |", "|---|---|---|---|---|" ]; for (const r of manifestRows) { lines.push(`| ${r.image} | ${r.field} | ${r.match ? "✓" : "✗"} | ${r.expected} | ${r.predicted} |`); } fs.writeFileSync(path.join(OUT_DIR, "manifest.md"), lines.join("\n") + "\n", "utf8"); console.log(`Copied ${copied} images into ${OUT_DIR}, wrote manifest.md (${manifestRows.length} rows).`);