튜토리얼
HiAPI API를 통한 gpt-image-2.5-sunburst/image-to-image 사용 방법: curl과 Python
개발자를 위한 실행 가능한 요청, 참조 이미지 업로드 흐름 및 오류 문제 해결
이 페이지에서
이 엔드포인트의 이미지 간 변환 기능
gpt-image-2.5-sunburst/image-to-image 엔드포인트는 간단한 규약을 따릅니다. 참조 이미지와 자연어 편집 지시를 보내면, 모델이 해당 지시를 적용하면서도 참조 이미지에 기반을 둔 새 이미지를 반환합니다. 텍스트-이미지와 달리 — 텍스트-이미지는 처음부터 시작해 오로지 프롬프트에 의존합니다 — 이미지 간 변환은 참조 이미지를 시각적 컨텍스트로 삼습니다. 구도, 주제, 스타일, 색상 단서가 상속되며, 지시가 이를 명시적으로 변경하라고 요구하지 않는 한 유지됩니다.
이 때문에 이미 소재가 있고 통제된 변환을 원하는 시나리오에 적합합니다. 예를 들어 제품 사진의 스타일을 바꾸거나, 조명이나 배경을 변경하거나, 주제의 외관을 조정하거나, 기존 콘셉트의 변형을 생성하는 경우입니다. 소재가 없고 최대한의 창작 자유를 원할 때는 텍스트-이미지를, 기존 이미지에 대한 충실도가 새로움보다 중요할 때는 이미지 간 변환을 선택하세요.
개발자가 기억해야 할 핵심 사고 모델: 참조 이미지는 입력 제약이고, 편집 지시는 증분입니다. 좋은 지시는 무엇이 존재해야 하는지 전부가 아니라 무엇이 바뀌어야 하는지를 설명합니다. “배경을 깔끔한 스튜디오 그라디언트로 바꾸고, 주제와 그 그림자는 유지하세요”가 전체 장면 설명보다 잘 작동하는 이유는 참조 이미지가 이미 장면을 제공하기 때문입니다. 아래 요청 구조 설명을 읽을 때 이를 염두에 두세요 — 요청 본문은 작지만 지시의 품질이 출력의 품질을 결정합니다.
사전 준비와 요청 구조
처음 호출하기 전에 세 가지를 준비했는지 확인하세요:
- API 키 — HiAPI 계정에서 발급됩니다. 소스 코드가 아닌 환경 변수에 보관하세요.
- 기본 URL — HiAPI API의 base URL로, 대시보드나 API 참고 문서를 참조하세요.
- 엔드포인트 경로:
gpt-image-2.5-sunburst/image-to-image.
모든 요청은 JSON 본문과 Authorization 헤더를 담은 POST 요청입니다. 개념적으로 요청 본문은 세 가지 논리적 부분으로 구성됩니다:
- 모델 선택 — 게이트웨이가 호출을 올바르게 라우팅할 수 있도록 하는 엔드포인트의 모델 식별자.
- 입력 — 참조 이미지(호스팅 URL 또는 base64 데이터 문자열)와 편집 지시 텍스트.
- 출력 제어 — 크기나 수량처럼 엔드포인트 문서에 나열된 선택적 매개변수. 공식 참고 문서에 나온 매개변수만 사용하고 이름을 추측하지 마세요.
규율에 대한 팁: 호스팅 엔드포인트이므로 어떤 필드가 허용되는지는 다른 이미지 API에서 추론한 것이 아니라 현재 API 참고 문서가 정의합니다. 확신이 없으면 최소 유효 본문(model, image, prompt)을 먼저 보내 200 응답을 확인한 뒤 선택적 필드를 하나씩 추가하세요. 그래야 각 장애를 단일 변경에 귀속시킬 수 있으며, 한꺼번에 조립한 본문으로 인한 혼란을 피할 수 있습니다.
참조 이미지와 편집 지시 전송
참조 이미지를 제공하는 지원 방식은 두 가지이며, 절충점은 주로 이미지 바이트가 어디에 저장되는지에 있습니다.
호스팅 URL
이미지가 공개적으로 접근 가능하다면 URL을 직접 전달하세요. 이렇게 하면 요청 본문이 작고 직렬화가 빨라 개발 단계에서 가장 간편한 선택입니다. URL은 서비스가 직접 가져올 수 있어야 합니다 — 인증 뒤에 있거나, 리다이렉트 체인이거나, 이미지를 포함한 HTML 페이지여서는 안 됩니다.
Base64 데이터
이미지가 로컬에 있거나 비공개 리소스라면 인코딩하여 인라인으로 보내세요. Base64는 요청 본문을 약 3분의 1 부풀리므로 원본 이미지가 크면 크기 제한에 근접할 수 있습니다. 한도에 가까워지면 먼저 다운샘플링한 뒤 인코딩하세요.
형식과 크기 함정
- 주요 형식(PNG, JPEG, WebP)을 고수하고 파일 확장자가 실제 바이트와 일치하는지 확인하세요.
- 지나치게 큰 이미지는 요청이 거부되는 가장 흔한 원인입니다. 적절한 크기의 원본 이미지를 사용하세요. 한 번의 편집을 구동하는 데 전체 해상도 소재가 보통 필요하지 않습니다.
- base64 문자열을 직접 조립한다면 API 참고 문서의 예시에 data URI 접두사가 포함된 경우에만 붙이고, 그렇지 않으면 제거하세요. 이 두 규약을 혼용하는 것이 “invalid image” 오류의 흔한 원인입니다.
편집 지시 작성
출력 품질의 성패는 지시에 달려 있습니다. 무엇을 바꿀지 구체적으로 명시하고, 무엇을 유지할지 분명히 밝히세요. 대상(“재킷”), 변환(“짙은 네이비로 다시 채색”), 제약(“모델의 자세와 기존 그림자는 유지”)을 명시하세요. 한 지시에 여러 무관한 편집을 쌓지 마세요 — 서로 독립적인 변경이 필요하면 여러 번의 호출로 나누면 각 결과도 평가하기 쉬워집니다.
실행 가능한 curl 요청
아래는 터미널에서 완전히 실행할 수 있는 요청입니다. 키와 이미지 자리표시자를 자신의 값으로 바꾸세요.
curl -X POST "$HIAPI_BASE_URL/gpt-image-2.5-sunburst/image-to-image" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2.5-sunburst/image-to-image",
"image": "https://your-cdn.example.com/reference.png",
"prompt": "배경을 부드러운 중성 스튜디오 그라디언트로 교체하세요. 주제, 그 자세, 기존 그림자는 변경하지 마세요."
}'
항목별 설명:
-X POST— 이 작업은 새 이미지를 생성하므로 POST를 사용합니다.- URL은 기본 URL과 엔드포인트 경로를 이어 붙여 만듭니다. 기본 URL을 환경 변수에 두면 환경 전환이 쉽습니다.
Authorization: Bearer ...— API 키입니다.HIAPI_API_KEY로 내보내면 shell 기록이나 로그에 나타나지 않습니다.Content-Type: application/json— 본문은 JSON입니다. 이 헤더를 빠뜨리는 것이 혼란스러운 4xx 응답의 흔한 원인입니다.model— 엔드포인트의 식별자입니다. 문서와 정확히 일치시키세요.image— 참조 이미지이며 여기서는 호스팅 URL입니다. base64로 바꾸려면 데이터 문자열이나 로컬 인코딩 변수로 교체하세요.prompt— 편집 지시입니다. 무엇을 바꾸고 무엇을 유지할지만 작성하세요.
수동 인코딩 없이 로컬 파일로 테스트하고 싶다면 대부분의 shell에서 작은 스크립트나 jq로 JSON을 구성할 수 있습니다. 핵심은 최종 본문이 이 필드들을 담은 유효한 JSON이라는 점입니다.
같은 요청을 Python으로 구현
Python 버전은 응답을 나란히 비교할 수 있도록 요청 본문을 정확히 동일하게 유지합니다. requests를 사용하세요:
import os
import requests
base_url = os.environ["HIAPI_BASE_URL"]
api_key = os.environ["HIAPI_API_KEY"]
payload = {
"model": "gpt-image-2.5-sunburst/image-to-image",
"image": "https://your-cdn.example.com/reference.png",
"prompt": (
"배경을 부드러운 중성 스튜디오 그라디언트로 교체하세요. "
"주제, 그 자세, 기존 그림자는 변경하지 마세요."
),
}
response = requests.post(
f"{base_url}/gpt-image-2.5-sunburst/image-to-image",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json=payload,
timeout=120,
)
response.raise_for_status()
print(response.json())
주목할 점 두 가지. 첫째, json=payload는 콘텐츠 유형을 설정하고 본문을 대신 직렬화하여 수작업 JSON 조립 오류의 범주 전체를 제거합니다. 둘째, timeout=120은 의도적입니다. 이미지 생성은 즉각적이지 않으므로 영원히 기다리는 클라이언트는 깔끔하게 실패하는 클라이언트보다 나쁩니다. 워크로드에 맞게 타임아웃을 조정하되 반드시 설정하세요.
로컬 파일로 바꾸려면 바이트를 읽어 base64로 인코딩하고 그 결과를 image에 할당하세요. 호스팅 URL을 사용할 때는 문자열을 그대로 유지하세요. curl과 Python 호출이 동일한 구조를 반환하면 두 방식이 일치함을 확인한 것이며, 어느 쪽을 기반으로든 계속 구축할 수 있습니다.
흔한 요청 실패 문제 해결
대부분의 실패는 네 범주로 나눌 수 있습니다. 각 범주가 다음 범주로 위장할 수 있으므로 아래 순서대로 점검하세요.
인증 오류
401 또는 403은 거의 항상 키가 없거나, 형식이 잘못되었거나, 만료되었음을 의미합니다. 헤더가 정확히 Authorization: Bearer <key>인지 확인하고, 복사-붙여넣기로 들어간 여분의 따옴표나 줄바꿈이 없는지 확인하며, 요청을 실행하는 shell이나 프로세스에 해당 환경 변수가 실제로 설정되어 있는지 확인하세요. curl에서는 되는데 Python에서는 안 되는 키는 보통 잘못된 키가 아니라 설정되지 않은 변수를 가리킵니다.
본문 형식 오류
검증 메시지가 있는 400은 보통 JSON이 유효하지 않거나 필수 필드가 누락되었음을 의미합니다. 보내기 전에 본문을 예쁘게 출력해 확인하고, model이 엔드포인트 식별자와 일치하는지, 편집 지시 필드 이름이 문서와 일치하는지 확인하세요. curl에서 JSON을 직접 작성할 때 후행 쉼표와 작은따옴표가 전형적인 원인이며, Python의 json=은 이런 문제를 피합니다.
이미지 입력이 유효하지 않거나 너무 큼
서비스가 이미지를 거부한다면 세 가지를 확인하세요: URL이 공개적으로 가져올 수 있고 리다이렉트나 오류 페이지가 아닌 이미지를 반환하는지, 형식이 지원되는지, 본문이 문서에 명시된 크기 제한을 초과하지 않는지. base64 입력의 경우 인코딩이 깔끔하고 data URI 접두사 규약이 참고 예시와 일치하는지 확인하세요. 확신이 없으면 다운샘플링한 뒤 다시 시도하세요 — 더 작은 원본 이미지는 이러한 오류 상당수를 해결합니다.
타임아웃과 일시적 장애
오래 걸리는 생성은 클라이언트 타임아웃을 초과할 수 있고, 429 또는 5xx 응답은 속도 제한에 걸렸거나 일시적 서버 문제를 만났음을 나타냅니다. 클라이언트 오류와 구분하세요: 400을 그대로 재시도하지 말고, 429나 503은 백오프 재시도에 적합합니다. 실패할 때마다 상태 코드와 응답 본문을 기록하세요 — 명확한 오류 로그는 문제 해결을 추측에서 항목별 점검으로 바꿔 줍니다.
스크립트에서 재사용 가능한 클라이언트로
일회성 스크립트는 엔드포인트가 작동함을 증명하고, 작은 래퍼는 파이프라인에서 안정적으로 실행되게 합니다. 호출을 함수로 감싸 요청, 타임아웃, 제한된 재시도 정책의 세 가지를 책임지게 하세요.
import os
import time
import requests
class ImageEditClient:
def __init__(self, base_url: str, api_key: str, timeout: int = 120):
self.base_url = base_url.rstrip("/")
self.api_key = api_key
self.timeout = timeout
def edit(self, image: str, prompt: str, retries: int = 3):
url = f"{self.base_url}/gpt-image-2.5-sunburst/image-to-image"
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
}
payload = {
"model": "gpt-image-2.5-sunburst/image-to-image",
"image": image,
"prompt": prompt,
}
last_error = None
for attempt in range(retries):
try:
resp = requests.post(
url, headers=headers, json=payload, timeout=self.timeout
)
except requests.Timeout as err:
last_error = err
time.sleep(2 ** attempt)
continue
if resp.status_code in (429, 500, 502, 503, 504):
last_error = RuntimeError(f"transient {resp.status_code}: {resp.text}")
time.sleep(2 ** attempt)
continue
if resp.status_code >= 400:
raise RuntimeError(f"request failed {resp.status_code}: {resp.text}")
return resp.json()
raise RuntimeError(f"exhausted retries: {last_error}")
설계 선택이 코드 자체보다 중요합니다. 재시도는 타임아웃과 일시적 상태 코드에만 적용되고 4xx 클라이언트 오류에는 절대 적용되지 않습니다. 형식이 잘못된 본문을 재시도하는 것은 할당량만 낭비하기 때문입니다. 지수 백오프는 속도 제한에 걸린 파이프라인이 엔드포인트를 반복적으로 강타하는 것을 방지합니다. 클라이언트 오류는 응답 본문과 함께 즉시 발생하여 호출자가 서비스가 무엇을 거부하는지 정확히 볼 수 있게 합니다. 그리고 모델 식별자를 한 곳에 모아 두면 향후 다른 이미지 엔드포인트로 전환할 때 코드베이스 곳곳을 뒤질 필요 없이 한 줄만 바꾸면 됩니다.
이를 기반으로 각 시도에 구조화된 로깅을 추가하고, 다운스트림 소비자가 응답을 사용하기 전에 크기/형태 검사를 하세요. 같은 게이트웨이의 다른 이미지 모델을 탐색할 준비가 되면 HiAPI 모델 카탈로그가 클라이언트를 다시 작성하지 않고도 각 엔드포인트를 비교하기 좋은 곳입니다.
관련 글
모든 아티클 보기 →-
튜토리얼
HiAPI API로 kimi-k3.1-pro 호출하는 방법: curl, Python과 바로 실행 가능한 요청
엔드포인트, 요청 파라미터, 스트리밍, 도구 호출, 오류 문제 해결을 다루는 실전 통합 가이드
-
튜토리얼
HiAPI의 ElevenLabs Music API: curl, Python 및 프롬프트 레시피로 음악 생성하기
HiAPI를 통해 elevenlabs/music-v2.5를 호출하는 실전 튜토리얼과 스타일·분위기·길이를 위한 복사 가능한 프롬프트 레시피
-
튜토리얼
HiAPI API로 gemini-omni-1.2-flash 사용하기: curl과 Python