Python · Ghost mannequin API

Ghost mannequin API di Python

Ringkasan singkat

Instal requests, muat PHOTTA_API_KEY dari env, tulis wrapper photta() yang mengirimkan Bearer key dan memunculkan PhottaError bertipe pada respons non-2xx, lalu kirim POST ke /api/v1/ghost-mannequin dan lakukan polling ke /api/v1/ghost-mannequin/{id} setiap 3 detik hingga status bernilai completed.

  • Waktu umum: 1.5–4 min
  • Credits: 4 credits pada 2K · 5 credits pada 4K
  • Pemrosesan: async, polling
  • Batasan: 600 requests/min
  • Autentikasi: Bearer key

Setiap angka di halaman ini bersumber dari dokumentasi API Photta · diperiksa

POST/api/v1/ghost-mannequin
import os, requests

res = requests.post(
    "https://api.photta.app/api/v1/ghost-mannequin",
    headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
    json={
      "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
      "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
      "image_side": "front",
      "angle": "side",
      "style": "3d",
      "background_color": "white",
      "resolution": "2K",
      "aspect_ratio": "3:4",
      "user_instruction": "closed front, cream interior lining",
      "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
    },
)
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/ghost-mannequin/{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")

Sekilas

Sekilas

Endpoint
POST /api/v1/ghost-mannequin
Autentikasi
API key Bearer
Pemrosesan
Asinkron — lakukan polling ke endpoint status
Waktu umum
1.5–4 min
Credits
4 credits pada 2K · 5 credits pada 4K
Rasio aspek
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Batas input
Hingga 10 MB per gambar; JPEG, PNG, WebP
Idempoten
Tidak

Cara kerja

Lima langkah, nol dependensi khusus Photta — requests mencakup segalanya.

  1. Langkah 1

    Daftar dan buat key

    Jalur yang sama seperti bahasa lainnya: ai.photta.app → Developers → Generate API key. Key dimulai dengan `photta_live_` dan bekerja di seluruh kapabilitas Photta.

  2. Langkah 2

    Muat key dari env

    Tetapkan `PHOTTA_API_KEY` di environment dan baca via `os.environ`. Di FastAPI atau Django, muat sekali saat booting ke dalam modul settings. Jangan sematkan key di kode sumber atau riwayat Git publik.

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

    Tulis wrapper requests

    Fungsi `photta_request()` sebanyak 30 baris menangani base URL, header Authorization, serialisasi JSON, dan translasi error. Hanya itu abstraksi yang Anda butuhkan sampai Python SDK dirilis.

    # 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. Langkah 4

    Kirim dan lakukan polling

    Lakukan POST ke `/api/v1/ghost-mannequin` untuk mendapatkan ID pembuatan, lalu lakukan polling ke `/api/v1/ghost-mannequin/{id}` dengan interval 3 detik. Di Celery atau RQ, bagi loop polling ke beberapa task agar pekerjaan yang memakan waktu beberapa menit tidak membebani worker.

    import os, requests
    
    res = requests.post(
        "https://api.photta.app/api/v1/ghost-mannequin",
        headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
        json={
          "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
          "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
          "image_side": "front",
          "angle": "side",
          "style": "3d",
          "background_color": "white",
          "resolution": "2K",
          "aspect_ratio": "3:4",
          "user_instruction": "closed front, cream interior lining",
          "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
        },
    )
    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/ghost-mannequin/{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. Langkah 5

    Simpan hasilnya secara permanen

    Payload completed mencakup `output_url` dan `thumbnail_url`. Unduh byte-nya ke object storage Anda sendiri — S3, GCS, Cloudflare R2 — agar produk Anda tidak terikat dengan CDN Photta untuk rendering jangka panjang.

Error

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", "/ghost-mannequin", json={
      "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
      "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
      "image_side": "front",
      "angle": "side",
      "style": "3d",
      "background_color": "white",
      "resolution": "2K",
      "aspect_ratio": "3:4",
      "user_instruction": "closed front, cream interior lining",
      "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
    })
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

