HiAPI
블로그

튜토리얼

HiAPI에서 gpt-image-2/image-to-image를 호출하는 방법: curl, Python 및 실제로 동작하는 요청

개발자를 위한 이미지-투-이미지 요청 실전: 참조 이미지 제출, 작업 폴링 및 결과 다운로드

Oct 31, 2026
扁平流体形态交叠的封面图,墨黑底色上浮现青瓷绿与石板灰的克制波纹,呼应教程文章。

image-to-image 엔드포인트가 기대하는 것

HiAPI의 gpt-image-2/image-to-image 모델은 비동기 이미지 생성 엔드포인트입니다. 이미지가 반환될 때까지 차단 대기하는 동기 호출과 달리, 이 엔드포인트는 요청을 받아 대기열에 넣고 작업 핸들을 반환합니다. 그런 다음 해당 작업이 완료될 때까지 계속 추적해야 합니다.

요청 레벨에서는 세 가지를 제공해야 합니다:

  • 모델 id: gpt-image-2/image-to-image.
  • 참조 이미지 1장: 모델이 이를 기반으로 변환하거나 구축해야 하는 원본 이미지입니다. 이것이 이미지-투-이미지 모드의 결정적 입력입니다. 이것이 없으면 텍스트-투-이미지를 하는 것입니다.
  • 프롬프트와 옵션: 원하는 출력을 설명하는 텍스트 지시문과 모델 문서에 나열된 선택적 필드(예: 크기 또는 출력 형식)입니다. 모델 문서에 나열된 매개변수만 전송하세요.

응답은 이미지 자체가 아니라 식별자와 상태를 포함한 작업 객체입니다. 이 상태를 단일 진실 공급원으로 취급하세요: pending 또는 processing은 계속 기다리라는 의미이고, succeeded는 결과가 준비되었음을, failed는 문제가 발생했으므로 폴링을 중단해야 함을 의미합니다.

처음부터 이 생명주기를 중심으로 클라이언트를 설계하세요. 이 튜토리얼의 다른 모든 것(curl, Python, 폴링, 다운로드)은 "제출과 완료는 서로 다른 두 시점"이라는 사실 위에 구축됩니다.

HiAPI 키와 참조 이미지 준비

코드를 작성하기 전에 두 가지를 준비하세요.

API 키. HiAPI 콘솔에서 생성하고 스크립트에 직접 붙여넣지 말고 환경 변수에 저장하세요:

export HIAPI_API_KEY="your-key-here"

키를 기밀로 취급하세요. 버전 관리에 커밋하거나 요청 로그에 기록하지 마세요.

참조 이미지. 변환하려는 로컬 이미지 파일을 선택하세요. 합리적인 크기를 유지하세요. 너무 크고 고해상도인 원본 이미지는 요청이 느려지거나 거부되는 가장 흔한 원인입니다. PNG 또는 JPEG를 스크립트가 있는 디렉터리에 두면 첫 실행이 가장 간편합니다:

ls -lh ./reference.png

파일 경로를 기록해 두세요. curl과 Python 예제 모두에서 참조하게 됩니다. 서버에서 모델을 호출할 계획이라면 프로세스가 해당 경로에 대한 읽기 권한이 있는지, 그리고 파일이 유효한 이미지인지(확장자만 잘못 바꾼 파일이 아닌지) 확인하세요.

키가 내보내지고 이미지가 디스크에 있으면 첫 요청에 필요한 모든 것이 준비된 것입니다.

실제로 동작하는 curl 요청

자격 증명과 요청 본문 구조를 가장 빠르게 검증하는 방법은 curl 호출을 한 번 실행하는 것입니다. 작업을 제출하고 작업 객체를 출력합니다:

curl -sS https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/image-to-image",
    "input": {
      "image": "https://example.com/reference.png",
      "prompt": "Turn this photo into a watercolor illustration"
    }
  }'

이 예제에 대해 두 가지 설명이 있습니다. 첫째, 참조 이미지는 input.image 필드를 통해 URL 형식으로 전달됩니다. 엔드포인트 문서가 사용 사례에 대해 인라인 base64 또는 multipart 업로드를 지원한다면 그 형식을 사용하되 필드 이름은 동일하게 유지하세요. 둘째, 프롬프트는 변환을 설명하는 곳입니다. 스타일, 구도, 그리고 어떤 요소가 변경되지 않아야 하는지를 구체적으로 명시하세요.

실행하고 응답을 읽으세요. 제출 성공은 작업 id와 비종료 상태를 반환합니다. 401을 받으면 키가 누락되었거나 잘못된 것입니다. 422 또는 유사한 검증 오류를 받으면 요청 본문을 확인하세요. 보통 모델 id나 image 필드 형식이 잘못된 경우입니다.

작업 id를 저장하세요. 이후 단계는 모두 이에 의존합니다.

Python으로 동일한 작업 수행

Python 버전은 curl 호출과 완전히 대응해야 하며, 인증과 요청 본문 구성을 명시적으로 유지하여 어떤 것도 래퍼 계층에 숨겨지지 않도록 해야 합니다. requests를 사용하세요:

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

payload = {
    "model": "gpt-image-2/image-to-image",
    "input": {
        "image": "https://example.com/reference.png",
        "prompt": "Turn this photo into a watercolor illustration",
    },
}

response = requests.post(f"{BASE_URL}/tasks", json=payload, headers=headers, timeout=30)
response.raise_for_status()
task = response.json()
print(task["id"], task["status"])

