"""Regenerate carpet-cleaning and commercial-overview service images with industrial extractor prompts.""" import os, sys, time, subprocess try: from google import genai from google.genai import types except ImportError: os.system(f"{sys.executable} -m pip install google-genai --quiet") from google import genai from google.genai import types API_KEY = os.environ.get("GEMINI_API_KEY", "AIzaSyB_1p8KvaT_rdNJGPs8HKk8bKsvUlcL6Kg") BASE_DIR = os.path.dirname(os.path.dirname(__file__)) IMG_DIR = os.path.join(BASE_DIR, "assets", "images", "services") VID_DIR = os.path.join(BASE_DIR, "assets", "videos", "hero", "clips") REEL_OUT = os.path.join(BASE_DIR, "assets", "videos", "hero", "hero-reel.mp4") client = genai.Client(api_key=API_KEY) # ── Service images ──────────────────────────────────────────────────────────── IMAGES = [ { "name": "carpet-cleaning", "prompt": ( "Wide shot of a large industrial stand-up hot water extraction machine being pushed across " "a plush beige residential carpet. The machine is a heavy commercial-grade upright extractor " "on wheels — tall, wide cleaning head at the base, long upright handle. " "The carpet behind it transitions from dirty and matted to clean, bright, and fluffy. " "Completely dry machine exterior, no steam, no water spraying anywhere. " "Warm natural interior light. Ultra-realistic professional photography." ), }, { "name": "commercial-overview", "prompt": ( "Professional carpet cleaning technician in a plain black shirt, shown from the side, " "pushing a large industrial stand-up hot water extraction machine through a bright commercial " "building lobby. The machine is a heavy commercial-grade upright extractor on wheels — " "tall, wide cleaning head, long handle. Clean carpet visible. No steam, no water spraying, " "no face visible. Professional editorial photography, ultra-realistic." ), }, ] for item in IMAGES: out_path = os.path.join(IMG_DIR, f"{item['name']}.jpg") print(f"[IMG] Generating {item['name']}...") try: resp = client.models.generate_images( model="imagen-4.0-generate-001", prompt=item["prompt"], config=types.GenerateImagesConfig( number_of_images=1, aspect_ratio="4:3", output_mime_type="image/jpeg", safety_filter_level="block_low_and_above", ), ) if resp.generated_images: b = resp.generated_images[0].image.image_bytes with open(out_path, "wb") as f: f.write(b) print(f" Saved {out_path} ({len(b)//1024}KB)") else: print(f" No image returned") except Exception as e: print(f" Error: {e}") # ── Video shots ─────────────────────────────────────────────────────────────── SHOTS = [ { "name": "shot-04-extraction-carpet", "prompt": ( "Cinematic slow-motion wide shot: a large industrial stand-up hot water extraction machine " "being pushed steadily forward across a beige residential carpet. The machine is a tall " "professional-grade upright extractor — heavy-duty, commercial size, on wheels, with a wide " "cleaning head at the base and an upright handle. No steam, no spraying water, no visible " "liquid anywhere on the machine exterior. The carpet behind the machine transitions from dirty " "and matted to bright, clean, and fluffy as it passes. Warm natural room light. Photorealistic." ), }, { "name": "shot-09-technician-unloading", "prompt": ( "Wide shot of a professional carpet cleaning technician wearing a plain black shirt with no logo, " "rolling a large industrial stand-up hot water extraction machine out of a white service van " "parked in a residential driveway in upstate New York. The machine is a heavy commercial-grade " "upright extractor on wheels — tall, industrial size. Autumn trees in background, bright day. " "Technician shown from side or behind, no face visible. Photorealistic." ), }, ] MODELS = ["veo-2.0-generate-001", "veo-3.0-generate-001"] def poll(op, timeout=420): elapsed = 0 while not op.done: if elapsed >= timeout: return None print(f" Waiting... ({elapsed}s)") time.sleep(15) elapsed += 15 op = client.operations.get(op) return op saved_clips = [] for item in SHOTS: out_path = os.path.join(VID_DIR, f"{item['name']}.mp4") print(f"\n[VID] Generating {item['name']}...") done = False for model in MODELS: try: print(f" Model: {model}") op = client.models.generate_videos( model=model, prompt=item["prompt"], config=types.GenerateVideosConfig( aspect_ratio="16:9", resolution="720p", duration_seconds=6, number_of_videos=1, ), ) op = poll(op) if op and op.response and op.response.generated_videos: vid = op.response.generated_videos[0].video try: b = client.files.download(file=vid) except Exception: b = None if b: with open(out_path, "wb") as f: f.write(b) print(f" Saved ({os.path.getsize(out_path)//1024}KB)") saved_clips.append(item["name"]) done = True break except Exception as e: print(f" Error with {model}: {e}") if not done: print(f" FAILED: {item['name']}") # ── Reconcat reel if both shots regenerated ─────────────────────────────────── if len(saved_clips) == 2: print("\nReconcatenating reel...") concat_file = os.path.join(VID_DIR, "concat.txt") order = [ "shot-01-door-opens-trimmed", "shot-02-pan-to-stains", "shot-03-stain-closeup", "shot-04-extraction-carpet", "shot-05-extraction-couch", "shot-06-extraction-stairs", "shot-07-office-entryway", "shot-08-showroom", "shot-09-technician-unloading", ] with open(concat_file, "w") as f: for name in order: f.write(f"file '{os.path.join(VID_DIR, name)}.mp4'\n") result = subprocess.run( ["ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", concat_file, "-c:v", "libx264", "-crf", "22", "-preset", "fast", "-movflags", "+faststart", REEL_OUT], capture_output=True, text=True ) if result.returncode == 0: print(f" Reel saved ({os.path.getsize(REEL_OUT)//1024}KB)") else: print(f" ffmpeg error: {result.stderr[-300:]}") else: print(f"\nOnly {len(saved_clips)}/2 video shots regenerated — skipping reconcat.") print("\nDone.")