[object Object]

← back to Wallco Ai

dogs/luxe gen: GEMINI_IMAGE_MODEL env override (re-roll on a newer Nano Banana) + dogs --force; provenance marker reflects model used

547c9df7ba7cc750c8f919c052cda2919281834e · 2026-06-03 08:28:32 -0700 · Steve

Files touched

Diff

commit 547c9df7ba7cc750c8f919c052cda2919281834e
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jun 3 08:28:32 2026 -0700

    dogs/luxe gen: GEMINI_IMAGE_MODEL env override (re-roll on a newer Nano Banana) + dogs --force; provenance marker reflects model used
---
 scripts/gen-luxe.js      |  7 +++++--
 scripts/generate-dogs.js | 15 +++++++++++----
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/scripts/gen-luxe.js b/scripts/gen-luxe.js
index da7fabc..d63cd37 100644
--- a/scripts/gen-luxe.js
+++ b/scripts/gen-luxe.js
@@ -65,8 +65,11 @@ function psql(sql) {
   if (r.status !== 0) throw new Error(r.stderr || 'psql failed');
   return r.stdout.trim();
 }
+// Image model env-overridable (default = original Nano Banana). Set
+// GEMINI_IMAGE_MODEL=gemini-3.1-flash-image / gemini-3-pro-image to re-roll. — 2026-06
+const IMG_MODEL = process.env.GEMINI_IMAGE_MODEL || 'gemini-2.5-flash-image';
 async function geminiImage(prompt) {
-  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent?key=${readKey()}`;
+  const url = `https://generativelanguage.googleapis.com/v1beta/models/${IMG_MODEL}:generateContent?key=${readKey()}`;
   const r = await fetch(url, {
     method: 'POST',
     headers: { 'Content-Type': 'application/json' },
@@ -294,7 +297,7 @@ INSERT INTO spoon_all_designs
    image_url, local_path, dominant_hex, category, is_published, parent_design_id)
 VALUES
   ('seamless_tile', 'wallco.ai', 24, 24,
-   'gemini-2.5-flash-image-luxe-v2',
+   ${esc(IMG_MODEL + '-luxe-v2')},
    ${esc('Luxe regen of #' + SRC_ID + ' anchored to de Gournay / House of Hackney / 1838-flock / Cole & Son / Brunschwig & Fils.' + (textureBrief ? ' Ground: ' + textureBrief + '.' : '') + (lastSubjectResult ? ' Subject-verify: primary=' + (SUBJECTS[0]||'?') + ' present=' + (lastSubjectResult.present.includes(SUBJECTS[0]) ? 'YES' : 'NO') + ' all=[' + lastSubjectResult.present.join(',') + ']/missing=[' + lastSubjectResult.missing.join(',') + '].' : '') + ' Motif: ' + MOTIF)},
    ${newSeed},
    '/designs/img/by-id/__NEW__',
diff --git a/scripts/generate-dogs.js b/scripts/generate-dogs.js
index e07ecb4..f84f437 100644
--- a/scripts/generate-dogs.js
+++ b/scripts/generate-dogs.js
@@ -89,6 +89,7 @@ function parseArgs() {
     if (a[i] === '--breeds') o.breeds = parseInt(a[++i], 10);
     else if (a[i] === '--colorways') o.colorways = parseInt(a[++i], 10);
     else if (a[i] === '--only') o.only = a[++i].split(',').map(s => s.trim()).filter(Boolean);
+    else if (a[i] === '--force') o.force = true;  // regenerate even if a row exists (re-roll on a new model)
   }
   return o;
 }
@@ -102,9 +103,13 @@ function readKey() {
   return m[1].trim();
 }
 const GEMINI_KEY = readKey();
+// Image model is env-overridable (default = original Nano Banana). Set
+// GEMINI_IMAGE_MODEL=gemini-3.1-flash-image (Nano Banana 3.1) or
+// gemini-3-pro-image (Nano Banana Pro) to re-roll on a newer model. — 2026-06
+const IMG_MODEL = process.env.GEMINI_IMAGE_MODEL || 'gemini-2.5-flash-image';
 
 async function geminiImage(prompt) {
-  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent?key=${GEMINI_KEY}`;
+  const url = `https://generativelanguage.googleapis.com/v1beta/models/${IMG_MODEL}:generateContent?key=${GEMINI_KEY}`;
   const r = await fetch(url, {
     method: 'POST',
     headers: { 'Content-Type': 'application/json' },
@@ -148,9 +153,10 @@ print(json.dumps([{'hex':'#{:02x}{:02x}{:02x}'.format(*rgb),'pct':round(n/total*
 }
 
 // ── one design ───────────────────────────────────────────────────────────────
+let FORCE = false;  // --force: bypass the idempotency skip to re-roll on a new model
 async function genOne(breed, cw) {
   const category = `dogs · ${breed.slug}`;
-  if (alreadyExists(category, cw.slug)) {
+  if (!FORCE && alreadyExists(category, cw.slug)) {
     console.log(`  · skip ${breed.slug}/${cw.slug} (already in PG)`);
     return { skipped: true };
   }
@@ -192,7 +198,7 @@ INSERT INTO spoon_all_designs
    dominant_hex, palette, category, product_line, is_published)
 VALUES
   ('seamless_tile', 'wallco.ai', 24, 24,
-   'gemini-2.5-flash-image-repeat-v2',
+   ${esc(IMG_MODEL + '-repeat-v2')},
    ${esc(storedPrompt)}, ${seed},
    '/designs/img/by-id/__NEW__', ${esc(outPath)},
    ${esc(dominant)}, ${esc(JSON.stringify(palette))}::jsonb,
@@ -207,12 +213,13 @@ RETURNING id;`;
 // ── main ─────────────────────────────────────────────────────────────────────
 (async () => {
   const opt = parseArgs();
+  FORCE = !!opt.force;
   let breeds = BREEDS.slice(0, opt.breeds);
   if (opt.only) breeds = BREEDS.filter(b => opt.only.includes(b.slug));
   const colorways = COLORWAYS.slice(0, opt.colorways);
   const total = breeds.length * colorways.length;
   console.log(`generate-dogs: ${breeds.length} breeds × ${colorways.length} colorways = ${total} designs`);
-  console.log(`engine: gemini-2.5-flash-image-repeat-v2 · is_published=FALSE (curate-then-publish)\n`);
+  console.log(`engine: ${IMG_MODEL}-repeat-v2 · is_published=FALSE (curate-then-publish)\n`);
 
   const t0 = Date.now();
   let ok = 0, skip = 0, fail = 0, retries = 0;

← 46bc416 detectors: handle Nano Banana C2PA JPEG (b64 magic /9j/, pat  ·  back to Wallco Ai  ·  mural-master: room-size 12x11ft scenic-master builder + vert 5bfe5e9 →