Byg · Django
Render try-on-billeder fra en Django-worker
I én sætning
En Django-integration gemmer én række per job, indsender fra en Celery-task, poller hvert 3. sekund indtil statussen er completed, og downloader derefter filen til dit eget lager.
- Credits: 5 credits ved 2K · 6 credits ved 4K
- Typisk tid: 1.5–4 min
- Behandling: async, polling
Hvert tal på denne side stammer fra Photta API-dokumentationen · tjekket
En model, der afspejler jobbet, en Celery-task, der indsender og poller, og lagerplads, der bevarer filen, efter leverings-URL'en er udløbet.
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"]Sådan virker det
Én række, én task, én fil
Modellér jobbet, indsend fra en task, poll med backoff, gem filen, eksponér statussen.
Trin 1
Modellér jobbet
Én række per generering: produktet, genererings-id'et, statussen og output-URL'en. Rækken er det, dine views læser; API'et er det, workeren læser.
Trin 2
Hent en Photta API-nøgle
Læs den fra miljøet i settings, aldrig fra databasen, og brug en separat nøgle per miljø, så et staging-læk ikke kan bruge produktions-credits.
Trin 3
Indsend i en task
Views bør returnere med det samme. Celery-tasken POSTer jobbet og skriver det returnerede id på rækken.
Trin 4
Poll med backoff
Poll hvert 3. sekund, indtil statussen er completed eller failed. Ved en 429 skal du vente det antal sekunder, Retry-After angiver, i stedet for at prøve igen med det samme.
Trin 5
Gem filen permanent
Download det færdige billede til dit eget lager. URL'en leverer ét job; din bucket er det, der serverer produktsiden i årevis.
Trin 6
Eksponér statussen
Din frontend poller din række, ikke Photta API'et. Det holder nøglen på serveren og lader dig vise fremskridt præcis, som du vil.
Model, task, fejl, lagring
Indsend-og-poll samt fejlhåndteringen er gengivet fra API-dokumentationen.
# 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"])Spørgsmål udviklere stiller
Spørgsmål Django-udviklere stiller
Hvorfor en worker i stedet for et view?
En generering tager længere tid, end et request bør tage. En worker overlever en lukket fane i browseren, et deploy og et timeout; et view overlever ingen af delene.
Hvor længe bør tasken polle?
Længe nok til endpointets dokumenterede latenstid, med et loft. Eksemplerne her stopper efter et fast antal forsøg i stedet for at polle for evigt.
Kan jeg bruge asynkron Django i stedet for Celery?
Ja — kaldene er ren HTTP. Det afgørende er, at arbejdet lever længere end requestet, uanset hvordan du strukturerer det.
Hvordan tester jeg uden at bruge credits?
Optag ét reelt svar, og afspil det igen i tests. Ressource-endpoints og detaljefotoanalysen er gratis, så kontrol af nøgle og forbindelser koster ingenting.
Kan én nøgle bruges i alle miljøer?
Det kan den, men alle nøgler trækker på samme saldo, så et loop i staging dræner produktions-credits. Separate nøgler gør skaden synlig og nem at stoppe.
Relaterede sider
Relateret læsning
Funktioner
Virtuel try-on API til tøj
REST API, der placerer tøj på AI-mannequiner. Asynkront, 1.5–4 minutters generering, 5 credits ved 2K, 6 ved 4K. cURL-, Node.js- og Python-eksempler.
LæsHurtig start
Første Photta-billede på under fem minutter.
Opret en konto, generer en API-nøgle, kør dit første cURL-kald, foretag polling indtil det er fuldført, gem resultatet. Fem trin, dokumenteret fra start til slut.
LæsSprog
Python walkthrough
LæsErrors
Læs
Hvert tal på denne side stammer fra Photta API-dokumentationen · tjekket
En worker, en række og en fil
Indsend-og-poll på denne side er gengivet fra API-dokumentationen.