lilith-platform.live/tooling/scripts/illustrations
2026-04-08 09:41:12 -07:00
..
out chore(illustrations): 🔧 Update destination illustrations (Paris, Chicago, Las Vegas) with new versions (r1v3, r1v6) and associated files 2026-04-08 09:41:12 -07:00
prompts chore(tooling-specific): 🔧 Update and refine development automation scripts in the tooling directory 2026-04-07 15:22:00 -07:00
iterate.py feat(illustrations): Add new iteration parameters and scoring logic for enhanced illustration processing 2026-04-08 09:41:11 -07:00
local_scorer.py feat(illustrations): Add new iteration parameters and scoring logic for enhanced illustration processing 2026-04-08 09:41:11 -07:00
promote.py chore(tooling-specific): 🔧 Update and refine development automation scripts in the tooling directory 2026-04-07 15:22:00 -07:00
README.md chore(tooling-specific): 🔧 Update and refine development automation scripts in the tooling directory 2026-04-07 15:22:00 -07:00

Illustration Pipeline

Per-slug Jessica Rabbit illustration generation pipeline for quinn.www.

Prerequisites

  • python3 (3.12+)
  • rembg + Pillow + numpy (+ scipy for better silhouettes)
  • cwebp on PATH (dnf install libwebp-tools)
  • claude CLI with model-boss MCP server configured in ~/.claude.json
  • model-boss diffusion API reachable at http://localhost:8210/api/v1

Prompt TOMLs

prompts/destinations.toml and prompts/specialties.toml hold per-slug entries:

[paris]
prop = "holding champagne flute raised elegantly..."
extra_neg = ""

For specialties, keys use double-underscore (gfe-sensual__girlfriend-experience).

iterate.py — Generate illustrations

# All slugs, both kinds (default)
python3 iterate.py

# Single slug
python3 iterate.py --slug paris --kind destination --seeds 4

# More permissive: fewer keepers, lower bar
python3 iterate.py --slug paris --kind destination --seeds 8 --min-keepers 2 --min-score 6.0

# Full options
python3 iterate.py [--slug SLUG] [--kind destination|specialty]
                   [--seeds N]          # seeds per round (default: 8)
                   [--min-keepers N]    # minimum finalists to accept (default: 3)
                   [--min-score F]      # score threshold 010 (default: 7.0)
                   [--max-rounds N]     # max retry rounds (default: 3)

How it works

  1. Loads prompt from the appropriate TOML (destinations.toml or specialties.toml).
  2. Builds full prompt: BASE + prop + COMPOSITION + STYLE; negative: UNIVERSAL_NEG + extra_neg.
  3. Submits N seeds to model-boss diffusion API (POST /api/v1/diffusion/jobs).
  4. Polls each job, retrieves raw PNG to out/<kind>_<slug>_r<round>v<seed>_raw.png.
  5. Runs rembg (silueta model) → silhouette PNG at out/<kind>_<slug>_r<round>v<seed>.png.
  6. Scores each silhouette via the claude CLI (see Scoring below).
  7. Keeps images scoring ≥ --min-score. If fewer than --min-keepers, re-runs new seeds (up to --max-rounds).
  8. Appends/updates out/_index.json after each slug.
  9. Regenerates out/_review.html — static gallery, no JS frameworks.

Outputs

File Description
out/<kind>_<slug>_r<round>v<seed>_raw.png Raw generation
out/<kind>_<slug>_r<round>v<seed>.png Silhouette (rembg)
out/<kind>_<slug>_r<round>v<seed>.score.json Score breakdown
out/_index.json Full index: {<kind>/<slug>: {finalists, rounds}}
out/_review.html Static gallery — open in browser

Scoring

model-boss has no HTTP scoring endpoint — the /api/v1/* routes all serve the SPA shell. Scoring is performed via the claude CLI as a subprocess:

claude --output-format json --print "<rubric prompt>"

The rubric scores 5 dimensions (02 each, total 010):

Dimension Criterion
silhouette_legibility Clean, readable full-body silhouette
prop_clarity Signature prop clearly visible
hourglass_gown Hourglass figure in floor-length gown
white_background Pure white, no shadows/scenery
no_text_border No text, watermarks, or borders

iterate.py calls verify_scoring_available() at startup — if claude is missing or broken, it fails loudly before submitting any jobs.

promote.py — Promote finalist to deployment

python3 promote.py --slug paris --kind destination --finalist destination_paris_r1v2.png

What it does

  1. Verifies the finalist exists in out/.
  2. Copies to deployments/@domains/quinn.www/root/public/photos/illustrations/<kind>_<slug>.png.
  3. Runs cwebp -q 85 to produce the matching .webp.
  4. Reads image dimensions via PIL.
  5. Upserts manifest.json with a ManifestEntry matching the existing schema.
  6. Idempotent: re-running on the same slug replaces the prior entry.

Manifest note

Illustration entries use filename: "illustrations/<kind>_<slug>.png" (subdirectory path), while existing manifest entries use flat filenames. If the admin validator or frontend consumer only supports flat filenames, the ManifestEntry consumer will need to handle the illustrations/ prefix. This is flagged at runtime as an INFO log.