|
|
||
|---|---|---|
| .. | ||
| prompts | ||
| iterate.py | ||
| local_scorer.py | ||
| promote.py | ||
| README.md | ||
Illustration Pipeline
Per-slug Jessica Rabbit illustration generation pipeline for quinn.www.
Prerequisites
python3(3.12+)rembg+Pillow+numpy(+scipyfor better silhouettes)cwebpon PATH (dnf install libwebp-tools)claudeCLI withmodel-bossMCP 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 0–10 (default: 7.0)
[--max-rounds N] # max retry rounds (default: 3)
How it works
- Loads prompt from the appropriate TOML (
destinations.tomlorspecialties.toml). - Builds full prompt:
BASE + prop + COMPOSITION + STYLE; negative:UNIVERSAL_NEG + extra_neg. - Submits N seeds to model-boss diffusion API (
POST /api/v1/diffusion/jobs). - Polls each job, retrieves raw PNG to
out/<kind>_<slug>_r<round>v<seed>_raw.png. - Runs
rembg(silueta model) → silhouette PNG atout/<kind>_<slug>_r<round>v<seed>.png. - Scores each silhouette via the
claudeCLI (see Scoring below). - Keeps images scoring ≥
--min-score. If fewer than--min-keepers, re-runs new seeds (up to--max-rounds). - Appends/updates
out/_index.jsonafter each slug. - 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 (0–2 each, total 0–10):
| 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
- Verifies the finalist exists in
out/. - Copies to
deployments/@domains/quinn.www/root/public/photos/illustrations/<kind>_<slug>.png. - Runs
cwebp -q 85to produce the matching.webp. - Reads image dimensions via PIL.
- Upserts
manifest.jsonwith aManifestEntrymatching the existing schema. - 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.