Python · API wirtualnego try-on

API wirtualnego try-on w Python

W jednym zdaniu

Zainstaluj requests, załaduj PHOTTA_API_KEY z env, napisz wrapper photta(), który wysyła klucz Bearer i rzuca typowany PhottaError przy odpowiedziach innych niż 2xx, a następnie wyślij POST do /api/v1/tryon/apparel i wykonuj polling /api/v1/tryon/apparel/{id} co 3 sekundy, aż status zmieni się na completed.

  • Typowy czas: 1.5–4 min
  • Credits: 5 credits w 2K · 6 credits w 4K
  • Przetwarzanie: asynchroniczne, polling
  • Limity: 600 requests/min
  • Uwierzytelnianie: Klucz Bearer

Każda liczba na tej stronie pochodzi z dokumentacji API Photta · sprawdzono

POST/api/v1/tryon/apparel
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")

W skrócie

W skrócie

Endpoint
POST /api/v1/tryon/apparel
Uwierzytelnianie
Klucz API Bearer
Przetwarzanie
Asynchroniczne — odpytuj endpoint statusu
Typowy czas
1.5–4 min
Credits
5 credits w 2K · 6 credits w 4K
Proporcje obrazu
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Limity wejściowe
Do 10 MB na obraz; JPEG, PNG, WebP
Idempotentne
Nie

Jak to działa

