← back to Wallco Ai
scripts/autoid-drunk-batch.js
74 lines
#!/usr/bin/env node
// Drunk-aware Auto-ID batch — NON-DESTRUCTIVE (flags only).
// Calls the drunk-aware /api/admin/cactus/:id/auto-id endpoint for N
// drunk-animals designs. That endpoint runs Gemini vision (No bottle /
// Not animals / Poor edges / Cartoonish) and PERSISTS the dotted-box
// findings to the bad_examples learning corpus. This script just drives it
// across a batch and tallies the breakdown. No publish/delete/deploy.
//
// Usage: node scripts/autoid-drunk-batch.js [--limit 30] [--concurrency 4]
// [--base http://127.0.0.1:9905] [--include-flagged]
const { execSync } = require('child_process');
const arg = (k, d) => {
const i = process.argv.indexOf('--' + k);
if (i === -1) return d;
const v = process.argv[i + 1];
return (v && !v.startsWith('--')) ? v : true;
};
const LIMIT = parseInt(arg('limit', '30'), 10);
const CONC = parseInt(arg('concurrency', '4'), 10);
const BASE = String(arg('base', 'http://127.0.0.1:9905'));
const INCLUDE_FLAGGED = !!arg('include-flagged', false);
const DB = process.env.WALLCO_DB || 'dw_unified';
// Prefer designs not yet auto-flagged (find NEW defects); --include-flagged
// re-scans everything. Published drunk-animals with a real file on disk.
const notFlagged = INCLUDE_FLAGGED ? '' : 'AND be.boxes IS NULL ';
const sql =
"SELECT d.id FROM all_designs d " +
"LEFT JOIN bad_examples be ON be.design_id=d.id " +
"WHERE d.category ILIKE '%drunk%' AND d.is_published=TRUE " +
"AND d.local_path IS NOT NULL " + notFlagged +
"ORDER BY d.id LIMIT " + LIMIT;
const ids = execSync(`psql -d ${DB} -tAc "${sql}"`, { encoding: 'utf8' })
.trim().split('\n').map(s => parseInt(s, 10)).filter(Boolean);
console.log(`[autoid-drunk] scanning ${ids.length} drunk-animals via ${BASE} (conc ${CONC})`);
if (!ids.length) { console.log('nothing to scan'); process.exit(0); }
const tally = {};
const flagged = [];
let idx = 0, done = 0;
async function worker() {
while (idx < ids.length) {
const id = ids[idx++];
try {
const r = await fetch(`${BASE}/api/admin/cactus/${id}/auto-id`);
if (!r.ok) { tally.err = (tally.err || 0) + 1; done++; continue; }
const j = await r.json();
const labels = [...new Set((j.candidates || []).map(b => b.label).filter(Boolean))];
if (labels.length) {
flagged.push({ id, labels });
labels.forEach(l => { tally[l] = (tally[l] || 0) + 1; });
} else {
tally.clean = (tally.clean || 0) + 1;
}
} catch (e) {
tally.err = (tally.err || 0) + 1;
}
done++;
if (done % 5 === 0) process.stderr.write(` ..${done}/${ids.length}\n`);
}
}
Promise.all(Array.from({ length: CONC }, worker)).then(() => {
console.log('\n=== Auto-ID breakdown (' + ids.length + ' drunk-animals) ===');
console.log('labels:', JSON.stringify(tally));
console.log('flagged ' + flagged.length + ' designs:');
flagged.forEach(f => console.log(' #' + f.id + ' ' + f.labels.join(', ')));
console.log('\n(boxes persisted to bad_examples — non-destructive, fates undecided)');
});