HiAPI
블로그

튜토리얼

HiAPI API로 gpt-image-2/text-to-image@ext를 호출하는 방법: curl과 Python

텍스트-이미지 생성 기능을 통합하려는 개발자를 위한 실전 요청 연습

Oct 31, 2026
黑绿底上,黄铜色与深绿色扁平缎带以经纬交织方式构成开放式网格,这是教程文章的封面图。

gpt-image-2/text-to-image@ext가 제공하는 것

gpt-image-2/text-to-image@ext는 HiAPI 통합 인터페이스를 통해 외부에 제공되는 텍스트-이미지 생성 모델입니다. 동일한 엔드포인트에 프롬프트와 선택적 생성 파라미터를 보내기만 하면 생성된 이미지 데이터를 받을 수 있습니다. 모델 전용 컴포넌트를 설치할 필요도, 벤더별로 SDK를 따로 연동할 필요도, 별도 계정을 관리할 필요도 없습니다. 동일한 API key와 동일한 요청 구조로 플랫폼의 나머지 기능까지 모두 커버할 수 있습니다.

제품이 텍스트 설명을 새로운 이미지로 바꿔야 할 때 이 모델을 선택하세요. 마케팅 문구를 메인 비주얼로, 사용자 프롬프트를 썸네일로, 설계 도구에서 필요할 때마다 콘셉트 이미지를 렌더링하는 경우가 그렇습니다. 호출이 일반적인 HTTP 요청 하나이기 때문에 클라이언트 라이브러리 없이도 백엔드 서비스, 큐 worker, 스크립트에 손쉽게 넣을 수 있습니다.

입력이 텍스트이고 출력이 직접 저장하고 배포할 비트맵일 때 바로 이 모델이 적합합니다. 나중에 플랫폼에서 다른 이미지 경로로 전환해야 하더라도 인증, 요청 봉투, 출력 처리 같은 통합 로직은 그대로 유지됩니다. 모델 식별자와 파라미터 블록만 바꾸면 됩니다.

이 가이드를 읽는 방법

이 연습은 단계별로 펼쳐집니다. 먼저 이미지를 반환하는 최소 요청, 그다음 Python 버전, 이어서 단일 호출과 비동기 폴링 사이의 구조적 결정, 마지막으로 출력 처리입니다. 각 단계는 독립적으로 테스트할 수 있으므로 문제가 생겼을 때 어느 변경이 원인인지 명확히 알 수 있습니다.

사전 조건과 인증

첫 요청을 보내기 전에 두 가지가 필요합니다. HiAPI 계정과 그에 연결된 API key입니다. 계정 대시보드에서 key를 생성하고, 어떤 비밀 키든 보관하는 방식으로 저장하세요. 로컬에서는 환경 변수, 프로덕션에서는 secrets manager를 사용합니다. 코드 저장소에 커밋하거나 브라우저로 전송되는 클라이언트 코드에 붙여 넣지 마세요.

인증은 요청 헤더의 bearer token으로 완료됩니다. 형식은 항상 동일합니다:

Authorization: Bearer $HIAPI_API_KEY

셸에서 이 변수를 한 번 설정하면 아래 예시에서 키를 다시 노출하지 않고 참조할 수 있습니다:

export HIAPI_API_KEY="your-key-here"

시작 전에 확인할 사항

  • 해당 key가 활성 상태이며 이미지 생성 접근 권한이 있어야 합니다.
  • 환경이 HiAPI 엔드포인트로 아웃바운드 HTTPS 요청을 보낼 수 있어야 합니다.
  • 생성 파일이 어디에 기록될지 알아야 합니다. 테스트에는 로컬 디렉터리, 프로덕션에는 오브젝트 스토리지를 사용합니다.

key가 없거나 형식이 잘못되면 첫 호출에서 곧바로 인증 오류로 드러납니다. 문제를 발견할 수 있는 가장 이르고 명확한 시점입니다.

실행 가능한 최소 curl 요청

이미지를 생성할 수 있는 최소 요청부터 시작하세요. 프롬프트를 제외한 모든 것은 선택 사항이며, 첫 호출을 간결하게 유지하면 어떤 오류든 거의 확실히 인증이나 요청 구조와 관련된 것이지 파라미터 충돌 때문이 아닙니다.

curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/text-to-image@ext",
    "prompt": "접힌 종이 지도 위에 놓인 얼룩덜룩한 황동 나침반, 부드러운 창가 빛, 얕은 심도",
    "size": "1024x1024",
    "n": 1
  }'

