← back to Wallco Ai

scripts/drunk_monkeys_birds_subdued_batch.js

73 lines

#!/usr/bin/env node
/**
 * Fire N drunk-monkey/bird/botanical-subdued designs through generate_designs.js.
 * Uses the focused prompt builder at drunk_monkeys_birds_subdued_prompts.js.
 * Settlement-gate filtered, errors-tolerant (single bad design ≠ batch kill).
 *
 * Usage:  node scripts/drunk_monkeys_birds_subdued_batch.js [N]   (default 100)
 *
 * Output rows land in dw_unified.spoon_all_designs with
 *   kind='seamless_tile', category='drunk-monkeys-birds-subdued'
 * so this batch is separable from the existing 2,687 'drunk-animals' rows.
 */
const { spawnSync } = require('child_process');
const path = require('path');
const fs = require('fs');
const { buildN } = require('./drunk_monkeys_birds_subdued_prompts');
const { checkPrompt } = require('./settlement-gate');

const N = parseInt(process.argv[2] || '100', 10);
const ROOT = path.join(__dirname, '..');
const CATEGORY = 'drunk-monkeys-birds-subdued';
const LOG = `/tmp/dmbs-batch-${new Date().toISOString().replace(/[:.]/g, '-')}.log`;
const t0 = Date.now();

function L(msg) {
  const line = `[${new Date().toISOString()}]  ${msg}`;
  console.log(line);
  fs.appendFileSync(LOG, line + '\n');
}

L(`=== drunk-monkeys-birds-subdued batch: firing ${N} designs ===`);
L(`log file: ${LOG}`);
L(`category: ${CATEGORY}`);

const items = buildN(N);
let ok = 0, fail = 0, skipped = 0;

for (let i = 0; i < items.length; i++) {
  const item = items[i];
  const gate = checkPrompt(item.prompt);
  if (gate.verdict !== 'OK') {
    L(`[${i+1}/${N}] SKIP (settlement ${gate.verdict}) — ${(gate.reason||'').slice(0,100)}`);
    skipped++;
    continue;
  }
  L(`[${i+1}/${N}] palette=${item.palette}  animal=${item.animal_summary}`);
  const r = spawnSync('node', [
    path.join(ROOT, 'scripts', 'generate_designs.js'),
    '--n', '1',
    '--kind', 'seamless_tile',
    '--category', CATEGORY,
    '--prompts', item.prompt,
  ], { cwd: ROOT, encoding: 'utf8', timeout: 240_000 });
  if (r.status === 0) {
    ok++;
    L(`  ✓ ok  (running: ${ok} ok, ${fail} fail, ${skipped} skip — ${((Date.now()-t0)/60000).toFixed(1)}min elapsed)`);
  } else {
    fail++;
    L(`  ✗ FAIL  status=${r.status}  stderr=${(r.stderr||'').slice(0,140)}`);
  }
}

L(`=== batch done: ${ok} ok / ${fail} fail / ${skipped} skipped  (${((Date.now()-t0)/60000).toFixed(1)} min) ===`);

// Refresh designs.json + tell wallco-ai server to reload its in-memory grid
L('refreshing designs.json snapshot…');
spawnSync('python3', [path.join(ROOT, 'scripts', 'refresh_designs_snapshot.py')],
          { stdio: 'inherit', cwd: ROOT, timeout: 180_000 });
L('hot-reloading wallco-ai server (local + remote if reachable)…');
spawnSync('curl', ['-sf', '-m', '5', '-X', 'POST', 'http://127.0.0.1:9878/admin/reload-designs'], { stdio: 'inherit', timeout: 10_000 });

process.exit(fail === 0 ? 0 : (ok > 0 ? 0 : 1));