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
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')
# $ID is data.id from the POST response. Poll every 3 seconds until status is "completed" or "failed".
for i in $(seq 1 120); do
RESULT=$(curl -s "https://api.photta.app/api/v1/tryon/apparel/$ID" -H "Authorization: Bearer $PHOTTA_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.data.status')
[ "$STATUS" = "completed" ] && break
[ "$STATUS" = "failed" ] && echo "generation failed" && exit 1
sleep 3
done
echo "$RESULT" | jq -r '.data.output_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
async function waitFor(id) {
for (let attempt = 0; attempt < 120; attempt++) {
const res = await fetch(`https://api.photta.app/api/v1/tryon/apparel/${id}`, { 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 ?? "generation failed");
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error("timed out after 6 minutes");
}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ứ.
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.
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"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 bodyBướ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")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
- 400
invalid_request_error - The request is malformed or contains invalid parameters.
- 401
authentication_error - The API key is missing, invalid, or expired.
- 402
insufficient_credits_error - Your account does not have enough credits.
- 404
not_found_error - The requested resource does not exist.
- 409
conflict_error - The request conflicts with current state — e.g. your concurrent-batch cap is reached.
- 429
rate_limit_error - Too many requests. Slow down and retry.Retry-After: 30
- 500
api_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:
raiseGiớ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
Node.js
Virtual try-on API trong Node.js
Gọi virtual try-on API của Photta từ backend Node.js bằng fetch gốc. Không cần SDK: chỉ cần lưu key, gửi job và poll kết quả.
ĐọccURL
Virtual try-on API với cURL
Gọi trực tiếp virtual try-on API của Photta từ shell bằng cURL. Gửi request, poll, tải về — mọi snippet đều kết hợp hoàn hảo với jq cho các script pipeline.
ĐọcTính năng
Virtual try-on API cho trang phục
REST API giúp mặc trang phục lên mannequin AI. Bất đồng bộ, thời gian tạo 1.5–4 phút, 5 credits ở 2K, 6 ở 4K. Kèm ví dụ cURL, Node.js và Python.
ĐọcXây dựng
Xây dựng tính năng virtual try-on cho ứng dụng của bạn
Quy trình end-to-end để triển khai tính năng virtual try-on với Photta API: tải lên, gửi yêu cầu, polling từ worker, kết xuất kết quả. Kiến trúc chuẩn server-only với TypeScript.
ĐọcXây dựng
Thêm virtual try-on vào ứng dụng iOS hoặc Android
Cách tích hợp AI virtual try-on vào ứng dụng native iOS hoặc Android bằng Photta API: tuyệt đối không đưa key vào thiết bị, dùng proxy qua backend của bạn, đồng bộ trạng thái job.
ĐọcBắt đầu nhanh
Tạo ảnh Photta đầu tiên trong vòng chưa đầy năm phút.
Đăng ký, tạo API key, chạy lệnh cURL đầu tiên, polling cho đến khi hoàn thành, lưu trữ kết quả. Năm bước, có tài liệu hướng dẫn trọn gói từ đầu đến cuối.
ĐọcTài liệu tham khảo
Bảng giá Photta API
Chi phí tính bằng credits cho từng endpoint của Photta API ở độ phân giải 2K và 4K, cơ chế trừ phí và hoàn tiền, cùng các endpoint miễn phí. Không tính giá tiền trực tiếp trên từng ảnh.
Đọc
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