[object Object]

← back to Wild Wallcoverings

post-gen settlement vision gate script

09e5811ec9098c7cfa5ad3db894346f17975f1dd · 2026-07-22 12:19:50 -0700 · Steve Abrams

Files touched

Diff

commit 09e5811ec9098c7cfa5ad3db894346f17975f1dd
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 22 12:19:50 2026 -0700

    post-gen settlement vision gate script
---
 data/designs.json                            | 120 +++++++++++++++++++++++++++
 output/designs/desert-choir-v1-nano.png      | Bin 0 -> 1907079 bytes
 output/designs/galaxy-bots-v1-nano.png       | Bin 0 -> 2101873 bytes
 output/designs/golden-pineapple-v1-nano.png  | Bin 0 -> 1133160 bytes
 output/designs/herbarium-press-v1-nano.png   | Bin 0 -> 1944088 bytes
 output/designs/monstera-bungalow-v1-nano.png | Bin 0 -> 2258457 bytes
 output/designs/moonrise-ikat-v1-nano.png     | Bin 0 -> 2051042 bytes
 output/designs/night-jungle-v1-nano.png      | Bin 0 -> 1784607 bytes
 output/designs/ray-shadow-v1-nano.png        | Bin 0 -> 1759352 bytes
 scripts/vision_gate.py                       |  88 ++++++++++++++++++++
 10 files changed, 208 insertions(+)

diff --git a/data/designs.json b/data/designs.json
index 7967a17..4871f18 100644
--- a/data/designs.json
+++ b/data/designs.json
@@ -43,5 +43,125 @@
     "created_at": "2026-07-22T19:18:44.703723+00:00"
    }
   ]
+ },
+ {
+  "id": "galaxy-bots",
+  "title": "Galaxy Bots",
+  "theme": "robots in outer space",
+  "description": "Astrobots (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:18:53.231918+00:00",
+  "variants": [
+   {
+    "file": "galaxy-bots-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:18:53.231941+00:00"
+   }
+  ]
+ },
+ {
+  "id": "herbarium-press",
+  "title": "Herbarium Press",
+  "theme": "pressed botanical flowers",
+  "description": "Herbario family (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:19:01.485722+00:00",
+  "variants": [
+   {
+    "file": "herbarium-press-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:19:01.485750+00:00"
+   }
+  ]
+ },
+ {
+  "id": "desert-choir",
+  "title": "Desert Choir",
+  "theme": "oversized southwest cacti",
+  "description": "Cactus Spirit (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:19:08.811454+00:00",
+  "variants": [
+   {
+    "file": "desert-choir-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:19:08.811475+00:00"
+   }
+  ]
+ },
+ {
+  "id": "ray-shadow",
+  "title": "Ray Shadow",
+  "theme": "spotted eagle ray skin",
+  "description": "Sea Ray (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:19:16.192537+00:00",
+  "variants": [
+   {
+    "file": "ray-shadow-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:19:16.192560+00:00"
+   }
+  ]
+ },
+ {
+  "id": "moonrise-ikat",
+  "title": "Moonrise Ikat",
+  "theme": "moon phases as ikat",
+  "description": "Earthlight (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:19:24.429045+00:00",
+  "variants": [
+   {
+    "file": "moonrise-ikat-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:19:24.429069+00:00"
+   }
+  ]
+ },
+ {
+  "id": "night-jungle",
+  "title": "Night Jungle",
+  "theme": "nocturnal jungle flora and fauna",
+  "description": "Jungle Dream (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:19:32.563982+00:00",
+  "variants": [
+   {
+    "file": "night-jungle-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:19:32.564009+00:00"
+   }
+  ]
+ },
+ {
+  "id": "golden-pineapple",
+  "title": "Golden Pineapple",
+  "theme": "pineapple welcome",
+  "description": "Pi\u00f1a Sola (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:19:39.573122+00:00",
+  "variants": [
+   {
+    "file": "golden-pineapple-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:19:39.573147+00:00"
+   }
+  ]
+ },
+ {
+  "id": "monstera-bungalow",
+  "title": "Monstera Bungalow",
+  "theme": "monstera leaves",
+  "description": "Deliciosa (theme only)",
+  "size": "24\" x 25\"",
+  "created_at": "2026-07-22T19:19:47.415754+00:00",
+  "variants": [
+   {
+    "file": "monstera-bungalow-v1-nano.png",
+    "engine": "nano-banana",
+    "created_at": "2026-07-22T19:19:47.415779+00:00"
+   }
+  ]
  }
 ]
