aether-garden / ai /image_generation.py
kavyabhand's picture
Deploy Aether Garden application
781b9f7 verified
Raw
History Blame Contribute Delete
3.12 kB
"""Soul portrait generation via HuggingFace Inference API (FLUX.1-schnell)."""
from __future__ import annotations
import os
from pathlib import Path
PORTRAITS_DIR = Path(__file__).parent.parent / "assets" / "generated"
def _portraits_dir() -> Path:
PORTRAITS_DIR.mkdir(parents=True, exist_ok=True)
return PORTRAITS_DIR
def _build_prompt(entity: dict) -> str:
"""Build a vivid image prompt from entity data."""
appearance = (entity.get("appearance") or "")[:220]
etype = entity.get("type", "character")
traits = entity.get("personality_traits") or []
trait_str = ", ".join(t for t in traits[:2]) if traits else ""
type_style = {
"character": "fantasy portrait, close-up, mysterious figure",
"creature": "fantasy creature, full body, magical beast",
"object": "magical enchanted artifact, studio lighting, detailed",
"place": "mystical location concept art, atmospheric, wide view",
}.get(etype, "fantasy entity")
prompt = (
f"{appearance}. {type_style}. {trait_str}. "
"Dark fantasy art style, painterly, dramatic atmospheric lighting, "
"highly detailed, moody, cinematic, oil painting, intricate details, "
"no text, no watermark, masterpiece quality"
)
return prompt[:500]
def generate_soul_portrait(entity: dict) -> str | None:
"""
Generate a portrait image for the given entity using HF Inference API.
Returns the local file path (string) on success, or None on failure/skip.
Silently skips if HF_TOKEN is not set.
"""
import requests
hf_token = os.environ.get("HF_TOKEN")
if not hf_token:
return None
entity_id = entity.get("id")
if not entity_id:
return None
out_path = _portraits_dir() / f"{entity_id}.jpg"
if out_path.exists():
return str(out_path)
prompt = _build_prompt(entity)
# Try FLUX.1-schnell first (best quality, still fast)
models = [
"black-forest-labs/FLUX.1-schnell",
"stabilityai/sdxl-turbo",
]
for model in models:
try:
resp = requests.post(
f"https://api-inference.huggingface.co/models/{model}",
headers={"Authorization": f"Bearer {hf_token}"},
json={
"inputs": prompt,
"parameters": {
"num_inference_steps": 4,
"width": 512,
"height": 512,
"guidance_scale": 0.0,
},
},
timeout=45,
)
if resp.status_code == 200 and resp.content:
out_path.write_bytes(resp.content)
return str(out_path)
except Exception:
continue
return None
def portrait_url_for(entity: dict) -> str | None:
"""Return the Gradio-servable URL for a portrait if it exists on disk."""
entity_id = entity.get("id")
if not entity_id:
return None
p = PORTRAITS_DIR / f"{entity_id}.jpg"
return str(p) if p.exists() else None