"""Generate 4 cinematic persona images — moment shots, not portraits. Wide 2:1 aspect ratio for editorial strip layout. """ import os, time from concurrent.futures import ThreadPoolExecutor, as_completed from google import genai from google.genai import types client = genai.Client(api_key="AIzaSyCHnesXLjPw-UgeZaQotut66bgjFdvy12E") OUT = "pledge-now-pay-later/public/images/landing" PROMPTS = { "persona-01-dinner.jpg": ( "End of a charity fundraising dinner. A round banquet table, white tablecloth slightly rumpled. " "A single small pledge card sits slightly askew on the tablecloth near an empty water glass. " "Chairs pushed back. Warm tungsten chandelier light creates golden glow. A few guests leaving " "in the far background, blurred. Crumpled napkin. The generosity happened here, but the table " "is emptying. Cinematic wide shot, melancholy but beautiful. No one looking at camera. " "Shot on Leica Q2, 28mm, f/1.7, available light. Portra-like color rendering. " "2:1 landscape aspect ratio." ), "persona-02-phone.jpg": ( "Close-up of a British South Asian woman's hands holding a smartphone above a wooden kitchen table. " "The phone screen shows a messaging app with a green chat bubble. Warm afternoon window light " "from the left illuminates the scene. Shallow depth of field - the rest of the table (a mug, " "a notebook) is softly blurred. Her sleeves are pushed up casually. Intimate, everyday, relatable. " "Not looking at camera - we only see hands and phone. " "Shot on Sony A7III, 55mm, f/1.4, natural light. Warm, honest. " "2:1 landscape aspect ratio." ), "persona-03-volunteer.jpg": ( "A young British South Asian man with a lanyard and dark polo shirt, seen from behind and slightly " "to the side, walking between round dinner tables at a charity gala. He carries a small stack of " "cards in one hand. Seated guests in smart dress at the white-clothed tables. Warm golden gala " "lighting, crystal chandelier bokeh in the upper background. The volunteer is in motion, purposeful. " "Not looking at camera. Other volunteers visible but blurred. Energy, purpose, youth. " "Shot on Canon EOS R5, 35mm, f/1.8, available light. Documentary candid event photography. " "2:1 landscape aspect ratio." ), "persona-04-desk.jpg": ( "A clean wooden desk photographed from a 45-degree overhead angle. An open laptop shows a " "spreadsheet with organized rows and a green progress indicator. Beside the laptop: a neat stack " "of printed A4 papers with a black binder clip, a fine-point pen, and a ceramic mug of tea. " "Soft morning window light from the left creates gentle shadows. No person visible - just the " "workspace. Everything is orderly, calm, under control. Documentary still life. " "Shot on Fujifilm GFX 50S, 63mm, f/4.0, natural light. Calm, precise. " "2:1 landscape aspect ratio." ), } def generate(filename, prompt): t0 = time.time() print(f" [GEN] {filename}...") try: resp = client.models.generate_content( model="gemini-3-pro-image-preview", contents=prompt, config=types.GenerateContentConfig( response_modalities=["TEXT", "IMAGE"], ), ) for part in resp.candidates[0].content.parts: if part.inline_data: path = os.path.join(OUT, filename) with open(path, "wb") as f: f.write(part.inline_data.data) sz = os.path.getsize(path) / 1024 print(f" [OK] {filename} -- {sz:.0f}KB ({time.time()-t0:.1f}s)") return filename, True print(f" [FAIL] {filename} -- no image in response") return filename, False except Exception as e: print(f" [FAIL] {filename} -- {e}") return filename, False if __name__ == "__main__": print(f"Generating {len(PROMPTS)} cinematic persona images...") ok = 0 with ThreadPoolExecutor(max_workers=2) as pool: futures = {pool.submit(generate, fn, p): fn for fn, p in PROMPTS.items()} for f in as_completed(futures): _, success = f.result() if success: ok += 1 print(f"\nDone: {ok}/{len(PROMPTS)} ok")