← back to Celeb Gucci Mockup

gen-images.py

89 lines

#!/usr/bin/env python3
"""Generate the Celebrity Signatures editorial model shots via OpenAI gpt-image-1.
Fails LOUD on any API error (no silent empty files). Saves into ./img/."""
import os, sys, base64, json, urllib.request, urllib.error, pathlib, re

KEY = os.environ.get("OPENAI_API_KEY", "")
if not KEY:
    env = pathlib.Path.home() / "Projects/secrets-manager/.env"
    if env.exists():
        m = re.search(r'^OPENAI_API_KEY=(.+)$', env.read_text(), re.M)
        if m: KEY = m.group(1).strip().strip('"')
if not KEY:
    sys.exit("gen-images: no OPENAI_API_KEY in env or secrets-manager/.env")

IMG = pathlib.Path(__file__).parent / "img"
IMG.mkdir(exist_ok=True)

# Original independent house — NO Gucci / GG monogram / horsebit / any real-brand marks.
# House motif = an allover tonal HANDWRITTEN-SIGNATURE / autograph jacquard (the "Celebrity
# Signatures" signature) + a small five-point STAR emblem. Loafers are plain & hardware-free.
STYLE = ("high-fashion luxury editorial campaign photography, cinematic soft natural light, "
         "muted warm film tones, subtle 35mm grain, elegant and minimal, medium-format film, "
         "sophisticated. Original independent fashion house — absolutely NO brand logos, NO GG "
         "monogram, NO interlocking-letter monogram, NO horsebit or metal shoe hardware, and "
         "nothing referencing Gucci or any real brand.")

# The featured "celebrity" (the example). Abraham Lincoln — historical public figure, freely
# depictable. His OWN autograph doubles as the house 'signature' motif on the pieces.
LINCOLN = ("Abraham Lincoln himself — the historical 16th President of the United States, "
           "unmistakable and historically accurate: tall and lean, gaunt angular face, deep-set "
           "eyes, dark hair, full chin-beard without moustache")
MOTIF = ("an allover subtle tonal jacquard of his own looping 'A. Lincoln' handwritten signature "
         "repeated as the house motif, tone-on-tone")

JOBS = [
    ("hero", "1536x1024",
     f"{LINCOLN}. He is OLDER (early 50s), weathered and gaunt, with his ICONIC FULL DARK CHIN-BEARD, "
     f"instantly recognizable as Abraham Lincoln — do not make him young or clean-shaven. Standing full "
     f"body in a high-fashion editorial campaign, wearing his iconic tall black stovepipe top hat, a silk "
     f"shirt patterned with {MOTIF}, tailored trousers, and ribbed dress socks with plain polished leather "
     f"loafers (no metal hardware). Positioned toward the right third of the frame, with generous empty "
     f"wall space on the left and above for a headline. {STYLE}"),
    ("editorial", "1536x1024",
     f"{LINCOLN}. Seated in a refined editorial pose in the full look — the tall-crown felt hat, a silk "
     f"shirt with {MOTIF}, and ribbed socks with plain loafers — warm cinematic light, dignified. {STYLE}"),
    ("hat", "1024x1536",
     f"{LINCOLN}. Editorial portrait, wearing an elegant tall-crown felt hat with a simple grosgrain band "
     f"(an original refined luxury product nodding to his iconic stovepipe). Solid felt, no logo. {STYLE}"),
    ("shirt", "1024x1536",
     f"{LINCOLN}. Three-quarter editorial portrait, wearing a luxurious silk button shirt patterned with "
     f"{MOTIF}, poised and dignified. {STYLE}"),
    ("socks", "1024x1536",
     f"{LINCOLN}, seated. Editorial crop of his lower legs wearing ribbed dress socks with a single small "
     f"embroidered five-point star at the cuff, worn with plain polished black leather loafers that have NO "
     f"metal bit and NO buckle. {STYLE}"),
]

def gen(name, size, prompt):
    body = json.dumps({
        "model": "gpt-image-1", "prompt": prompt, "size": size,
        "quality": "medium", "n": 1,
    }).encode()
    req = urllib.request.Request(
        "https://api.openai.com/v1/images/generations", data=body,
        headers={"Content-Type": "application/json", "Authorization": f"Bearer {KEY}"})
    try:
        with urllib.request.urlopen(req, timeout=180) as r:
            data = json.load(r)
    except urllib.error.HTTPError as e:
        detail = e.read().decode(errors="replace")[:500]
        sys.exit(f"gen-images: HTTP {e.code} generating '{name}': {detail}")
    except Exception as e:
        sys.exit(f"gen-images: error generating '{name}': {e}")

    b64 = (data.get("data") or [{}])[0].get("b64_json")
    if not b64:
        sys.exit(f"gen-images: no image bytes for '{name}'. Raw: {json.dumps(data)[:400]}")
    out = IMG / f"{name}.jpg"
    out.write_bytes(base64.b64decode(b64))
    print(f"  ✓ {name:9s} {size:9s} -> {out.name} ({out.stat().st_size//1024} KB)")

if __name__ == "__main__":
    only = sys.argv[1:] or [j[0] for j in JOBS]
    print(f"Generating {len(only)} image(s) with gpt-image-1 (medium)...")
    for name, size, prompt in JOBS:
        if name in only:
            gen(name, size, prompt)
    print("done.")