튜토리얼
HiAPI API를 통한 nano-banana-pro 사용 방법: curl 및 Python 예제
HiAPI의 nano-banana-pro가 제공하는 것
nano-banana-pro는 HiAPI 통합 API를 통해 호출할 수 있는 이미지 생성 모델입니다. 모델 제공자와 직접 통합할 필요 없이 HiAPI에 통일된 형식의 요청을 보내면 생성된 이미지를 얻을 수 있습니다. 다른 플랫폼 모델과 동일한 인증, 동일한 엔드포인트 규약, 동일한 응답 래퍼를 사용합니다.
nano-banana-pro는 프롬프트 기반 이미지 생성을 위해 설계되었으며, 텍스트 프롬프트 외에도 참조 이미지를 첨부할 수 있습니다. 참조 이미지를 통해 모든 것을 텍스트로 설명하지 않고도 시각적 맥락(피사체, 스타일, 구도)으로 출력을 유도할 수 있습니다. 출력은 2K 해상도로 제공되므로 이 모델은 빠른 초안보다는 프로덕션 자산에 더 적합합니다.
이 튜토리얼을 마치면 다음을 수행할 수 있는 완전히 작동하는 통합을 얻게 됩니다:
- 검증된
curl요청으로 HiAPI에 프롬프트를 nano-banana-pro로 전송; - 요청 페이로드를 변경하지 않고 Python에서 동일한 호출을 재현;
- 요청에 참조 이미지 첨부;
- 비동기 작업을 제출하고 완료까지 폴링하며 재시도를 합리적으로 처리;
- 완료된 2K 이미지를 다운로드하여 자체 인프라에 저장.
각 섹션은 이전 섹션을 기반으로 하므로 가장 안전한 경로는 순서대로 진행하는 것입니다: 먼저 수동으로 요청을 확인한 다음 코드로 옮기세요.
첫 요청을 보내기 전에
첫 호출 전에 세 가지를 준비해야 합니다.
API 키
HiAPI 계정에서 API 키를 생성하고 소스 관리에 포함되지 않도록 하세요. 다른 비밀 정보와 동일하게 취급하세요: 환경 변수(HIAPI_API_KEY) 또는 비밀 관리자에서 로드하고, 커밋할 수 있는 파일에 절대 하드코딩하지 마세요. 키가 유출되면 기록에서 제거하려 하지 말고 대시보드에서 교체하세요.
HTTP 클라이언트
HTTPS 요청을 보낼 수 있는 도구라면 무엇이든 됩니다. 첫 요청에는 명령줄의 curl이 이상적입니다. 여러분과 네트워크 사이에 프레임워크가 없어 모든 요청 헤더와 응답 본문의 모든 바이트를 볼 수 있기 때문입니다. Python 부분에는 표준 라이브러리의 urllib.request만으로 충분하며, 이미 requests 또는 httpx를 사용 중이라면 매핑은 동일합니다. 이 튜토리얼은 Python을 표준 라이브러리로 제한하므로 추가로 설치할 것이 없습니다.
출력을 저장할 위치
nano-banana-pro 작업은 비동기이므로 처음부터 완료된 이미지를 저장할 디렉터리나 버킷을 계획하세요. 개발 중에는 로컬 output/ 폴더로 충분하지만 프로덕션에서는 객체 스토리지를 목표로 해야 합니다.
공급자 SDK를 설치할 필요는 없습니다. HiAPI는 일반 HTTPS 호출로 동작하므로 curl에서 구성한 요청은 나중에 Python 클라이언트가 보내는 요청과 정확히 동일합니다.
작동하는 curl 요청, 단계별 설명
키, 엔드포인트, 페이로드가 모두 올바른지 확인하는 가장 빠른 방법은 수동으로 요청을 보내는 것입니다. 입력하기 전에 각 부분으로 나누어 보세요.
엔드포인트와 메서드
모든 모델 호출은 동일한 HiAPI 기본 URL로 전송되며, 모델은 경로가 아닌 요청 본문에서 식별됩니다. 생성 요청에는 POST를 사용합니다.
요청 헤더
모든 호출에서 중요한 세 가지 요청 헤더가 있습니다:
Authorization: Bearer $HIAPI_API_KEY— 키를 bearer 토큰으로 전달합니다.Content-Type: application/json— 프롬프트만 포함된 요청에 사용합니다.Accept: application/json— HTML 오류 페이지가 아닌 구조화된 응답을 받기 위함입니다.
요청 본문
JSON 요청 본문에는 모델 이름과 생성 매개변수가 포함됩니다. 최소한 모델 식별자와 프롬프트를 보내야 합니다:
curl -sS -X POST "$HIAPI_BASE_URL" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"model": "nano-banana-pro",
"input": {
"prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
}
}'
이 명령을 실행하기 전에 셸에서 HIAPI_BASE_URL과 HIAPI_API_KEY를 설정하세요. URL을 변수에 저장하면 나중에 명령을 수정하지 않고도 동일한 스크립트를 스테이징 또는 샌드박스 URL로 향하게 할 수 있습니다.
응답 읽기
성공적인 제출은 작업을 식별하는 JSON 객체를 반환합니다. 중요한 필드는 작업 식별자이며, 폴링 단계에서 사용하게 됩니다. 생성에는 시간이 걸리므로 첫 응답에서 이미지 자체를 기대하지 마세요. nano-banana-pro는 비동기로 동작하며 이 호출은 상호작용의 제출 부분일 뿐입니다.
명령이 오류를 반환하면 여기서 멈추고 코드를 작성하기 전에 수정하세요. 검증된 curl 요청이 참조 구현입니다. 이후 모든 단계는 동일한 HTTP 요청을 생성해야 합니다.
요청을 Python으로 이식하기
이식은 기계적입니다: URL, 메서드, 요청 헤더, JSON 요청 본문은 그대로 유지됩니다. 클라이언트만 바뀝니다.
urllib을 사용한 동일한 요청
import json
import os
import urllib.request
api_key = os.environ["HIAPI_API_KEY"]
base_url = os.environ["HIAPI_BASE_URL"]
payload = {
"model": "nano-banana-pro",
"input": {
"prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
},
}
request = urllib.request.Request(
base_url,
data=json.dumps(payload).encode("utf-8"),
method="POST",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
"Accept": "application/json",
},
)
with urllib.request.urlopen(request, timeout=60) as response:
body = json.loads(response.read().decode("utf-8"))
print(body)
매핑 규칙
curl에서 변환할 때 실수하기 쉬운 세 가지 세부 사항이 있습니다:
- 요청 본문은 바이트여야 합니다.
json.dumps는 문자열을 생성하므로 요청 객체에 전달하기 전에 인코딩해야 합니다. - 요청 헤더는 플래그가 아닌 사전입니다. 각
-H줄은 키/값 쌍이 됩니다.Bearer접두사와 그 뒤의 공백을 유지하세요. - 메서드는 명시적으로 지정해야 합니다. 데이터가 있을 때
urllib.request는 기본적으로POST를 사용하지만method="POST"를 설정하면 의도가 더 명확해지고 나중에 요청 본문을 제거할 때 예기치 않은 동작을 방지합니다.
requests를 사용하는 경우 동등한 표현은 requests.post(base_url, headers=headers, json=payload, timeout=60)입니다. json=이 직렬화와 콘텐츠 유형을 처리합니다. httpx를 사용하는 경우 호출 형식은 동일합니다.
가져둘 가치가 있는 작은 헬퍼 함수
제출 호출을 프롬프트를 받아 작업 식별자를 반환하는 함수에 넣으세요. 이후 모든 섹션(참조 이미지, 폴링, 다운로드)이 해당 함수 위에 구축되므로 한 곳에 유지하면 요청 형식의 변경이 한 번만 발생합니다.
프롬프트와 함께 참조 이미지 보내기
참조 이미지는 요청 형식을 변경하므로 애플리케이션이 어떤 입력 방식을 사용할지 일찍 결정하세요.
두 가지 실용적인 옵션
URL 기반 입력. 참조 이미지가 HTTPS를 통해 접근 가능하다면 요청 본문에 프롬프트와 함께 해당 URL을 첨부할 수 있습니다. 이렇게 하면 요청이 application/json으로 유지되며 재시도와 로깅이 가장 쉬운 형식입니다.
파일 업로드. 이미지가 클라이언트나 프라이빗 스토리지에 있다면 multipart/form-data 요청의 파일 부분으로 보낼 수 있습니다. 이 경우 Content-Type: application/json 헤더는 multipart 콘텐츠 유형으로 대체됩니다. 경계가 올바르게 생성되도록 HTTP 클라이언트가 이를 생성하게 하고, JSON 필드는 동일한 요청의 폼 필드가 됩니다.
대부분의 서버 측 통합에는 URL 기반 입력이 더 간단합니다: 이미지가 이미 객체 스토리지에 있고 요청이 JSON으로 유지되며 재시도 시 큰 요청 본문을 두 번 보내는 것을 피할 수 있습니다.
프롬프트와 참조 이미지를 동기화 상태로 유지
프롬프트는 참조 이미지의 내용뿐 아니라 참조 이미지의 용도를 설명해야 합니다. "참조 이미지의 조명과 색조를 따른다; 피사체를 도자기 꽃병으로 변경한다"는 모델에 명확한 작업을 제공합니다. 참조 이미지를 무시하는 프롬프트는 입력을 낭비합니다.
보내기 전 검증
참조 이미지는 요청 오류의 가장 흔한 원인입니다. URL이 공개적으로 접근 가능한지(또는 시스템 양쪽이 서명된 URL 만료 시간에 합의했는지), 파일 형식이 모델에서 허용되는지, 이미지가 너무 커서 업로드 시간 초과가 발생하지 않는지 확인하세요. 이러한 검사는 먼저 자체 코드에서 수행하세요. 클라이언트 측 검증 실패는 거부된 요청보다 디버깅 비용이 훨씬 낮습니다.
비동기 작업 처리 및 결과 폴링
nano-banana-pro 생성은 비동기입니다. 클라이언트를 세 개의 개별 단계로 구성하세요: 제출, 폴링, 다운로드. 이를 하나의 함수로 섞으면 재시도와 시간 초과를 추론하기 어려워집니다.
1단계: 제출
위의 요청을 보내고 반환된 작업 식별자를 저장하세요. 프로세스가 제출과 완료 사이에 재시작될 수 있으므로 식별자를 데이터베이스 행이나 큐 메시지 같은 영구 위치에 저장하세요.
2단계: 폴링
동일한 기본 URL과 동일한 Authorization 헤더를 사용하여 요청에 작업 식별자를 포함해 작업 상태를 가져오세요. 타이트 루프 대신 간격을 두고 폴링하세요. 검사 사이에 몇 초 간격을 두는 것이 일반적이며, 연속 검사에서 대기 상태가 반환되면 백오프해야 합니다.
import time
TERMINAL = {"succeeded", "failed"}
def wait_for_job(job_id, timeout=300, interval=3):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
status = get_job_status(job_id) # same headers as submit
if status in TERMINAL:
return status
time.sleep(interval)
raise TimeoutError(f"job {job_id} did not finish in time")
3단계: 상태 존중
상태 필드를 열거형으로 취급하세요. 작업은 실행 중이거나, 성공적으로 완료되었거나, 실패한 것입니다. 세 가지 경우 모두 명시적으로 처리하세요: 성공 시 다운로드로 이동하고, 실패 시 오류 정보를 읽어 입력 문제인지 프롬프트 문제인지 판단하며, 시간 초과 시 폴링을 중지하고 추가 조사를 위해 작업 식별자를 노출하세요.
재시도는 두 계층에 속함
네트워크 수준 재시도는 제출 호출과 각 폴링 요청에 적용되어야 하며 시도 횟수는 제한되어야 합니다. 작업 수준 재시도는 다릅니다: 작업이 좋지 않은 프롬프트나 참조 이미지로 인해 실패하면 동일한 페이로드를 다시 제출해도 같은 방식으로 실패합니다. 작업 자체는 입력을 변경한 후에만 재시도하세요.
일반적인 프로덕션 패턴은 worker가 폴링 루프를 담당하도록 하여 웹 요청이 생성으로 인해 차단되지 않도록 하는 것입니다. API 핸들러에서 제출하고, 작업 식별자를 worker에 넘기고, worker가 완료되면 클라이언트에 알리세요.
2K 출력 다운로드 및 저장
작업의 최종 응답은 생성된 이미지를 내장하지 않고 가리키므로 다운로드는 여러분이 담당해야 하는 단계입니다.
이미지 가져오기
작업이 성공을 보고하면 응답에 출력 위치가 포함됩니다. 일반 GET 요청으로 검색한 다음 바이트를 파일에 쓰거나 스토리지로 스트리밍하세요. 개발 중에는 작업 식별자로 구성된 예측 가능한 이름으로 로컬 디렉터리에 저장하여 파일과 작업 기록을 연결하세요.
import pathlib
import urllib.request
def save_image(url, job_id, out_dir="output"):
pathlib.Path(out_dir).mkdir(exist_ok=True)
target = pathlib.Path(out_dir) / f"nano-banana-pro-{job_id}.png"
with urllib.request.urlopen(url, timeout=60) as response:
target.write_bytes(response.read())
return target
올바르게 저장
프로덕션에서는 로컬 디스크에 쓰지 않고 응답을 객체 스토리지로 직접 스트리밍하여 어떤 worker가 작업을 처리하든 동작이 일관되도록 하세요. 데이터베이스에 객체 키와 작업 식별자를 기록하고 콘텐츠 유형과 파일 확장자가 모델이 생성한 것과 일치하는지 확인하세요. 이미지가 웹페이지에서 제공될 경우 동일한 파이프라인에서 썸네일을 생성하여 공개 페이지가 절대 전체 2K 해상도 파일을 로드하지 않도록 하세요.
보존 정책 계획
생성된 출력은 여러분의 데이터입니다. 얼마나 오래 보존할지, 버전 관리가 필요한지, 최종 위치가 손실 시 애플리케이션이 재생성할 수 있는지 결정하세요. 답이 아니오라면 요청 페이로드와 이미지를 함께 저장하여 향후 버그나 모델 변경으로 인해 결과를 재현할 수 없게 되지 않도록 하세요.
흔한 실패 지점과 디버깅 방법
대부분의 첫 통합은 몇 가지 이유로 실패합니다. 모델에 문제가 있다고 가정하기 전에 이 체크리스트를 항목별로 확인하세요.
- 권한 부여 오류.
Bearer접두사 누락, 환경 파일에서 복사한 키에 줄바꿈 문자가 붙은 경우, 또는 설정된 기본 URL과 다른 환경의 키를 사용하는 경우. - 콘텐츠 유형 불일치. multipart 요청 헤더로 JSON 필드를 보내거나
application/json으로 파일을 보내는 것은 참조 이미지 요청이 거부되는 가장 흔한 원인입니다. multipart 요청 본문의 경우 클라이언트가 헤더를 설정하게 하세요. - 잘못된 메서드 또는 요청 본문 형식. POST 대신 GET을 사용하거나 중첩된
input객체 대신 최상위prompt를 사용하면 전혀 관련 없어 보이는 검증 오류가 발생합니다. 요청을 검증된curl호출과 바이트 단위로 비교하세요.curl -v는 실제 전송된 헤더를 보여줍니다. - 너무 빠른 폴링 또는 폴링 안 함. 상태 엔드포인트를 자주 요청하면 속도 제한이 발생하고, 전혀 폴링하지 않으면 아무것도 얻지 못합니다. 백오프가 있는 고정 간격과 하드 시간 초과를 사용하세요.
- 출력 URL 만료. 작업 완료와 다운로드 사이에 너무 오래 기다리면 서명된 출력 URL이 만료될 수 있습니다. 성공 직후 다운로드하거나 새 위치를 얻는 재조회 경로를 준비하세요.
- 코드의 조용한 실패. 오류 시 항상 HTTP 상태 코드와 응답 본문을 로깅하세요. HTTP 클라이언트가 던지는 일반 예외 메시지는 응답에서 유용한 부분을 숨깁니다.
불분명한 부분이 있으면 첫 번째 섹션의 검증된 curl 요청으로 돌아가세요. 해당 요청이 작동하는데 Python 호출이 작동하지 않는다면 둘 사이의 차이가 버그입니다.
관련 글
모든 아티클 보기 →-
튜토리얼
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 튜토리얼
요청 우선 실전 데모: 프롬프트에서 비디오 클립까지의 호출 구성, 요청 제출, 완료 상태 폴링 및 결과 다운로드