\ No newline at end of file
diff --git a/output/designs/desert-choir-v1-nano.png b/output/designs/desert-choir-v1-nano.png
new file mode 100644
index 0000000..3364f87
Binary files /dev/null and b/output/designs/desert-choir-v1-nano.png differ
diff --git a/output/designs/galaxy-bots-v1-nano.png b/output/designs/galaxy-bots-v1-nano.png
new file mode 100644
index 0000000..4b41007
Binary files /dev/null and b/output/designs/galaxy-bots-v1-nano.png differ
diff --git a/output/designs/golden-pineapple-v1-nano.png b/output/designs/golden-pineapple-v1-nano.png
new file mode 100644
index 0000000..ed42571
Binary files /dev/null and b/output/designs/golden-pineapple-v1-nano.png differ
diff --git a/output/designs/herbarium-press-v1-nano.png b/output/designs/herbarium-press-v1-nano.png
new file mode 100644
index 0000000..5e860b0
Binary files /dev/null and b/output/designs/herbarium-press-v1-nano.png differ
diff --git a/output/designs/monstera-bungalow-v1-nano.png b/output/designs/monstera-bungalow-v1-nano.png
new file mode 100644
index 0000000..f35cb2b
Binary files /dev/null and b/output/designs/monstera-bungalow-v1-nano.png differ
diff --git a/output/designs/moonrise-ikat-v1-nano.png b/output/designs/moonrise-ikat-v1-nano.png
new file mode 100644
index 0000000..5aed09a
Binary files /dev/null and b/output/designs/moonrise-ikat-v1-nano.png differ
diff --git a/output/designs/night-jungle-v1-nano.png b/output/designs/night-jungle-v1-nano.png
new file mode 100644
index 0000000..9b787cc
Binary files /dev/null and b/output/designs/night-jungle-v1-nano.png differ
diff --git a/output/designs/ray-shadow-v1-nano.png b/output/designs/ray-shadow-v1-nano.png
new file mode 100644
index 0000000..a18a9b6
Binary files /dev/null and b/output/designs/ray-shadow-v1-nano.png differ
diff --git a/scripts/vision_gate.py b/scripts/vision_gate.py
new file mode 100644
index 0000000..2607945
--- /dev/null
+++ b/scripts/vision_gate.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+"""Post-gen settlement vision pass over every generated image.
+
+Sends each image to gemini-2.5-flash asking for the five detector booleans,
+applies the binding combinator (defendant-favorable reading), writes verdicts
+into data/designs.json (per-variant) and appends to the settlement audit log.
+Cost ~$0.001-0.002 per image.
+
+Usage: GEMINI_API_KEY=... vision_gate.py
+"""
+import base64, json, os, sys, time, urllib.request
+from datetime import datetime, timezone
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+OUT = os.path.join(ROOT, "output", "designs")
+DESIGNS = os.path.join(ROOT, "data", "designs.json")
+AUDIT = os.path.expanduser("~/Projects/wallco-ai/data/settlement-audit/orchestrator-log.jsonl")
+KEY = os.environ["GEMINI_API_KEY"]
+URL = ("https://generativelanguage.googleapis.com/v1beta/models/"
+       "gemini-2.5-flash:generateContent?key=" + KEY)
+
+PROMPT = """Analyze this wallpaper pattern image. Answer ONLY with JSON:
+{"a1_directional_foliage": bool,  // repeating leaves/palm fronds/similar foliage with directional variation
+ "a2_open_space": bool,           // visible open space between leaves (only relevant if foliage present)
+ "a3_multi_color_leaves": bool,   // more than one ink color within the leaf/foliage layer itself
+ "b_prohibited": bool,            // ANY bananas, banana pods, grapes, birds, or butterflies visible
+ "b_matched": "what matched or empty",
+ "acceptable": bool}              // tree trunks, clearly represented branches, or fruit/animals OTHER than the prohibited list"""
+
+def check(path):
+    img = base64.b64encode(open(path, "rb").read()).decode()
+    body = {"contents": [{"parts": [
+        {"text": PROMPT},
+        {"inline_data": {"mime_type": "image/png", "data": img}}]}],
+        "generationConfig": {"responseMimeType": "application/json"}}
+    req = urllib.request.Request(URL, data=json.dumps(body).encode(),
+                                 headers={"Content-Type": "application/json"})
+    with urllib.request.urlopen(req, timeout=90) as r:
+        resp = json.load(r)
+    return json.loads(resp["candidates"][0]["content"]["parts"][0]["text"])
+
+def verdict(v):
+    part_a = v["a1_directional_foliage"] and v["a2_open_space"] and v["a3_multi_color_leaves"]
+    if part_a and v["b_prohibited"]:
+        return "BLOCK"
+    if v["b_prohibited"]:
+        return "NEEDS REVIEW"   # B present without full A is permitted, but borderline -> surface it
+    return "OK"
+
+def main():
+    designs = json.load(open(DESIGNS))
+    audit_entries = []
+    for d in designs:
+        for var in d["variants"]:
+            if var.get("settlement"):
+                continue
+            path = os.path.join(OUT, var["file"])
+            if not os.path.exists(path):
+                continue
+            for attempt in range(3):
+                try:
+                    v = check(path)
+                    break
+                except Exception as e:
+                    if attempt == 2:
+                        v = None
+                        print(f"  ERROR {var['file']}: {e}")
+                    time.sleep(5)
+            if v is None:
+                var["settlement"] = "UNKNOWN-BLOCK"  # unknown must yield BLOCK
+            else:
+                var["settlement"] = verdict(v)
+                var["settlement_detail"] = v
+            print(f"{var['file']:<40} {var['settlement']}")
+            audit_entries.append({"ts": datetime.now(timezone.utc).isoformat(),
+                                  "source": "wild-wallcoverings post-gen vision",
+                                  "file": var["file"], "verdict": var["settlement"],
+                                  "detail": v})
+    json.dump(designs, open(DESIGNS, "w"), indent=1)
+    os.makedirs(os.path.dirname(AUDIT), exist_ok=True)
+    with open(AUDIT, "a") as f:
+        for e in audit_entries:
+            f.write(json.dumps(e) + "\n")
+    n = len(audit_entries)
+    print(f"\nchecked {n} images, est cost ${n * 0.0015:.2f}")
+
+if __name__ == "__main__":
+    main()

← 94741ef briefs (settlement-gated 24/24 OK), batch driver, viewer liv  ·  back to Wild Wallcoverings  ·  nano batch complete (24/24), vision gate 27/27 OK 1a98106 →