튜토리얼
hiapi API로 gpt-image-2 이미지 투 이미지 사용하는 방법
hiapi에서 gpt-image-2의 이미지 투 이미지 엔드포인트를 호출하는 방법을 알려주는 바로 실행 가능한 코드 레시피: 요청 엔벨로프, 참조 이미지와 aspect_ratio 파라미터, 폴링과 콜백의 선택, 그리고 바로 복사해 붙여넣을 수 있는 curl, Python, Node.js 예제.
이 레시피는 hiapi 통합 작업 API를 통해 gpt-image-2의 이미지 투 이미지 모드를 호출하는 방법을 단계별로 보여줍니다. 바로 실행 가능한 curl 예제, 백엔드에 바로 삽입할 수 있는 Python 스크립트, 서버리스 환경에 적합한 Node.js 버전, 그리고 실제로 중요한 파라미터와 프로덕션 환경에서 흔히 겪는 함정들을 확인하게 됩니다.
이 글을 다 읽고 나면, 참조 이미지 URL과 프롬프트를 받아 생성된 이미지 URL을 반환하는 스크립트를 갖추게 됩니다. 이 URL을 직접 다운로드하거나 스토리지 계층에 넘겨 처리하면 됩니다.
준비물
- hiapi 계정과 API 키. hiapi 콘솔에서 발급받을 수 있습니다.
- 공개 HTTPS URL에 호스팅된 참조 이미지(또는 base64 data URL — 둘 다 가능합니다).
- 모델이 해당 참조 이미지에 어떤 변환을 적용하길 원하는지 설명하는 텍스트 프롬프트.
이게 전부입니다. SDK 설치가 필요 없습니다 — hiapi는 HTTP + JSON이므로 POST 요청을 보낼 수 있는 언어라면 무엇이든 사용할 수 있습니다.
순수 텍스트 투 이미지부터 알고 싶으신가요? hiapi API로 이미지 생성하는 방법을 참고하세요. 아래 패턴은 동일한 비동기 작업 흐름에
image필드만 추가된 형태입니다.
최소 실행 호출
hiapi는 동일한 비동기 작업 인터페이스로 모든 이미지 모델을 노출합니다:
POST /v1/tasks— 작업을 제출하면taskId가 반환됩니다.GET /v1/tasks/{taskId}를status === "success"가 될 때까지 폴링하거나, 또는callback.url을 제공하여 webhook으로 최종 결과를 받습니다.data.output[0].url에서 이미지 URL을 읽어 다운로드하거나 저장합니다.
curl
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2/image-to-image",
"input": {
"prompt": "transform the subject into a watercolor painting, soft pastel palette",
"image": "https://example.com/reference.jpg",
"aspect_ratio": "1:1",
"resolution": "1K"
}
}'
즉시 반환되는 응답에서 작업 id를 얻을 수 있습니다:
{ "data": { "taskId": "task_01HXXXX..." } }
그다음 결과를 폴링합니다:
curl https://api.hiapi.ai/v1/tasks/task_01HXXXX... \
-H "Authorization: Bearer sk-YOUR_KEY"
작업이 준비되면 응답은 다음과 같습니다:
{
"data": {
"status": "success",
"output": [{ "url": "https://cdn.hiapi.ai/...png", "expireAt": "..." }]
}
}
output[0].url은 단기간만 유효하므로(expireAt 참고) 즉시 다운로드하거나 자체 스토리지에 재업로드하세요 — 최종 사용자에게 핫링크로 제공해서는 안 됩니다.
실제로 중요한 파라미터
| 필드 | 유형 | 설명 |
|---|---|---|
model |
string | 맨 id gpt-image-2/image-to-image를 사용하세요. models/ 접두사를 붙이지 마세요. |
input.prompt |
string | 참조 이미지에 적용하고자 하는 변환. |
input.image |
string | HTTPS URL 또는 data:image/...;base64,... URL. |
input.aspect_ratio |
string | 다음 중 하나: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 또는 auto. |
input.resolution |
string | 1K, 2K 또는 4K. 기본값 1K. |
중요한 동작 두 가지:
- 일부 hiapi 모델은
aspect_ratio만 허용하고(resolution없이), 다른 모델은 픽셀 크기를 요구합니다. gpt-image-2/image-to-image는 위에 표시된aspect_ratio+resolution조합을 허용합니다 — 여기에size: "1024x1024"를 전달하지 마세요. image필드는 참조 이미지입니다. base64 data URL을 전달하는 경우 payload가 플랫폼의 요청 본문 제한보다 작은지 확인하세요(몇 MB는 괜찮지만, 여러 메가바이트 이미지는 먼저 업로드한 뒤 URL로 전달해야 합니다).
프로덕션용 Python 스크립트
이 버전은 데드라인을 두고 폴링하며 실패 시 깔끔하게 종료합니다:
import os
import time
import requests
API = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"]
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
def submit(prompt: str, image_url: str, aspect_ratio: str = "1:1") -> str:
payload = {
"model": "gpt-image-2/image-to-image",
"input": {
"prompt": prompt,
"image": image_url,
"aspect_ratio": aspect_ratio,
"resolution": "1K",
},
}
r = requests.post(API, headers=HEADERS, json=payload, timeout=30)
r.raise_for_status()
return r.json()["data"]["taskId"]
def wait(task_id: str, timeout_s: int = 300, interval_s: int = 5) -> str:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=20)
r.raise_for_status()
task = r.json()["data"]
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
time.sleep(interval_s)
raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")
if __name__ == "__main__":
task_id = submit(
prompt="transform the subject into a watercolor painting, soft pastel palette",
image_url="https://example.com/reference.jpg",
)
print("task:", task_id)
print("url:", wait(task_id))
HIAPI_API_KEY=sk-... python recipe.py로 실행하세요.
Node.js (fetch, 의존성 없음)
const API = "https://api.hiapi.ai/v1/tasks";
const TOKEN = process.env.HIAPI_API_KEY;
const headers = {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
};
async function submit(prompt, imageUrl, aspectRatio = "1:1") {
const r = await fetch(API, {
method: "POST",
headers,
body: JSON.stringify({
model: "gpt-image-2/image-to-image",
input: { prompt, image: imageUrl, aspect_ratio: aspectRatio, resolution: "1K" },
}),
});
const data = await r.json();
if (!r.ok) throw new Error(JSON.stringify(data));
return data.data.taskId;
}
async function wait(taskId, timeoutMs = 300000, intervalMs = 5000) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const r = await fetch(`${API}/${taskId}`, { headers });
const task = (await r.json()).data;
if (task.status === "success") return task.output[0].url;
if (task.status === "fail") throw new Error(JSON.stringify(task.error));
await new Promise((res) => setTimeout(res, intervalMs));
}
throw new Error(`task ${taskId} timed out`);
}
(async () => {
const id = await submit(
"transform the subject into a watercolor painting, soft pastel palette",
"https://example.com/reference.jpg",
);
console.log("task:", id, "\nurl:", await wait(id));
})();
폴링 vs. 콜백
5초마다 폴링하는 방식은 일회성 스크립트에는 문제없지만, 작업이 진행되는 동안 워커 하나를 계속 점유합니다. 실제 백엔드에서는 보통 webhook을 원합니다:
{
"model": "gpt-image-2/image-to-image",
"input": { "prompt": "...", "image": "https://example.com/reference.jpg" },
"callback": { "url": "https://your-app.example.com/api/hiapi-callback", "when": "final" }
}
작업이 결산(성공 또는 실패)되면 hiapi가 해당 URL로 GET /v1/tasks/{id}에서 받은 것과 동일한 payload를 POST합니다. 이 핸들러는 멱등하게 취급하세요 — 재시도가 발생할 수 있습니다 — 그리고 요청을 신뢰하기 전에 검증하세요(URL에 자체 서명 토큰 포함, Authorization 헤더 확인 등).
깔끔한 패턴은 다음과 같습니다: 작업을 제출하고, 자체 job id를 키로 taskId를 영속화하고, 호출자에게 202 Accepted를 반환한 뒤, webhook이 저장 + 알림 작업을 완료하게 합니다.
오류 처리
실무에서는 세 가지 실패 모드를 만나게 됩니다:
401 permission_denied와 함께"This API key cannot use the selected model."— 해당 키가gpt-image-2/image-to-image사용 권한이 없습니다. hiapi 콘솔에서 확인하고 가격 페이지에서 해당 모델이 요금제에 포함되는지 확인하세요.400과 함께additional properties not allowed— 특정 모델이 허용하지 않는 필드를 보냈습니다(예:aspect_ratio대신size사용). 오류 메시지가 위반한 키 이름을 알려주므로 해당 필드를 제거하고 다시 시도하세요.- 폴링 시
status: "fail"과 함께data.error객체 — 모델 자체가 입력을 거부했습니다(안전하지 않은 콘텐츠, 참조 URL 접근 불가 등).error.code와error.message를 로그에 기록하고 무작정 자동 재시도하지 마세요.
항상 POST /v1/tasks 호출에 요청 타임아웃을 설정하고(30초면 충분합니다 — taskId를 빠르게 반환합니다), 폴링 루프나 webhook 수신 경로에는 별도의 더 긴 타임아웃을 설정하세요.
관련 링크
- gpt-image-2 모델 페이지 — 기능 매트릭스와 가격 계층.
- 모든 hiapi 모델 — 다른 이미지나 비디오 모델이 필요하다면 전체 카탈로그가 있습니다.
- API 문서 —
/v1/tasks및 전체 인터페이스에 대한 완전한 레퍼런스. - hiapi API로 이미지 생성하는 방법 — 이 레시피의 텍스트 투 이미지 자매편.
자주 묻는 질문
Q: gpt-image-2/image-to-image는 여러 장의 참조 이미지를 지원하나요?
A: 최소 계약은 단일 image 필드를 사용합니다. 사용 사례에 여러 참조 이미지가 필요하다면(예: 피사체 이미지 + 스타일 이미지) 먼저 하나로 합성하거나 모델 페이지에서 최신 지원 필드를 확인하세요.
Q: URL 대신 로컬 파일을 전달할 수 있나요?
A: 네 — data:image/png;base64,... URL로 인코딩하여 input.image로 전달하면 됩니다. 약 3 MB를 초과하는 파일은 자체 스토리지에 먼저 업로드하고 공개 URL을 전달하세요. 더 빠르고 요청 본문 제한도 피할 수 있습니다.
Q: 작업 하나에 얼마나 걸리나요?
A: 대부분의 gpt-image-2 이미지 투 이미지 작업은 1K 해상도에서 10–30초에 완료됩니다. 더 높은 해상도와 복잡한 프롬프트는 더 오래 걸릴 수 있으므로 안전하게 폴링 타임아웃을 5분으로 설정하세요.
Q: 출력이 참조 이미지와 얼마나 달라지는지 어떻게 제어하나요? A: 프롬프트에서 명시적으로 표현하세요. "Keep the subject's pose and composition, only restyle to watercolor"가 "make this a watercolor"보다 더 엄격한 일관성을 만들어냅니다. gpt-image-2의 이미지 투 이미지 모드는 프롬프트 기반입니다 — 요청 엔벨로프에 별도의 "strength" 슬라이더는 없습니다.
Q: output[0].url은 영구적인가요?
A: 아닙니다. expireAt 타임스탬프가 있습니다(보통 몇 시간). 작업이 성공하면 최대한 빨리 바이트를 다운로드하여 자체 스토리지(R2, S3 등)에 업로드하세요.
Q: 이미지 한 장당 비용은 얼마인가요? A: 요금제와 해상도에 따라 다릅니다. 현재 호출당 비용은 가격 페이지를 참고하세요.
관련 글
모든 아티클 보기 →-
튜토리얼
HiAPI API로 hailuo-2.3-fast/image-to-video 호출하는 방법: curl과 Python 실전
빠르고 저렴한 이미지-투-비디오 등급의 첫 실행 요청 — 모델 ID부터 MP4 다운로드까지
-
튜토리얼
HiAPI API로 hailuo-2.3/text-to-video를 호출하는 방법: curl, Python 및 실행 가능한 요청 예시
-
튜토리얼
HiAPI에서 Kandinsky 6.0 Pro 텍스트-투-비디오 사용하기: curl 및 Python 튜토리얼
요청 우선 실전 데모: 프롬프트에서 비디오 클립까지의 호출 구성, 요청 제출, 완료 상태 폴링 및 결과 다운로드