#!/usr/bin/env python3 """Generate the book cover image with an image-generation model. This is, fittingly, the book eating its own dog food: the cover of a book about AI agents is produced by calling an image-generation model. Run it once; the cover (cover.tex) automatically switches to images/cover-image.png when present — no other change needed. You can then note on the colophon that the cover was generated by AI. Usage (OpenAI, the default): pip install openai export OPENAI_API_KEY=sk-... python gen_cover.py """ import os # ── The prompt ──────────────────────────────────────────────────────────── PROMPT = ( "Vintage scientific engraving illustration of an octopus, in the classic style of " "19th-century natural-history woodcuts and the O'Reilly animal book covers. Finely " "detailed black pen-and-ink crosshatching and fine line work; pure black line art, " "no color, no gray wash, no shading fills. The whole octopus rendered elegantly with " "gracefully curling tentacles, anatomically believable, slightly stylized. Perfectly " "clean pure white background, no scenery, no frame, no border, no text, no lettering, " "no numbers. Centered composition, crisp, high detail." ) OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "images", "cover-image.png") def generate_openai(prompt, out): """OpenAI Images API. Uses gpt-image-1 if available, else dall-e-3.""" api_key = os.environ.get("OPENAI_API_KEY") if not api_key: print("OPENAI_API_KEY environment variable not set. Skipping API image generation.") print("Cover page will use default TikZ vector art in cover.tex.") return False from openai import OpenAI import base64, urllib.parse, urllib.request client = OpenAI() try: r = client.images.generate(model="gpt-image-1", prompt=prompt, size="1024x1536", quality="high", n=1) data = base64.b64decode(r.data[0].b64_json) with open(out, "wb") as f: f.write(data) return True except Exception as e: print(f"gpt-image-1 unavailable ({e}); falling back to dall-e-3 …") try: r = client.images.generate(model="dall-e-3", prompt=prompt, size="1024x1792", quality="hd", style="natural", n=1) url = r.data[0].url parsed = urllib.parse.urlparse(url) if parsed.scheme != "https" or not parsed.netloc: raise ValueError(f"Invalid URL scheme or host for image download: {url}") with urllib.request.urlopen(url, timeout=60) as resp: with open(out, "wb") as f: f.write(resp.read()) return True except Exception as fallback_err: print(f"dall-e-3 image generation failed ({fallback_err}). Falling back to default TikZ art in cover.tex.") return False def generate(prompt, out): return generate_openai(prompt, out) if __name__ == "__main__": os.makedirs(os.path.dirname(OUT), exist_ok=True) print("Generating cover image …") if generate(PROMPT, OUT): print(f"Saved {OUT}") print("Now rebuild: bash build_pdf.sh (cover.tex auto-detects the image)")