Wdróż · Virtual Try-On

Zbuduj funkcję virtual try-on dla swojej aplikacji

W jednym zdaniu

Odbierz zdjęcie produktu w swoim backendzie, wyślij żądanie POST do /api/v1/tryon/apparel z mannequin ID, odpytuj zwrócony generation ID w tle za pomocą workera (nigdy w wątku żądania HTTP) do momentu, aż status zmieni się na completed, a następnie zapisz output_url we własnym object storage i wyrenderuj go w UI.

  • Credits: 5 credits w 2K · 6 credits w 4K
  • Typowy czas: 1.5–4 min
  • Przetwarzanie: asynchroniczne, polling

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

Sprawdzony na produkcji schemat: klient przesyła zdjęcie produktu, Twój backend kolejkuje zadanie try-on w Photta, worker wykonuje polling do momentu zakończenia, a frontend wyświetla wynik na modelu. Bez blokujących żądań, bez wyciekających kluczy API, bez sztucznych SDK.

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')

Jak to działa

Od uploadu do zdjęcia na modelu

Sześć konkretnych kroków. Przy pierwszym podejściu zarezerwuj od dziesięciu do piętnastu minut na integrację.

  1. Krok 1

    Rozrysuj przepływ danych

    Urządzenie klienta → Twój backend (upload) → Photta API (submit) → Photta API (polling) → Twoja baza danych (odzwierciedlenie statusu) → urządzenie klienta (renderowanie). Rozrysuj to na kartce przed napisaniem pierwszej linijki kodu — granica między Twoim backendem a Photta to jedyna rzecz, która ma znaczenie.

  2. Krok 2

    Wygeneruj i zapisz klucz API

    Klucze produkcyjne zaczynają się od photta_live_. Zapisz go w zmiennej środowiskowej. Nigdy nie przesyłaj go do przeglądarki. Jeden klucz obsługuje każdą funkcjonalność Photta, więc nie potrzebujesz osobnych kluczy dla try-on, jewelry ani ghost mannequin.

  3. Krok 3

    Skonfiguruj endpoint do uploadu

    W pierwszej kolejności zapisz zdjęcie produktu przesłane przez klienta w object storage. Przekazanie do Photta publicznego URL jest prostsze niż base64 i zapewnia pełną ścieżkę audytu dla każdego żądania.

  4. Krok 4

    Zleć zadanie z poziomu serwera

    Wyślij POST do /api/v1/tryon/apparel z adresem URL produktu, mannequin_id, resolution oraz aspect_ratio. API zwróci kod 202 Accepted + generation ID. Zapisz ten ID w swojej bazie danych, aby klient mógł odpytywać Twój własny endpoint, a nie infrastrukturę Photta.

  5. Krok 5

    Wykonuj polling z poziomu workera działającego w tle

    Nie wykonuj operacji polling wewnątrz żądania HTTP — zadanie trwa od 1.5 do 4 minut, co przekracza limity timeoutu większości środowisk serverless. Użyj Trigger.dev, Inngest, BullMQ, Vercel Cron lub własnej kolejki, aby ponawiać polling co 3 sekundy do momentu ukończenia zadania.

  6. Krok 6

    Wyrenderuj wynik

    Gdy status zmieni się na completed, skopiuj data.output_url do swojej bazy danych i wyemituj zdarzenie w czasie rzeczywistym (WebSocket, SSE lub long-polling) do urządzenia klienta. UI podmienia placeholder ładowania na gotowy obraz. Gotowe.

Trzy przykłady kodu, end-to-end

Obsługa uploadu, dyspozytor zadań, worker realizujący polling — każdy komponent niezbędny do wdrożenia funkcji.

// POST /app/try-on → your backend upload handler
import { put } from "@vercel/blob";

export async function uploadProduct(file: File) {
  const { url } = await put(`products/${crypto.randomUUID()}.jpg`, file, {
    access: "public",
  });
  return url;
}
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.status
// Trigger.dev / Inngest / BullMQ task
const BASE = "https://api.photta.app/api/v1";

export const pollTryOnTask = task({
  id: "poll-try-on",
  run: async ({ generationId, attempt = 0 }) => {
    const res = await fetch(`${BASE}/tryon/apparel/${generationId}`, {
      headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` },
    });
    const { data } = await res.json();
    if (data.status === "completed") return data.output_url;
    if (data.status === "failed") throw new Error(data.error_message);
    if (attempt >= 120) throw new Error("try-on timed out");
    // Re-schedule this same task after 3 seconds.
    return ctx.retry.after(3000, { generationId, attempt: attempt + 1 });
  },
});

Pytania zadawane przez programistów

Pytania przed wdrożeniem produkcyjnym

Czy mogę to zrobić bez backendu?

Nie. Twój klucz API Photta musi pozostać po stronie serwera. Nawet prosty route handler w Next.js lub Cloudflare Worker liczy się w tym przypadku jako backend — klucz musi po prostu znajdować się w miejscu niedostępnym dla user-agenta.

Jak uniknąć zawieszających się żądań HTTP?

Nigdy nie wykonuj pollingu wewnątrz handlera żądania. Prześlij zadanie synchronicznie, zwróć identyfikator generowania do klienta i odpytuj z poziomu workera w tle. Klient odpytuje TWÓJ status endpoint, a nie Photta — dzięki temu limity zapytań (rate limits) są Twoim problemem do obsłużenia, a nie każdego użytkownika.

Co się stanie, jeśli zadanie nie powiedzie się w trakcie przetwarzania?

Photta automatycznie zwraca credits w przypadku niepowodzenia, a odpowiedź zawiera data.error_code + data.error_message. Wyświetl przystępny komunikat użytkownikowi i udostępnij przycisk ponowienia, który uruchamia nowe zadanie.

Czy mogę pokazać rzeczywisty postęp?

Photta nie emituje postępu pośredniego — status to processing, completed lub failed. Dobrze sprawdza się pasek postępu z timerem skalibrowanym pod okno 1.5–4 minut lub prosty skeleton loader. Nie przekłamuj wartości procentowych.

Czy URL wyniku jest stały?

URL z CDN jest stabilny, ale Twój produkt nie powinien polegać na nim przy długoterminowym renderowaniu. Pobierz bajty raz i zapisz je we własnym buckecie S3/GCS/R2 — wtedy Twoja strona produktu (PDP) nadal działa, nawet jeśli CDN Photta ulegnie zmianie.

Wdróż virtual try-on w jedno popołudnie

Każdy przykład kodu na tej stronie jest zgodny z oficjalną dokumentacją Photta. Pobierz klucz API, a będziesz mieć działający prototyp, zanim zaparzy się kawa.