통합에서 URL 대신 로컬 파일을 전송하는 경우, 자체 필드를 만들지 말고 엔드포인트 문서에 따라 이미지를 인코딩하고 첨부하세요. 규율은 curl과 동일합니다: 요청 본문을 일반 딕셔너리로 구성하고, 전송하고, 파싱 전에 HTTP 상태를 확인하세요.

제출 로직을 작업 id를 반환하는 함수로 캡슐화하세요. 그러면 다음 섹션의 폴링 코드가 작업이 어떻게 생성되었는지와 무관해집니다.

비동기 작업이 완료될 때까지 폴링

제출 호출은 이미지가 아직 생성 중일 때 반환됩니다. 결과를 얻으려면 작업이 종료 상태에 도달할 때까지 작업 상태 엔드포인트를 폴링하세요. 견고한 루프에는 세 가지 특성이 있습니다: 폴링 간 지연, 최대 대기 시간, 그리고 실패 상태에 대한 명확한 처리입니다.

import time

def wait_for_task(task_id, headers, base_url, timeout=300, interval=3):
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(f"{base_url}/tasks/{task_id}", headers=headers, timeout=30)
        r.raise_for_status()
        task = r.json()
        status = task["status"]
        if status == "succeeded":
            return task
        if status == "failed":
            raise RuntimeError(f"Task failed: {task}")
        time.sleep(interval)
    raise TimeoutError(f"Task {task_id} did not finish within {timeout}s")

몇 가지 실용적인 개선 사항:

  • 백오프: 짧은 간격으로 시작하여 점차 늘리거나, API를 너무 자주 때리지 않도록 충분히 넉넉한 고정 간격을 유지하세요. 이미지 생성은 즉시 완료되지 않습니다.
  • 타임아웃: 항상 총 대기 시간에 상한을 두세요. 그렇지 않으면 멈춘 작업이 워커를 무기한 대기시킵니다.
  • 종료 상태: succeeded와 failed만 종료 상태로 간주하세요. 다른 모든 상태는 계속 폴링하라는 의미입니다. API가 나중에 중간 상태를 추가하더라도 루프는 올바르게 동작합니다.

많은 작업을 실행할 계획이라면 웹 요청을 차단하지 말고 백그라운드 워커나 큐에서 폴링하세요. 생명주기는 동일하고 동시성 모델만 다릅니다.

결과 다운로드 및 검증

작업이 성공을 보고하면 작업 객체에 생성된 이미지의 위치가 포함됩니다. 보통 출력 필드의 URL입니다. 다운로드하여 디스크에 쓰세요:

task = wait_for_task(task_id, headers, BASE_URL)
image_url = task["output"]["image"]

img = requests.get(image_url, timeout=60)
img.raise_for_status()

with open("result.png", "wb") as f:
    f.write(img.content)

서명 URL에 유효 기간이 있다면 완료 후 즉시 다운로드하거나, URL을 나중에 사용하려고 저장하지 말고 파일을 직접 영속화하세요. 엔드포인트가 URL 대신 base64를 반환하면 먼저 디코딩한 후 쓰세요.

빠른 무결성 검사는 혼란스러운 다운스트림 장애를 방지합니다:

from PIL import Image

with Image.open("result.png") as im:
    im.verify()
print("valid image, bytes:", os.path.getsize("result.png"))

파일이 디코딩 가능한 이미지가 아니면 verify()가 예외를 발생시켜 잘린 다운로드와 이미지로 저장된 오류 페이지를 잡아냅니다. 바이트 크기를 확인하면 응답이 합리적인지도 알 수 있습니다. 이로써 루프가 완성됩니다: 제출, 폴링, 다운로드, 검증.

일반적인 장애 문제 해결

대부분의 첫 통합은 몇 가지 예측 가능한 방식으로 실패합니다. 다음 순서로 진단하세요.

인증 오류(401/403). 키가 누락되었거나, 형식이 잘못되었거나, 권한이 부족합니다. 환경 변수가 요청을 실행하는 셸이나 프로세스에 내보내졌는지, Authorization 헤더가 API가 기대하는 정확한 접두사를 사용하는지 확인하세요.

참조 이미지가 유효하지 않거나 너무 큼(400/422). 이미지 URL이 API 측에서 접근 불가능하거나, 파일이 손상되었거나, 크기와 파일 크기가 제한을 초과했을 수 있습니다. 작고 확인된 PNG로 먼저 테스트하세요. URL을 전달하는 경우 공개적으로 접근 가능한지 확인하고, 인라인 데이터를 전달하는 경우 인코딩이 올바른지 확인하세요.

폴링 타임아웃. 작업이 계속 타임아웃에 도달하면 상한을 늘리거나, 간격을 연장하거나, 작업이 실제로 실패했는데 원인을 표시하지 않았는지 확인하세요. 예외를 발생시키기 전에 마지막 작업 객체를 기록하여 상태를 볼 수 있게 하세요.

속도 제한(429). 즉시 재시도하지 말고 지터를 포함한 백오프로 재시도하세요. 대량으로 병렬 제출하는 경우 동시성을 제한하여 급증 트래픽이 제한을 트리거하지 않도록 하고, 작업 id를 기록하여 재시도가 멱등성을 갖도록 하세요.

어떤 오류 범주든 HTTP 상태, 잘린 응답 본문, 작업 id를 기록하세요. 이 세 가지로 보통 문제가 인증, 요청 본문, 타이밍 중 어디에 있는지 판단할 수 있습니다. curl 예제로 문제가 코드에 있는지 입력에 있는지 먼저 격리한 후 수정 사항을 Python으로 이식하세요.

영구 AI 아티팩트로 빌드 시작하기

API 키를 받아 태스크 기반의 하나의 API로 이미지, 비디오, 오디오 모델을 호출하세요.

API 문서 보기