Python · 가상 피팅 API
Python 가상 피팅 API
pip install photta는 필요하지 않습니다. Photta 문서는 공식적으로 requests 라이브러리를 권장합니다. 30줄 정도의 래퍼 코드로 Django, FastAPI, Celery 워커, Lambda 핸들러에 간편하게 통합할 수 있습니다.
요약
`requests`를 설치하고 환경 변수에서 `PHOTTA_API_KEY`를 로드한 뒤, `Authorization: Bearer photta_live_xxx`를 전송하고 에러 발생 시 예외를 던지는 `photta_request()` 래퍼를 작성하세요. `/tryon/apparel`로 POST하고 `data.status == 'completed'`가 될 때까지 3초마다 `/tryon/apparel/:id`를 폴링하세요. 보통 1.5~4분 소요됩니다.
업데이트됨 · 2026-04-19
첫 번째 요청
import time
from photta import photta_request, PhottaError
# 1. Submit the job
created = photta_request("POST", "/tryon/apparel", json={
"product_type": "dress",
"product_images": ["https://example.com/dress.jpg"],
"mannequin_id": "mnq_athena_ts",
"pose_id": "pose_standing_front",
"resolution": "2K",
"aspect_ratio": "3:4",
})
generation_id = created["data"]["id"]
# 2. Poll every 3 seconds. Upper bound: 120 attempts ≈ 6 minutes,
# comfortably above the documented 1.5–4 minute window.
for _ in range(120):
result = photta_request("GET", f"/tryon/apparel/{generation_id}")
status = result["data"]["status"]
if status == "completed":
print("Result:", result["data"]["output_url"])
break
if status == "failed":
raise RuntimeError(result["data"]["error_message"])
time.sleep(3)기대 효과
Typical completion
1.5–4min
2K / 4K credits
5 / 7
Aspect ratios
5
Product types
6
작동 원리
Python 가상 피팅 API
5단계, Photta 전용 의존성 없음 — requests 하나면 충분합니다.
- 01
단계 1
가입 및 키 생성
다른 언어와 동일합니다: ai.photta.app → 개발자 → API 키 생성. `photta_live_`로 시작하는 키는 모든 Photta 기능에 공통으로 사용됩니다.
- 02
단계 2
환경 변수에서 키 로드
환경 변수에 `PHOTTA_API_KEY`를 설정하고 `os.environ`으로 읽으세요. FastAPI나 Django에서는 부팅 시 한 번 설정 모듈로 로드하는 것이 좋습니다. 소스 코드나 공용 Git 기록에 키를 포함하지 마세요.
- 03
단계 3
requests 래퍼 작성
Base URL, Authorization 헤더, JSON 직렬화 및 에러 변환을 처리하는 30줄 정도의 `photta_request()` 함수를 만듭니다. Python SDK가 출시되기 전까지는 이 추상화만으로 충분합니다.
- 04
단계 4
제출 및 폴링
`/tryon/apparel`로 POST하여 생성 ID를 받은 뒤, 3초 간격으로 `/tryon/apparel/:id`를 폴링하세요. Celery나 RQ 환경에서는 4분간 워커가 점유되지 않도록 폴링 루프를 작업 단위로 나누어 설계하세요.
- 05
단계 5
결과 저장
완료된 페이로드의 `output_url` 및 `thumbnail_url`을 확인하세요. 장기적인 렌더링을 위해 Photta CDN에 묶이지 않도록 바이트 데이터를 S3, GCS, Cloudflare R2 등 자체 스토리지에 다운로드하여 보관하세요.
전체 코드
Copy, paste, done.
Four snippets — install prerequisites, wrap the REST call, submit + poll, then handle the errors that actually happen in production.
# Photta doesn't ship an official Python SDK yet — requests is the
# recommended path in the docs. Standard library urllib works too if
# you need zero dependencies.
pip install requests
# Store your API key in env (dotenv optional but convenient)
echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env# photta.py
import os
import requests
PHOTTA_BASE_URL = "https://ai.photta.app/api/v1"
class PhottaError(Exception):
def __init__(self, status: int, code: str, message: str, retry_after: int | None = None):
super().__init__(message)
self.status = status
self.code = code
self.retry_after = retry_after
def photta_request(method: str, path: str, **kwargs):
headers = {
"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}",
"Content-Type": "application/json",
**kwargs.pop("headers", {}),
}
response = requests.request(method, f"{PHOTTA_BASE_URL}{path}", headers=headers, **kwargs)
body = response.json()
if not response.ok:
err = body.get("error", {})
raise PhottaError(
status=response.status_code,
code=err.get("code", "unknown"),
message=err.get("message", response.reason),
retry_after=err.get("retry_after"),
)
return bodyimport time
from photta import photta_request, PhottaError
# 1. Submit the job
created = photta_request("POST", "/tryon/apparel", json={
"product_type": "dress",
"product_images": ["https://example.com/dress.jpg"],
"mannequin_id": "mnq_athena_ts",
"pose_id": "pose_standing_front",
"resolution": "2K",
"aspect_ratio": "3:4",
})
generation_id = created["data"]["id"]
# 2. Poll every 3 seconds. Upper bound: 120 attempts ≈ 6 minutes,
# comfortably above the documented 1.5–4 minute window.
for _ in range(120):
result = photta_request("GET", f"/tryon/apparel/{generation_id}")
status = result["data"]["status"]
if status == "completed":
print("Result:", result["data"]["output_url"])
break
if status == "failed":
raise RuntimeError(result["data"]["error_message"])
time.sleep(3)from photta import photta_request, PhottaError
import time
try:
photta_request("POST", "/tryon/apparel", json={ ... })
except PhottaError as err:
if err.status == 402:
# Out of credits — err.code == "insufficient_credits"
raise
elif err.status == 429:
# Rate-limited. Honour the Retry-After header.
time.sleep(err.retry_after or 30)
# then retry…
elif err.status >= 500:
# Server-side — retry with exponential backoff.
raise
else:
raise구조 설계 이유
현재 requests 라이브러리가 최선인 이유
- Zero Photta-specific dependencies — `requests` is already in most Python projects
- Works anywhere Python runs: Django, FastAPI, Flask, Celery workers, Lambda, scripts
- The client wrapper is ~30 lines — paste it into `photta.py` and move on
- Pairs naturally with asyncio via `httpx` if you need parallel submission
제외된 기능
Honest caveats
- No official @photta/python SDK yet — REST + requests is the documented pattern
- No async fetch helper shipped; swap `requests` for `httpx` when you need concurrency
- Bearer token auth only — no OAuth client credentials yet
개발자 자주 묻는 질문
Questions other developers ask
공식 Photta Python SDK가 있나요?+
아직 없습니다. 유료 API 고객이 10명을 넘으면 Python SDK를 우선 출시할 계획입니다. 그때까지는 공식 문서에서 지원하는 requests(동기) 또는 httpx(비동기) 라이브러리를 사용하세요. 이 페이지의 30줄 래퍼 코드는 두 방식 모두에서 잘 작동합니다.
지원되는 Python 버전은 무엇인가요?+
Python 3.9 이상입니다. 예제 코드는 3.10 이상에서 잘 작동하는 타입 힌트, f-string, `str | None` 구문을 사용합니다. 3.9 환경이라면 `str | None`을 `Optional[str]`로 바꾸어 사용하세요. requests 자체는 3.8 이상을 지원하지만, 현대적인 Photta 프로젝트를 위해서는 3.9 이상을 권장합니다.
requests와 httpx 중 무엇을 써야 하나요?+
순차적인 호출만 필요하다면 더 간단하고 대중적인 requests를 추천합니다. 비동기 동시성 처리(병렬 제출, 대량 백필 등)나 HTTP/2가 필요하다면 httpx를 쓰세요. 래퍼 코드는 거의 동일하므로 `requests.request`를 `httpx.Client().request`로 바꾸기만 하면 됩니다.
Django에서 호출할 수 있나요?+
네. 래퍼를 `services/photta.py`에 두고 뷰나 Celery 태스크에서 임포트하세요. 작업 시간이 길 수 있으므로 동기식 요청 핸들러 안에서 API를 직접 폴링하지 마세요. 뷰에서는 작업을 제출해 생성 ID만 반환하고, 배경 작업이나 Channels 컨슈머에서 폴링을 처리하는 것이 좋습니다.
Celery 워커에서 폴링은 어떻게 하나요?+
하나의 태스크에서 작업을 제출하고, 3초 뒤에 자신을 다시 예약하는 후속 태스크(`apply_async(countdown=3)`)를 실행하게 하세요. 작업이 완료되거나 최대 재시도 횟수에 도달할 때까지 반복하면 됩니다. 이렇게 하면 워커가 계속 점유되는 것을 방지하고 오토스케일러에 영향을 주지 않습니다.
에러 처리는 어떻게 하나요?+
2xx 이외의 응답은 `type`, `code`, `message`를 포함하며, 400 에러 시 `param`, 429 에러 시 `retry_after` 필드가 포함됩니다. 이 페이지의 래퍼 코드는 이 모든 정보를 담은 `PhottaError`를 발생시키므로, 호출부에서 직접 본문을 파싱할 필요 없이 상태 코드에 따라 분기 처리할 수 있습니다.
Python · 가상 피팅 API
계정 생성 및 API 키 발급
`requests`를 설치하고 환경 변수에서 `PHOTTA_API_KEY`를 로드한 뒤, `Authorization: Bearer photta_live_xxx`를 전송하고 에러 발생 시 예외를 던지는 `photta_request()` 래퍼를 작성하세요. `/tryon/apparel`로 POST하고 `data.status == 'completed'`가 될 때까지 3초마다 `/tryon/apparel/:id`를 폴링하세요. 보통 1.5~4분 소요됩니다.