Bouwen · Django
Genereer try-on-afbeeldingen via een Django-worker
In één zin
Een Django-integratie slaat één rij per job op, dient in vanuit een Celery-taak, pollt elke 3 seconden totdat de status completed is en downloadt het bestand vervolgens naar je eigen opslag.
- Credits: 5 credits bij 2K · 6 credits bij 4K
- Typische duur: 1.5–4 min
- Verwerking: async, polling
Elk getal op deze pagina is afkomstig uit de Photta-API-documentatie · gecontroleerd
Een model dat de job weerspiegelt, een Celery-taak die indient en pollt, en opslag die het bestand bewaart nadat de leverings-URL is verlopen.
RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}),
});
const { data } = await res.json(); // data.id, data.statusimport os, requests
res = requests.post(
"https://api.photta.app/api/v1/tryon/apparel",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": True,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
},
)
data = res.json()["data"] # data["id"], data["status"]Hoe het werkt
Eén rij, één taak, één bestand
Modelleer de job, dien in vanuit een taak, poll met backoff, sla het bestand op, toon de status.
Stap 1
Modelleer de job
Eén rij per generatie: het product, de generatie-id, de status en de output-URL. De rij is wat je views lezen; de API is wat de worker leest.
Stap 2
Vraag een Photta API-sleutel aan
Lees deze uit de omgeving in settings, nooit uit de database, en gebruik een aparte sleutel per omgeving zodat een staging-lek geen productie-credits kan verbruiken.
Stap 3
Dien in binnen een taak
Views moeten direct retourneren. De Celery-taak POST de job en schrijft de geretourneerde id naar de rij.
Stap 4
Poll met backoff
Poll elke 3 seconden totdat de status completed of failed is. Wacht bij een 429 het aantal Retry-After seconden in plaats van direct opnieuw te proberen.
Stap 5
Sla het bestand op
Download de voltooide afbeelding naar je eigen opslag. De URL levert één job op; jouw bucket is wat de productpagina jarenlang bedient.
Stap 6
Toon de status
Je frontend pollt jouw rij, niet de Photta API. Daarmee blijft de sleutel op de server en kun je de voortgang tonen zoals je zelf wilt.
Model, taak, fouten, opslag
Het indienen-en-pollen en de foutafhandeling zijn gegenereerd vanuit de API-documentatie.
# store/models.py
from django.db import models
class TryOn(models.Model):
product = models.ForeignKey("Product", on_delete=models.CASCADE)
generation_id = models.CharField(max_length=64, db_index=True)
status = models.CharField(max_length=16, default="processing")
output_url = models.URLField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)# store/tasks.py
from celery import shared_task
@shared_task(bind=True, max_retries=3)
def run_try_on(self, try_on_id):
import os, requests
res = requests.post(
"https://api.photta.app/api/v1/tryon/apparel",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": True,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
},
)
data = res.json()["data"] # data["id"], data["status"]
import time
def wait_for(job_id):
for _ in range(120):
res = requests.get(f"https://api.photta.app/api/v1/tryon/apparel/{job_id}", headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"})
data = res.json()["data"]
if data["status"] == "completed":
return data["output_url"]
if data["status"] == "failed":
raise RuntimeError(data.get("error_message", "generation failed"))
time.sleep(3)
raise TimeoutError("timed out after 6 minutes")try:
photta("POST", "/tryon/apparel", json={
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": True,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
})
except PhottaError as e:
if e.status == 402:
print("insufficient_credits_error: top up before retrying")
elif e.status == 429:
time.sleep(int(e.retry_after or 30))
else:
raise# store/tasks.py — the output URL delivers one job; your storage keeps it
import requests
from django.core.files.base import ContentFile
def persist(try_on, output_url):
body = requests.get(output_url, timeout=60).content
try_on.product.gallery.save(f"{try_on.generation_id}.jpg", ContentFile(body))
try_on.status, try_on.output_url = "completed", output_url
try_on.save(update_fields=["status", "output_url"])Veelgestelde vragen van developers
Vragen van Django-ontwikkelaars
Waarom een worker in plaats van een view?
Een generatie duurt langer dan een request zou moeten duren. Een worker overleeft een gesloten browsertabblad, een deploy en een time-out; een view overleeft geen van deze.
Hoe lang moet de taak pollen?
Lang genoeg voor de gedocumenteerde latentie van het endpoint, met een limiet. De voorbeelden hier stoppen na een vast aantal pogingen in plaats van oneindig te pollen.
Kan ik asynchrone Django gebruiken in plaats van Celery?
Ja — de aanroepen zijn eenvoudige HTTP. Het belangrijkste is dat het werk het request overleeft, hoe je het ook inricht.
Hoe test ik zonder credits te verbruiken?
Neem één echte response op en speel deze opnieuw af in tests. De resource-endpoints en de detailfoto-analyse zijn gratis, dus sleutel- en connectiviteitscontroles kosten niets.
Kan één sleutel voor elke omgeving worden gebruikt?
Dat kan, maar elke sleutel gebruikt hetzelfde saldo, dus een staging-loop verbruikt productie-credits. Aparte sleutels maken schade zichtbaar en eenvoudig te stoppen.
Gerelateerde pagina's
Gerelateerde artikelen
Mogelijkheden
Virtual try-on API voor kleding
REST API die kleding op AI-mannequins plaatst. Asynchroon, generatie in 1.5–4 minuten, 5 credits bij 2K, 6 bij 4K. Voorbeelden in cURL, Node.js en Python.
LezenSnelstartgids
Eerste Photta-afbeelding in minder dan vijf minuten.
Registreer je, genereer een API-sleutel, voer je eerste cURL-call uit, poll totdat deze is voltooid, sla het resultaat op. Vijf stappen, end-to-end gedocumenteerd.
LezenTalen
Python walkthrough
LezenErrors
Lezen
Elk getal op deze pagina is afkomstig uit de Photta-API-documentatie · gecontroleerd
Een worker, een rij en een bestand
Het indienen-en-pollen op deze pagina is gegenereerd vanuit de API-documentatie.