ai-virtual-try-on / prefetch_cache.py
tonyassi's picture
Deploy Ai fitting room (FastAPI + Docker)
16babf7 verified
"""Pre-generate the 12 example combos (2 faces × 6 clothes) and save PNGs into static/cached/.
Idempotent: skips files that already exist. Run once, commit the results.
"""
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
import httpx
from dotenv import load_dotenv
HERE = Path(__file__).resolve().parent
STATIC_DIR = HERE / "static"
FACE_DIR = STATIC_DIR / "face"
CLOTHES_DIR = STATIC_DIR / "clothes"
CACHE_DIR = STATIC_DIR / "cached"
CACHE_DIR.mkdir(exist_ok=True)
# Make sibling modules importable
sys.path.insert(0, str(HERE))
from fashn import FashnClient, FashnError, to_data_url # noqa: E402
load_dotenv(HERE / ".env")
API_KEY = os.environ.get("FASHN_API_KEY")
if not API_KEY:
raise SystemExit("FASHN_API_KEY missing — make sure code/.env is set")
FACES = ["tony", "dahlia"]
CLOTHES = ["1", "2", "3", "4", "5", "6"]
async def fetch_to_file(url: str, dest: Path) -> None:
async with httpx.AsyncClient(timeout=60.0) as c:
r = await c.get(url)
r.raise_for_status()
dest.write_bytes(r.content)
async def main() -> None:
client = FashnClient(api_key=API_KEY)
todo: list[tuple[str, str]] = []
for f in FACES:
for cl in CLOTHES:
cached = CACHE_DIR / f"{f}_{cl}.png"
if cached.exists():
print(f"[skip] {cached.name} already exists")
continue
todo.append((f, cl))
if not todo:
print("\nAll 12 combos cached. Nothing to do.")
return
print(f"\nGenerating {len(todo)} combos…\n")
for i, (face, clothing) in enumerate(todo, 1):
cached = CACHE_DIR / f"{face}_{clothing}.png"
face_path = FACE_DIR / f"{face}.jpg"
clothing_path = CLOTHES_DIR / f"{clothing}.webp"
print(f"[{i}/{len(todo)}] face={face} clothing={clothing} …", flush=True)
try:
result = await client.product_to_model(
product_image=to_data_url(clothing_path),
face_reference=to_data_url(face_path),
aspect_ratio="3:4",
generation_mode="balanced",
resolution="1k",
num_images=1,
output_format="png",
)
except FashnError as e:
print(f" FAILED: {e}")
continue
output = result.get("output") or []
if not output:
print(" FAILED: no output returned")
continue
try:
await fetch_to_file(output[0], cached)
print(f" ✓ saved {cached.name}")
except Exception as e:
print(f" FAILED to download: {e}")
print("\nDone.")
if __name__ == "__main__":
asyncio.run(main())