import os, sys, time, requests
BASE = os.environ.get("GENLOOK_BASE_URL", "https://api.genlook.app/tryon/v1")
API_KEY = os.environ["GENLOOK_API_KEY"] # required
session = requests.Session()
session.headers["x-api-key"] = API_KEY
# ── 1. Upload the customer photo once ───────────────────────
def upload_customer(file_path: str, *, crop: bool = True) -> str:
"""Returns an imageId you can reuse across many generations."""
with open(file_path, "rb") as f:
r = session.post(
f"{BASE}/images/upload",
files={"file": (os.path.basename(file_path), f, "image/jpeg")},
data={"crop": "true" if crop else "false"},
)
r.raise_for_status()
return r.json()["imageId"]
# ── 2. Try-on with ref-first, upsert-on-miss ────────────────
def try_on(image_id: str, external_id: str, full_payload: dict) -> str:
"""Reference the product if it's cached; full inline upsert if it's not.
`full_payload` is the dict you'd pass as the single `products[]` item to upsert: at
minimum `{title, description, images: [{source: {url|fileKey}}, ...]}`. The function
adds `externalId` for you.
"""
# First attempt: pure reference (cheap)
r = session.post(
f"{BASE}/try-on",
json={
"products": [{"externalId": external_id}],
"person": {"image": {"source": {"id": image_id}}},
},
)
if r.status_code == 404 and r.json().get("code") == "PRODUCT_NOT_FOUND":
# TTL expired (or first time we've seen this externalId). Upsert + retry.
r = session.post(
f"{BASE}/try-on",
json={
"products": [{**full_payload, "externalId": external_id}],
"person": {"image": {"source": {"id": image_id}}},
},
)
r.raise_for_status()
body = r.json()
print(f"Generation queued: {body['generationId']} product={body['productExternalId']}")
return body["generationId"]
# ── 3. Poll until done ──────────────────────────────────────
def poll(generation_id: str, *, timeout_s: int = 180) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = session.get(f"{BASE}/generations/{generation_id}")
r.raise_for_status()
data = r.json()
status = data["status"]
print(f" {int(time.time() - (deadline - timeout_s)):3d}s {status}")
if status == "COMPLETED":
return data
if status == "FAILED":
sys.exit(f"Generation failed: {data.get('errorMessage')}")
time.sleep(2)
sys.exit("Timed out")
# ── Run it ──────────────────────────────────────────────────
if __name__ == "__main__":
CUSTOMER_PHOTO = "./customer.jpg"
PRODUCT = {
"title": "Red tee",
"description": "Soft cotton regular fit",
"images": [{"source": {"url": "https://cdn.example.com/red-tee.jpg"}}],
}
EXTERNAL_ID = "shirt-42"
image_id = upload_customer(CUSTOMER_PHOTO)
print(f"Customer uploaded: {image_id}")
# Try a generation. Works on a cold start (will upsert) and on subsequent
# calls (will just reference). Idempotent either way.
gen_id = try_on(image_id, EXTERNAL_ID, PRODUCT)
result = poll(gen_id)
print(f"\n→ {result['resultImageUrl']}")