필드별 설명

  • model — 모델 식별자입니다. 요청을 gpt-image-2/text-to-image@ext에 묶는 유일한 값이며 정확히 일치해야 합니다.
  • prompt — 내용 설명입니다. 주제, 스타일, 조명을 구체적으로 쓰세요. 모호한 프롬프트는 모호한 이미지를 만들고 파라미터 오류보다 디버깅하기 어렵습니다.
  • size — 출력 크기입니다. 파이프라인 검증 단계에서는 생략하고 기본값을 받아도 됩니다.
  • n — 호출당 생성할 이미지 수입니다. 통합 중에는 실패가 정확히 하나의 출력에 대응하도록 1로 유지하세요.

응답을 파일로 기록하면 터미널이 바이너리 데이터로 어수선해지지 않고 검사할 수 있습니다:

curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json -o response.json

이미지가 반환되면 이미 동작이 확인된 기준선을 갖게 됩니다. 이후의 모든 변경은 그 기준선에 대한 되돌릴 수 있는 단일 편집이어야 합니다.

요청을 Python으로 이식하기

Python 버전은 동일한 요청이고 전송 방식만 다릅니다. requests를 사용하세요. 가장 실수가 적은 선택이며 이미 검증한 curl 필드와 일대일로 대응합니다.

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"]

payload = {
    "model": "gpt-image-2/text-to-image@ext",
    "prompt": "접힌 종이 지도 위에 놓인 얼룩덜룩한 황동 나침반, 부드러운 창가 빛",
    "size": "1024x1024",
    "n": 1,
}

response = requests.post(
    f"{BASE_URL}/v1/images/generations",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=120,
)

response.raise_for_status()
data = response.json()

핵심 요점 해석

  • json=payload는 콘텐츠 타입을 설정하고 요청 본문을 직렬화하는 일을 한 번에 합니다. 수동 문자열 조합도, 이스케이프 버그도 없습니다.
  • 실무에서 timeout은 선택 사항이 아닙니다. 이미지 생성은 일반적인 JSON API 호출보다 느리므로, 타임아웃이 없으면 업스트림이 느려질 때 worker가 멈춥니다.
  • raise_for_status()는 HTTP 실패를 잡아서 분류할 수 있는 예외로 바꾸어, 잘못된 응답 본문이 다운스트림으로 흘러가지 않게 합니다.

payload는 인라인 문자열이 아니라 dict로 유지하세요. 나중에 파라미터를 추가할 때 키만 더하면 되고 요청 구조는 그대로이므로 전송 계층을 다시 디버깅할 일이 없습니다.

SDK 스타일 클라이언트를 선호한다면 동일한 엔드포인트와 요청 헤더가 그대로 적용됩니다. 호출 문법만 다릅니다. 먼저 curl로 검증한 뒤 애플리케이션에서 이미 표준화한 클라이언트를 채택하세요.

단일 호출과 비동기 폴링 중 선택

이것은 문법이 아니라 설계 결정이며, 재시도와 저장 로직에 통합의 다른 어떤 선택보다 큰 영향을 미칩니다.

단일 호출

다음 경우에는 단일 요청-응답 주기를 사용하세요:

  • 필요할 때 생성하고 기다리는 사용자가 있습니다.
  • HTTP 계층이 긴 연결을 견딜 수 있습니다.
  • 한 번에 한 장씩 생성하고 대량 생성은 하지 않습니다.

관찰한 가장 느린 생성 시간보다 타임아웃을 넉넉하게 설정하고, 타임아웃을 하드 오류가 아닌 재시도 가능한 실패로 취급하세요.

비동기 폴링

배치 처리, 요청이 큐 worker에서 오는 경우, 또는 호출자가 블로킹하면 안 되는 경우에는 비동기를 선택하세요. 패턴은 제출하고 핸들을 받은 뒤 완료 상태를 폴링하는 것입니다.

import time

def poll_until_done(fetch_status, handle, interval=2, max_wait=300):
    deadline = time.monotonic() + max_wait
    while time.monotonic() < deadline:
        status = fetch_status(handle)
        if status["state"] == "succeeded":
            return status
        if status["state"] == "failed":
            raise RuntimeError(status.get("error", "generation failed"))
        time.sleep(interval)
    raise TimeoutError("generation did not finish in time")

안정적으로 동작하는 폴링 루프 규칙

  • 백오프. 짧은 간격으로 시작해 점차 늘리세요. 일정하게 빠듯한 폴링은 할당량과 레이트 예산을 낭비합니다.
  • 대기 제한. max_wait 데드라인은 고아 작업이 worker를 영구히 점유하지 않게 합니다.
  • 핸들 영속화. worker가 재시작되면 다시 제출해 중복 생성을 지불하는 대신 폴링을 복구할 수 있어야 합니다.
  • 실패를 작업별 종료 상태로 취급하세요. failed 상태는 기록해야 하며 빠듯한 루프에서 조용히 재시도해서는 안 됩니다.

