Python · Virtual try-on API

Virtual try-on API bằng Python

Tóm tắt trong một câu

Cài đặt requests, nạp PHOTTA_API_KEY từ env, viết wrapper photta() gửi khóa Bearer và raise PhottaError có định kiểu khi gặp phản hồi non-2xx, sau đó POST tới /api/v1/tryon/apparel và poll /api/v1/tryon/apparel/{id} mỗi 3 giây cho đến khi status là completed.

  • Thời gian điển hình: 1.5–4 min
  • Credits: 5 credits ở 2K · 6 credits ở 4K
  • Xử lý: async, polling
  • Giới hạn: 600 requests/min
  • Xác thực: Bearer key

Mọi số liệu trên trang này đều lấy từ tài liệu Photta API · đã kiểm tra

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

Tổng quan nhanh

Tổng quan nhanh

Endpoint
POST /api/v1/tryon/apparel
Xác thực
Bearer API key
Xử lý
Bất đồng bộ — polling status endpoint
Thời gian điển hình
1.5–4 min
Credits
5 credits ở 2K · 6 credits ở 4K
Tỷ lệ khung hình
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Giới hạn đầu vào
Tối đa 10 MB mỗi ảnh; JPEG, PNG, WebP
Idempotent
Không

Cơ chế hoạt động

Năm bước, không phụ thuộc thư viện riêng của Photta — requests đáp ứng mọi thứ.

  1. Bước 1

    Đăng ký và tạo khóa

    Quy trình tương tự như mọi ngôn ngữ khác: ai.photta.app → Developers → Generate API key. Khóa bắt đầu bằng `photta_live_` và dùng được cho mọi capability của Photta.

  2. Bước 2

    Nạp khóa từ env

    Đặt `PHOTTA_API_KEY` trong môi trường và đọc qua `os.environ`. Trong FastAPI hoặc Django, nạp khóa một lần khi khởi động vào module settings. Không nhúng khóa vào mã nguồn hoặc lịch sử Git công khai.

    python3 -m pip install requests
    export PHOTTA_API_KEY="photta_live_xxxxx"
  3. Bước 3

    Viết một requests wrapper

    Một hàm `photta_request()` khoảng ba mươi dòng sẽ xử lý base URL, header Authorization, serialize JSON và dịch lỗi. Đó là lớp abstraction duy nhất bạn cần cho đến khi Python SDK chính thức ra mắt.

    # 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. Bước 4

    Gửi request và poll

    Gửi POST đến `/api/v1/tryon/apparel` để lấy generation ID, sau đó poll `/api/v1/tryon/apparel/{id}` theo chu kỳ 3 giây. Trong Celery hoặc RQ, hãy tách vòng lặp poll thành các task riêng biệt để một job kéo dài nhiều phút không chiếm dụng worker.

    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. Bước 5

    Lưu trữ kết quả

    Payload khi hoàn thành bao gồm `output_url` và `thumbnail_url`. Hãy tải các byte dữ liệu về object storage của riêng bạn — S3, GCS, Cloudflare R2 — để sản phẩm của bạn không bị phụ thuộc vào CDN của Photta khi cần hiển thị lâu dài.

Lỗi

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

Giới hạn

  • 600 request mỗi phút trên mỗi API key (Fixed window; giới hạn như nhau trên mọi gói)
  • Mã 429 kèm header Retry-After: 30 giây
  • Tối đa 10 MB mỗi ảnh
  • Định dạng: JPEG, PNG, WebP
  • Batch đồng thời theo từng gói: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Chỉ hỗ trợ polling — API không gửi webhook.

Vì sao requests là lựa chọn chuẩn xác hiện nay

  • Không phụ thuộc vào thư viện riêng của Photta — requests vốn đã có sẵn trong hầu hết các dự án Python
  • Hoạt động ở mọi môi trường chạy Python: Django, FastAPI, Flask, Celery workers, Lambda, script
  • Client wrapper chỉ khoảng ba mươi dòng — dán vào photta.py là xong
  • Kết hợp mượt mà với asyncio qua httpx khi bạn cần gửi song song nhiều request

Những gì nó không hỗ trợ

  • Chưa có package Python chính thức từ Photta — REST với requests là chuẩn mẫu được ghi nhận trong tài liệu
  • Polling là tín hiệu hoàn thành duy nhất; API không gửi webhook
  • Chỉ dùng Bearer key; không có luồng client-credentials của OAuth

Câu hỏi thường gặp từ developer

Đã có Photta Python SDK chính thức chưa?

Chưa. Phương thức tích hợp được hỗ trợ hiện tại là thư viện requests (đồng bộ) hoặc httpx (bất đồng bộ) — cả hai chỉ cần một wrapper mỏng, và wrapper trên trang này hoạt động với mọi capability.

Những phiên bản Python nào được hỗ trợ?

Python 3.9 trở lên. Wrapper sử dụng type hints, f-strings và cú pháp `str | None`, vốn hoạt động tốt trên 3.10+. Trên 3.9, hãy đổi `str | None` thành `Optional[str]`. Bản thân requests hỗ trợ chính thức 3.8+, nhưng 3.9+ là mức tối thiểu trên thực tế cho các dự án Photta hiện đại.

Tôi nên dùng requests hay httpx?

Dùng requests nếu bạn chỉ thực hiện một vài lệnh gọi tuần tự — nó đơn giản hơn và đã có sẵn trong hầu hết codebase. Dùng httpx nếu bạn cần xử lý đồng thời bất đồng bộ (gửi song song nhiều request, backfill hàng loạt) hoặc HTTP/2. Wrapper đều rất gọn trong cả hai trường hợp; chỉ cần đổi `requests.request` thành `httpx.Client().request` là phần code còn lại giữ nguyên.

Tôi có thể gọi API từ Django không?

Có. Đặt wrapper vào `services/photta.py`, import nó từ một view hoặc một Celery task. Đừng gọi API bên trong request handler đồng bộ nếu job xử lý lâu — hãy gửi request từ view, trả về generation ID, rồi poll từ một background task hoặc một Channels consumer.

Làm cách nào để poll từ một Celery worker?

Gửi job từ một task, sau đó lên lịch cho một task tiếp nối (qua `apply_async(countdown=3)`) để poll một lần rồi tự lên lịch lại cho chính nó cho đến khi job hoàn tất hoặc chạm ngưỡng max-retries. Cách này giúp giải phóng worker và tránh các task chạy kéo dài làm ảnh hưởng đến cơ chế autoscale.

API báo lỗi như thế nào?

Các response khác 2xx sẽ trả về body JSON chứa object `error`: `type`, `code`, `message`, cùng với `param` đối với lỗi 400 và `retry_after` đối với lỗi 429. Wrapper trên trang này sẽ throw một `PhottaError` chứa toàn bộ các trường trên, giúp code gọi API có thể phân nhánh theo status code mà không cần tự parse body.

Các trang liên quan

Mọi số liệu trên trang này đều lấy từ tài liệu Photta API · đã kiểm tra

Thử nghiệm API trong năm phút

Tạo một Photta API key, dán đoạn mã cURL ở trên, và bạn sẽ nhận được bức ảnh mẫu mặc đồ đầu tiên trước khi pha xong ly cà phê.

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