← back to Wild Wallcoverings
post-gen settlement vision gate script
09e5811ec9098c7cfa5ad3db894346f17975f1dd · 2026-07-22 12:19:50 -0700 · Steve Abrams
Files touched
M data/designs.jsonA output/designs/desert-choir-v1-nano.pngA output/designs/galaxy-bots-v1-nano.pngA output/designs/golden-pineapple-v1-nano.pngA output/designs/herbarium-press-v1-nano.pngA output/designs/monstera-bungalow-v1-nano.pngA output/designs/moonrise-ikat-v1-nano.pngA output/designs/night-jungle-v1-nano.pngA output/designs/ray-shadow-v1-nano.pngA scripts/vision_gate.py
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 →