Bygg · Django
Rendera try-on-bilder från en Django-worker
I en mening
En Django-integration sparar en rad per jobb, skickar från en Celery-task, pollar var 3:e sekund tills status är completed, och laddar sedan ned filen till din egen lagring.
- Credits: 5 credits vid 2K · 6 credits vid 4K
- Typisk tid: 1.5–4 min
- Bearbetning: asynkron, polling
Varje siffra på den här sidan kommer från Photter API-dokumentationen · kontrollerad
En modell som speglar jobbet, en Celery-task som skickar och genomför polling samt lagring som behåller filen efter att leverans-URL:en har försvunnit.
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"]Hur det fungerar
En rad, en task, en fil
Modellera jobbet, skicka från en task, polla med backoff, spara filen, exponera statusen.
Steg 1
Modellera jobbet
En rad per generering: produkten, genererings-id, status och output-URL. Raden är vad dina views läser; API:et är vad din worker läser.
Steg 2
Hämta en Photta API-nyckel
Läs den från miljön i settings, aldrig från databasen, och använd en separat nyckel per miljö så att en läcka i staging inte kan förbruka produktions-credits.
Steg 3
Skicka i en task
Views bör svara direkt. Celery-tasken gör en POST av jobbet och skriver det returnerade id:t till raden.
Steg 4
Polla med backoff
Polla var 3:e sekund tills status är completed eller failed. Vid 429, vänta antalet sekunder i Retry-After istället för att försöka igen omedelbart.
Steg 5
Spara filen
Ladda ned den färdiga bilden till din egen lagring. URL:en levererar ett jobb; din bucket är det som servar produktsidan i flera år.
Steg 6
Exponera statusen
Ditt gränssnitt pollar din rad, inte Photta API:et. Det håller nyckeln på servern och låter dig visa förloppet precis som du vill.
Modell, task, fel, lagring
Submit-and-poll och felhanteringen genereras från 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"])Vanliga utvecklarfrågor
Frågor som Django-utvecklare ställer
Varför en worker istället för en view?
En generering tar längre tid än en request bör ta. En worker överlever en stängd webbläsarflik, en driftsättning och en timeout; en view överlever inget av dem.
Hur länge ska tasken polla?
Tillräckligt länge för endpointens dokumenterade latens, med ett tak. Exemplen här avbryter efter ett fast antal försök istället för att polla i all oändlighet.
Kan jag använda asynkron Django istället för Celery?
Ja — anropen är vanlig HTTP. Det viktiga är att arbetet överlever requesten, oavsett hur du strukturerar det.
Hur testar jag utan att förbruka credits?
Spela in ett riktigt svar och återuppspela det i testerna. Resurs-endpoints och detaljfotoanalysen är gratis, så nyckel- och anslutningskontroller kostar ingenting.
Kan en nyckel användas i alla miljöer?
Det går, men varje nyckel förbrukar samma saldo, så en loop i staging tömmer dina produktions-credits. Separata nycklar gör skadan synlig och enkel att stoppa.
Relaterade sidor
Relaterad läsning
Funktioner
API för virtuell try-on för apparel
REST API som placerar kläder på AI-mannekänger. Asynkron, 1,5–4 minuters generering, 5 credits vid 2K, 6 vid 4K. Exempel för cURL, Node.js och Python.
LäsSnabbstart
Första Photta-bilden på under fem minuter.
Skapa konto, generera en API-nyckel, kör ditt första cURL-anrop, polla tills det är klart, spara resultatet. Fem steg, dokumenterade från början till slut.
LäsSpråk
Python walkthrough
LäsErrors
Läs
Varje siffra på den här sidan kommer från Photter API-dokumentationen · kontrollerad
En worker, en rad och en fil
Submit-and-poll på den här sidan genereras från API-dokumentationen.