Batasan

  • 600 request per menit per API key (Fixed window; batasannya sama di setiap paket)
  • Respons 429 menyertakan Retry-After: 30 detik
  • Hingga 10 MB per gambar
  • Format: JPEG, PNG, WebP
  • Batch konkuren per paket: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Hanya polling — API tidak mengirim webhook.

Alasan requests adalah pilihan yang tepat saat ini

  • Tanpa dependensi khusus Photta — requests sudah ada di sebagian besar proyek Python
  • Bisa berjalan di mana pun Python berjalan: Django, FastAPI, Flask, worker Celery, Lambda, skrip
  • Wrapper klien-nya hanya sekitar 30 baris — tempelkan ke photta.py dan lanjutkan pekerjaan Anda
  • Cocok dipadukan dengan asyncio via httpx jika Anda membutuhkan pengiriman paralel

Hal yang tidak dilakukannya

  • Belum ada package Python resmi untuk Photta — REST dengan requests adalah pola yang terdokumentasi
  • Polling adalah satu-satunya sinyal penyelesaian; API ini tidak mengirim webhook
  • Hanya menggunakan Bearer key; tidak ada alur client-credentials OAuth

Pertanyaan umum developer

Apakah ada SDK Python resmi untuk Photta?

Belum ada. Jalur integrasi yang didukung adalah library requests (sinkron) atau httpx (asinkron) — keduanya hanya membutuhkan wrapper tipis, dan wrapper di halaman ini berfungsi untuk setiap kapabilitas.

Versi Python mana saja yang didukung?

Python 3.9 dan yang lebih baru. Wrapper ini menggunakan type hints, f-strings, dan sintaks `str | None`, yang berjalan lancar di 3.10+. Pada 3.9, ubah `str | None` menjadi `Optional[str]`. requests sendiri secara resmi mendukung 3.8+, tetapi 3.9+ adalah batas minimum praktis untuk proyek Photta modern.

Sebaiknya saya menggunakan requests atau httpx?

Gunakan requests jika Anda hanya membuat beberapa panggilan berurutan — lebih sederhana dan sudah ada di sebagian besar codebase. Gunakan httpx jika Anda membutuhkan konkurensi asinkron (pengiriman paralel, backfill massal) atau HTTP/2. Bagaimanapun, wrapper-nya sangat ringkas; cukup ganti `requests.request` dengan `httpx.Client().request` dan sisa kodenya tetap identik.

Bisakah saya memanggilnya dari Django?

Bisa. Tempatkan wrapper di `services/photta.py`, lalu impor dari sebuah view atau task Celery. Jangan memanggil API di dalam request handler sinkron jika pekerjaannya membutuhkan waktu lama — kirim dari view, kembalikan ID pembuatan, lalu lakukan polling dari task latar belakang atau Channels consumer.

Bagaimana cara melakukan polling dari worker Celery?

Kirim pekerjaan dari satu task, lalu jadwalkan task lanjutan (melalui `apply_async(countdown=3)`) yang melakukan polling sekali dan menjadwalkan ulang dirinya sendiri hingga pekerjaan selesai atau mencapai batas maksimum percobaan ulang. Ini menjaga worker tetap bebas dan menghindari task yang berjalan terlalu lama yang dapat mengganggu autoscaler.

Bagaimana API memberikan sinyal error?

Respons non-2xx menyertakan body JSON dengan objek `error`: `type`, `code`, `message`, ditambah `param` pada 400 dan `retry_after` pada 429. Wrapper di halaman ini memicu `PhottaError` yang membawa semua informasi ini sehingga pemanggil Anda dapat membuat percabangan logika berdasarkan status code tanpa perlu mem-parsing body sendiri.

Coba API dalam lima menit

Buat Photta API key, tempel cuplikan cURL di atas, dan Anda akan mendapatkan gambar on-model pertama sebelum kopi selesai diseduh.

  • 1.5–4 min
  • 4 credits pada 2K · 5 credits pada 4K
  • async, polling
  • 600 requests/min
  • Bearer key