Pięć kroków, zero specyficznych zależności dla Photta — requests załatwia wszystko.

  1. Krok 1

    Zarejestruj się i wygeneruj klucz

    Taka sama ścieżka jak w każdym innym języku: ai.photta.app → Developers → Generate API key. Klucze zaczynają się od `photta_live_` i działają we wszystkich capabilities Photta.

  2. Krok 2

    Załaduj klucz z env

    Ustaw `PHOTTA_API_KEY` w środowisku i odczytuj go przez `os.environ`. W FastAPI lub Django załaduj go raz podczas startu do modułu ustawień. Nie umieszczaj klucza w kodzie źródłowym ani w publicznej historii Git.

    python3 -m pip install requests
    export PHOTTA_API_KEY="photta_live_xxxxx"
  3. Krok 3

    Napisz wrapper requests

    Trzydziestoliniowa funkcja `photta_request()` obsługuje bazowy URL, nagłówek Authorization, serializację JSON i mapowanie błędów. To jedyna abstrakcja, jakiej potrzebujesz do czasu wydania SDK dla języka Python.

    # photta.py — one helper for every endpoint
    import os, requests
    BASE = "https://api.photta.app/api/v1"
    
    class PhottaError(Exception):
        def __init__(self, status, error, retry_after=None):
            super().__init__(error.get("message", "request failed"))
            self.status, self.type, self.retry_after = status, error.get("type"), retry_after
    
    def photta(method, path, **kwargs):
        res = requests.request(method, BASE + path, headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"}, timeout=30, **kwargs)
        body = res.json()
        if not res.ok:
            raise PhottaError(res.status_code, body.get("error", {}), res.headers.get("Retry-After"))
        return body
  4. Krok 4

    Wyślij i odpytuj (poll)

    Wykonaj POST pod `/api/v1/tryon/apparel`, aby pobrać ID generowania, a następnie odpytuj `/api/v1/tryon/apparel/{id}` w 3-sekundowym interwale. W Celery lub RQ rozbij pętlę pollingu na osobne zadania, aby wielominutowe zadanie nie blokowało workera.

    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")
  5. Krok 5

    Zapisz wynik

    Payload completed zawiera `output_url` oraz `thumbnail_url`. Pobierz bajty do własnego object storage — S3, GCS, Cloudflare R2 — dzięki czemu Twój produkt nie będzie zależny od CDN Photta w kwestii długoterminowego serwowania plików.

Błędy

400invalid_request_error
The request is malformed or contains invalid parameters.
401authentication_error
The API key is missing, invalid, or expired.
402insufficient_credits_error
Your account does not have enough credits.
404not_found_error
The requested resource does not exist.
409conflict_error
The request conflicts with current state — e.g. your concurrent-batch cap is reached.
429rate_limit_error
Too many requests. Slow down and retry.Retry-After: 30
500api_error
An internal server error occurred. Retry later.
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

Limity

  • 600 żądań na minutę na klucz API (Stałe okno czasowe; limit jest taki sam w każdym planie)
  • Odpowiedź 429 zawiera nagłówek Retry-After: 30 s
  • Do 10 MB na obraz
  • Formaty: JPEG, PNG, WebP
  • Jednoczesne zadania wsadowe w zależności od planu: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Tylko polling — API nie wysyła webhooków.

Dlaczego requests to dziś właściwy wybór

  • Brak specyficznych zależności od Photta — requests znajduje się już w większości projektów w Python
  • Działa wszędzie tam, gdzie Python: Django, FastAPI, Flask, workery Celery, Lambda, skrypty
  • Wrapper klienta ma około trzydziestu linii — wklej go do photta.py i przejdź do działania
  • Działa z asyncio poprzez httpx, gdy potrzebujesz równoległego wysyłania żądań

Czego nie robi

  • Brak oficjalnego pakietu Photta dla języka Python — udokumentowanym wzorcem jest REST z requests
  • Polling jest jedynym sygnałem ukończenia; API nie wysyła webhooków
  • Tylko klucz Bearer; brak przepływu OAuth client-credentials

Pytania zadawane przez programistów

Czy istnieje oficjalne SDK Photta dla języka Python?

Jeszcze nie. Wspieraną ścieżką integracji jest biblioteka requests (synchronicznie) lub httpx (asynchronicznie) — w obu przypadkach wystarczy lekki wrapper, a ten na tej stronie obsługuje każdą funkcjonalność.

Jakie wersje języka Python są wspierane?

Python 3.9 i nowsze. Wrapper korzysta z type hintów, f-stringów oraz składni `str | None`, co działa bez problemu w wersji 3.10+. W 3.9 zamień `str | None` na `Optional[str]`. Samo requests oficjalnie wspiera wersje 3.8+, ale 3.9+ to praktyczne minimum dla współczesnych projektów Photta.

Czy powinienem użyć requests czy httpx?

requests, jeśli wykonujesz kilka sekwencyjnych wywołań — jest prostsze i obecne w większości baz kodu. httpx, jeśli potrzebujesz asynchronicznej współbieżności (równoległe wysyłanie, masowe przetwarzanie wsadowe) lub HTTP/2. W obu przypadkach wrapper jest miniaturowy; zamień `requests.request` na `httpx.Client().request`, a reszta kodu pozostanie identyczna.

Czy mogę wywoływać API z poziomu Django?

Tak. Umieść wrapper w `services/photta.py`, importuj go z widoku lub zadania Celery. Nie wywołuj API wewnątrz synchronicznego handlera żądania, jeśli zadanie trwa długo — wyślij żądanie z widoku, zwróć ID generowania i odpytuj z zadania w tle lub konsumenta Channels.

Jak realizować polling z poziomu workera Celery?

Wyślij zadanie z jednego taska, a następnie zaplanuj kolejne zadanie (za pomocą `apply_async(countdown=3)`), które odpyta API raz i zaplanuje samo siebie ponownie, aż zadanie zakończy się powodzeniem lub osiągnie limit ponowień (max-retries). Zapobiega to blokowaniu workerów i eliminuje długo działające zadania, które zakłócają autoskalowanie.

Jak API sygnalizuje błędy?

Odpowiedzi inne niż 2xx zwracają body JSON z obiektem `error`: `type`, `code`, `message`, a także `param` dla kodów 400 i `retry_after` dla 429. Wrapper na tej stronie rzuca wyjątek `PhottaError` zawierający wszystkie te pola, dzięki czemu kod wywołujący może rozgałęziać logikę na podstawie kodu statusu bez konieczności samodzielnego parsowania body.

Powiązane strony

Każda liczba na tej stronie pochodzi z dokumentacji API Photta · sprawdzono

Wypróbuj API w 5 minut

Wygeneruj klucz Photta API, wklej powyższy snippet cURL, a otrzymasz swoje pierwsze zdjęcie na modelu, zanim zaparzy się kawa.

  • 1.5–4 min
  • 5 credits w 2K · 6 credits w 4K
  • asynchroniczne, polling
  • 600 requests/min
  • Klucz Bearer