Spaces:
Sleeping
Sleeping
Download image_engine.py from build-small-hackathon/stage-whisper: direct link, hf CLI and curl.
- Browser
- Download file 3.32 kB
-
https://huggingface.co/spaces/build-small-hackathon/stage-whisper/resolve/main/image_engine.py
- Command line
-
hf download hf://spaces/build-small-hackathon/stage-whisper/image_engine.py
-
curl -L -o image_engine.py https://huggingface.co/spaces/build-small-hackathon/stage-whisper/resolve/main/image_engine.py
3.32 kB
| """ | |
| Image Engine — Generates scene images via OpenRouter using black-forest-labs/flux.2-pro. | |
| Saves images as compressed JPEG files to avoid huge base64 data URIs. | |
| """ | |
| import os | |
| import re | |
| import io | |
| import base64 | |
| import requests | |
| from PIL import Image | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY", "") | |
| MODEL_ID = "black-forest-labs/flux.2-pro" | |
| OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions" | |
| # Directory to store generated scene images | |
| IMG_DIR = os.path.join(os.path.dirname(__file__), "generated_scenes") | |
| os.makedirs(IMG_DIR, exist_ok=True) | |
| _img_counter = 0 | |
| def _save_as_jpeg(data_uri: str) -> str: | |
| """Convert a base64 data URI (PNG) to a compressed JPEG file. Returns file path.""" | |
| global _img_counter | |
| _img_counter += 1 | |
| # Strip data URI prefix | |
| b64_data = data_uri.split(",", 1)[1] if "," in data_uri else data_uri | |
| raw = base64.b64decode(b64_data) | |
| img = Image.open(io.BytesIO(raw)).convert("RGB") | |
| path = os.path.join(IMG_DIR, f"scene_{_img_counter}.jpg") | |
| img.save(path, "JPEG", quality=72) | |
| size_kb = os.path.getsize(path) / 1024 | |
| print(f"[ImageEngine] Saved JPEG ({size_kb:.0f} KB): {path}") | |
| return path | |
| def generate_scene_image(prompt: str) -> str | None: | |
| """ | |
| Generate a scene image from a text prompt via OpenRouter chat/completions. | |
| Returns a local file path to a JPEG or None on failure. | |
| """ | |
| headers = { | |
| "Authorization": f"Bearer {OPENROUTER_API_KEY}", | |
| "Content-Type": "application/json", | |
| } | |
| full_prompt = ( | |
| f"A cinematic wide-angle theatrical stage scene, dramatic lighting, " | |
| f"rich colors, film still quality: {prompt}" | |
| ) | |
| payload = { | |
| "model": MODEL_ID, | |
| "messages": [ | |
| {"role": "user", "content": full_prompt} | |
| ], | |
| "modalities": ["image"], | |
| } | |
| try: | |
| print(f"[ImageEngine] Generating image: {prompt[:60]}...") | |
| resp = requests.post( | |
| OPENROUTER_URL, | |
| headers=headers, | |
| json=payload, | |
| timeout=60, | |
| ) | |
| if resp.status_code != 200: | |
| print(f"[ImageEngine] API Error ({resp.status_code}): {resp.text[:200]}") | |
| return None | |
| data = resp.json() | |
| message = data.get("choices", [{}])[0].get("message", {}) | |
| # Flux returns images in message.images[] array | |
| images = message.get("images", []) | |
| if images: | |
| img = images[0] | |
| if isinstance(img, dict): | |
| url = img.get("image_url", {}).get("url") or img.get("url") | |
| if url and url.startswith("data:image"): | |
| return _save_as_jpeg(url) | |
| elif url: | |
| return url # External URL, use directly | |
| # Fallback: check content field | |
| content = message.get("content") | |
| if content: | |
| if content.startswith("data:image"): | |
| return _save_as_jpeg(content) | |
| md_match = re.search(r'!\[.*?\]\((.*?)\)', content) | |
| if md_match: | |
| return md_match.group(1) | |
| print(f"[ImageEngine] Could not extract image from response.") | |
| return None | |
| except Exception as e: | |
| print(f"[ImageEngine] Error: {e}") | |
| return None | |