가능한 한 일찍 결정하세요. 나중에 동기 코드 경로에 비동기 의미를 개조하는 것은 호출자, 저장, 오류 처리를 동시에 다시 작성하는 일을 뜻합니다.

이미지 출력 처리

응답에는 생성된 이미지가 담겨 있지만, 그것은 JSON 봉투 안의 데이터이지 핫링크할 수 있는 URL이 아닙니다. 직접 소유한 바이너리 출력으로 취급하세요.

디코드 및 영속화

import base64

item = data["data"][0]
image_bytes = base64.b64decode(item["b64_json"])

with open("out.png", "wb") as f:
    f.write(image_bytes)

응답이 인라인 데이터가 아니라 URL을 담고 있다면 즉시 가져와 바이트를 자체 스토리지에 기록하세요. 생성된 URL은 임시적입니다. 사용자에게 제공하는 모든 콘텐츠는 자체 인프라 뒤에 있어야 합니다.

배포 전에 검증

  • 매직 넘버 확인. PNG는 \x89PNG로 시작하고 HTML 오류 페이지는 그렇지 않습니다. 몇 바이트 확인만으로 HTTP 200을 반환하지만 본문이 잘못된 프록시 문제를 잡을 수 있습니다.
  • 크기 기록. 바이트 길이를 기록하면 잘린 다운로드가 모니터링에서 드러납니다.
  • 결정적 저장. 프롬프트 텍스트가 아니라 생성 ID로 파일 이름을 정하고, 프롬프트, 파라미터, 응답 메타데이터를 이미지와 함께 저장하세요. 이 조합이 있으면 나중에 어떤 출력이든 재현하거나 감사할 수 있습니다.
  • 콘텐츠 타입을 올바르게 설정하세요 — 추측이 아니라 실제 파일에서 도출해야 합니다.

메타데이터를 산출물과 함께 보존

작은 동반 기록을 작성하세요. 모델 식별자, 전체 프롬프트, 크기와 수량, 타임스탬프, 응답의 모든 요청 ID를 담습니다. 6개월 뒤 누군가 이 이미지가 왜 이렇게 보이는지 묻는다면 이 기록이 유일한 답이 될 것입니다.

흔한 장애 디버깅

대부분의 첫 통합 장애는 세 가지 범주로 나뉩니다. 대략 진단 비용이 낮은 순서로 확인하세요.

인증 오류

401 또는 403은 key가 틀렸거나, 폐기되었거나, 전송되지 않았다는 뜻입니다. 키 없이 요청 헤더 구성을 출력해 Bearer 접두사와 공백이 온전한지 확인하고, 요청을 보내는 프로세스에서 환경 변수가 실제로 채워졌는지 확인하세요. 셸에서는 설정했지만 worker나 컨테이너에서는 설정하지 않는 것이 흔한 함정입니다.

잘못된 요청 본문

400은 보통 요청 본문을 가리킵니다. curl 섹션의 최소 요청으로 되돌린 뒤 필드를 하나씩 다시 추가하세요. 흔한 원인은 다음과 같습니다:

  • model 문자열이 gpt-image-2/text-to-image@ext와 정확히 일치하지 않음.
  • 요청 본문이 유효한 JSON이 아님 — 중복 쉼표 또는 이스케이프되지 않은 따옴표.
  • 파라미터 타입 오류. n은 숫자이지 문자열이 아닙니다.
  • Content-Type: application/json 누락으로 서버가 요청 본문을 파싱하지 못함.

타임아웃과 느린 응답

이미지가 반환되기 전에 연결이 끊긴다면 모델 장애가 아니라 클라이언트 타임아웃을 초과했을 가능성이 큽니다. 단일 호출 설계에서는 타임아웃을 늘리고, 어떤 형태의 배치라도 비동기 폴링으로 전환하세요. 재시도할 때 중복 생성이 없도록 하세요. 요청이 이미 성공했을 수 있다면 다시 제출하기 전에 결과가 있는지 확인하세요.

위의 어느 것도 아닐 때

실패한 요청의 전체 응답 — 상태 코드, 응답 헤더, 응답 본문 — 을 캡처하고 최소 curl 명령으로 재현하세요. 최소 요청에서도 남는 장애는 환경의 통합 문제이고, 사라지는 장애는 추가한 파라미터를 가리킵니다.

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

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

API 문서 보기