HERO IMAGE: - Generated 3 concepts with gemini-3-pro-image-preview, picked #1 - Phone showing 'Payment Received' notification at a charity gala dinner - Warm tungsten bokeh chandeliers against dark bg-gray-950 - Directly visualizes the headline: 'money in the bank' - Candid documentary angle, not looking at camera, brand compliant IMAGE OPTIMIZATION (85% total reduction): - All 21 images resized: landscape max 1200px, portrait max 1000px - Compressed JPEG quality 80, progressive encoding, EXIF stripped - Total: 13.6MB -> 2.1MB (saved 11.5MB) - Individual savings: 81-90% per image NEXT.JS IMAGE PIPELINE: - Added sharp (10x faster than squoosh for image processing) - next.config.mjs: WebP format, proper device/image sizes, 1yr cache TTL - Dockerfile: libc6-compat + NEXT_SHARP_PATH for Alpine sharp support - First request: ~3s (processing), cached: <1s WebP served sizes: hero 52KB, cards 32-40KB (vs original 500-800KB JPEGs)
89 lines
5.2 KiB
Python
89 lines
5.2 KiB
Python
"""Generate a world-class hero image for Pledge Now, Pay Later."""
|
|
import sys, io, os, time
|
|
sys.stdout.reconfigure(encoding='utf-8')
|
|
|
|
from google import genai
|
|
from google.genai import types
|
|
from PIL import Image
|
|
|
|
client = genai.Client(api_key="AIzaSyCHnesXLjPw-UgeZaQotut66bgjFdvy12E")
|
|
MODEL = "gemini-3-pro-image-preview"
|
|
|
|
OUT_DIR = "pledge-now-pay-later/public/images/landing"
|
|
BRAND_DIR = "pledge-now-pay-later/brand/photography"
|
|
|
|
PROMPTS = [
|
|
# Concept 1: Phone notification at gala
|
|
"""Photorealistic close-up documentary photograph.
|
|
A woman's hand holding a smartphone at a charity gala dinner table. The phone screen glows bright showing a green checkmark payment confirmation notification. Her hand is in sharp focus.
|
|
Background: beautifully soft bokeh of warm golden tungsten chandelier lights, round dinner tables with white tablecloths, blurred guests in formal attire. A glass of water and edge of a plate visible on the dark wooden table.
|
|
British South Asian woman, dark navy blazer sleeve, simple gold bracelet on wrist.
|
|
Shot on Sony A7IV, 50mm f/1.4, available warm tungsten light. Extremely shallow depth of field. Documentary candid style, warm color temperature.
|
|
The mood: quiet triumph. The pledge came through. Money in the bank.
|
|
Portrait orientation, 4:5 aspect ratio. Professional editorial photography.""",
|
|
|
|
# Concept 2: Dashboard laptop at desk after event
|
|
"""Photorealistic documentary photograph of a charity manager's desk, end of a successful fundraising evening.
|
|
An open MacBook showing a dashboard with bright green progress bars at 100 percent and payment confirmations. The laptop screen glows in the dim warm light. A phone beside it shows a WhatsApp message. A cup of tea, reading glasses folded on the desk.
|
|
The setting is a quiet office after an event. Warm desk lamp casting golden light, a window showing evening London skyline with city lights in the far background, completely out of focus.
|
|
British South Asian woman in her 40s, slight smile, looking at the laptop screen, only her silhouette partially visible from the side. Not looking at camera.
|
|
Shot on Leica Q2, 28mm f/1.7, available warm lamp light and blue window light. Shallow depth of field. Documentary candid style.
|
|
The mood: satisfied relief. Every pledge tracked. Every penny accounted for.
|
|
Portrait orientation, 4:5 aspect ratio. Professional editorial photography.""",
|
|
|
|
# Concept 3: The green glow moment
|
|
"""Photorealistic documentary photograph capturing the exact moment of success.
|
|
A close-up of a smartphone in a woman's hand, the screen casting a soft green glow on her face from below. She is standing at the edge of a busy charity gala ballroom. The phone shows a payment dashboard with multiple green indicators.
|
|
Background: a sweeping view of a London hotel ballroom with crystal chandeliers creating beautiful warm bokeh circles. Guests at round tables, energy and generosity in the air. All beautifully blurred.
|
|
British woman wearing a dark structured blazer, hijab, professional. She holds the phone at mid-chest level, glancing down at it with a subtle knowing expression. Candid, not posed.
|
|
Shot on Canon R5, 85mm f/1.2, warm tungsten available light. Extremely shallow depth of field. The phone and her nearest hand are razor sharp, face slightly soft, background completely dissolved into warm golden bokeh circles.
|
|
Cinematic documentary photography. The feeling: this is what success looks like. Quiet. Precise. Money in the bank.
|
|
Portrait orientation, 4:5 aspect ratio. Professional editorial photography.""",
|
|
]
|
|
|
|
os.makedirs(OUT_DIR, exist_ok=True)
|
|
os.makedirs(BRAND_DIR, exist_ok=True)
|
|
|
|
results = []
|
|
for i, prompt in enumerate(PROMPTS):
|
|
for attempt in range(3):
|
|
try:
|
|
print(f"\n--- Generating concept {i+1}/3 (attempt {attempt+1}) ---")
|
|
response = client.models.generate_content(
|
|
model=MODEL,
|
|
contents=prompt,
|
|
config=types.GenerateContentConfig(
|
|
response_modalities=["IMAGE", "TEXT"],
|
|
temperature=1.0,
|
|
),
|
|
)
|
|
|
|
found = False
|
|
for part in response.candidates[0].content.parts:
|
|
if part.inline_data and part.inline_data.mime_type.startswith("image/"):
|
|
img = Image.open(io.BytesIO(part.inline_data.data))
|
|
fname = f"hero-concept-{i+1}.jpg"
|
|
path = os.path.join(OUT_DIR, fname)
|
|
if img.mode != "RGB":
|
|
img = img.convert("RGB")
|
|
img.save(path, "JPEG", quality=92, optimize=True)
|
|
sz = os.path.getsize(path)
|
|
print(f" OK {fname} -- {img.size[0]}x{img.size[1]}, {sz//1024}KB")
|
|
results.append((fname, img.size, sz))
|
|
found = True
|
|
break
|
|
if found:
|
|
break
|
|
else:
|
|
print(" No image in response, retrying...")
|
|
|
|
except Exception as e:
|
|
emsg = str(e).encode('ascii', 'replace').decode('ascii')
|
|
print(f" Error: {emsg}")
|
|
if attempt < 2:
|
|
time.sleep(5)
|
|
|
|
print(f"\n=== Generated {len(results)}/3 hero concepts ===")
|
|
for fname, size, sz in results:
|
|
print(f" {fname}: {size[0]}x{size[1]}, {sz//1024}KB")
|