HiAPI
블로그

튜토리얼

HiAPI API로 nano-banana 사용하는 방법: curl, Python 및 실행 가능한 요청

첫 요청부터 출력 다운로드까지의 실전 전체 흐름

Oct 31, 2026
博客封面图:错位叠放的骨白色纸张,炭灰边缘,夹一张锈红色纸片,扁平投影。

nano-banana 요청의 모습

코드를 작성하기 전에 HiAPI에서 nano-banana 호출의 수명 주기를 이해하면 도움이 됩니다. 모든 요청은 동일한 패턴을 따릅니다. 원하는 내용을 설명하는 JSON 요청 본문을 보내면 HiAPI가 해당 작업을 접수하고, 그다음 완료된 결과를 직접 받거나 작업 핸들을 받아 완료 상태를 폴링합니다.

몇 가지 특징이 그 형태를 정의합니다:

  • 하나의 엔드포인트, 하나의 API 키. 모든 nano-banana 트래픽은 HiAPI 통합 인터페이스를 거칩니다. HiAPI 키로 인증하며 업스트림과 직접 접촉하는 일은 없습니다.
  • JSON 입력, JSON 출력. 요청 본문은 JSON입니다. 응답도 JSON이며, 인라인 결과를 포함하거나 작업 id와 상태 필드를 포함합니다.
  • 텍스트 필수, 이미지 선택. 최소한 프롬프트를 보내야 합니다. 참조 이미지를 추가하여 주체, 스타일 또는 캐릭터를 유도할 수 있습니다.
  • 비동기 친화적. 이미지 생성은 일반적인 HTTP 타임아웃보다 오래 걸릴 수 있으므로 API는 비동기 작업을 지원하며, 완료될 때까지 폴링할 수 있습니다.

요청 본문의 대략적인 구조:

{
  "model": "nano-banana",
  "prompt": "a description of the image you want",
  "image_input": ["https://.../reference.jpg"],
  "consistency": "character",
  "async": true
}

비동기일 때의 응답:

{
  "id": "job_abc123",
  "status": "queued",
  "created_at": "..."
}

작업이 완료되어 가져오면 status가 succeeded(또는 failed)로 바뀌고 결과 페이로드에 출력 URL이 포함됩니다. 이 2단계 모델을 기억하세요. 이 튜토리얼의 이후 모든 내용이 이 위에 구축되기 때문입니다.

실행 가능한 curl 요청

이것은 이미지를 생성하는 최소 요청입니다. HIAPI_API_KEY가 셸에 내보내져 있다고 가정합니다:

curl -X POST https://api.hiapi.ai/v1/images/generations \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana",
    "prompt": "a cozy reading nook by a rain-streaked window, warm lamp light, watercolor style",
    "async": true
  }'

필드별 설명:

  • model — nano-banana로 설정합니다. HiAPI는 이를 사용하여 요청을 라우팅합니다.
  • prompt — 유일하게 엄격히 필수인 창작 필드입니다. 주체, 구도, 스타일을 구체적으로 설명하세요. 모호한 프롬프트는 실망스러운 출력의 가장 흔한 원인입니다.
  • async — true일 때 API는 즉시 작업 핸들을 반환합니다. 완료될 때까지 차단하려면 false로 설정할 수 있지만 더 긴 응답 시간을 대비하세요.
  • image_input — 선택적 참조 이미지 URL 배열입니다. 텍스트만으로 이미지를 생성할 때는 생략합니다.
  • consistency — 선택적 이미지 간 캐릭터 또는 주체 제어입니다. 자세한 내용은 아래를 참조하세요.

현재 버전이 어떤 선택적 파라미터를 지원하는지 확실하지 않다면 필드를 추가하기 전에 HiAPI의 해당 모델 문서 페이지를 먼저 확인하세요. 알 수 없는 필드는 파라미터에 따라 무시되거나 거부될 수 있습니다.

명령을 실행하고 JSON을 확인하세요. async가 true라고 가정하면 이미지 대신 작업 객체를 받게 됩니다. id를 저장하세요. 그것이 다음 단계의 핸들입니다.

요청을 Python으로 이식하기

curl 호출은 그대로 변환할 수 있습니다. 여기서 목표는 일회성 스크립트를 작성하는 것이 아니라 파이프라인에 넣을 수 있는 재사용 가능한 래퍼입니다.

import os
import time
import requests

BASE = "https://api.hiapi.ai"
HEADERS = {
    "Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
    "Content-Type": "application/json",
}

def create_image(prompt, image_input=None, consistency=None, async_job=True):
    body = {"model": "nano-banana", "prompt": prompt, "async": async_job}
    if image_input:
        body["image_input"] = image_input
    if consistency:
        body["consistency"] = consistency

    resp = requests.post(
        f"{BASE}/v1/images/generations",
        headers=HEADERS,
        json=body,
        timeout=60,
    )
    if resp.status_code >= 400:
        raise RuntimeError(f"create failed: {resp.status_code} {resp.text}")
    return resp.json()

다음 몇 가지가 단순히 작동하는 것을 넘어 견고하게 만듭니다:

  • 명시적 타임아웃. 항상 전달하세요. "영원히 기다림" 기본값은 일시적인 네트워크 문제를 멈춘 프로세스로 바꿉니다.
  • 파싱 전 상태 확인. 오류 응답에 예외를 발생시키면 잘못된 요청이 나중에 인덱싱할 JSON 본문을 조용히 반환하지 않습니다.
  • 선택적 필드는 비우지 말고 생략하세요. "image_input": null을 보내는 대신 값이 있을 때만 해당 키를 추가하세요. 이렇게 하면 로그를 더 읽기 쉽게 하고 null이 "없음"인지 "설정되지 않음"인지에 대한 모호함을 피할 수 있습니다.

함수로 감싸면 재시도도 쉬워집니다. 함수가 실패 시 예외를 발생시키므로 호출자는 요청 코드를 건드리지 않고 재시도 루프로 감쌀 수 있습니다. 단일 이미지에서 배치 처리로 이동하면 이러한 분리가 보상을 줍니다.

텍스트와 이미지 입력 보내기

텍스트로 이미지 생성은 단순한 경우입니다. nano-banana의 흥미로운 부분은 단일 요청에서 프롬프트와 참조 이미지를 결합하는 것입니다. image_input을 URL 배열로 전달하고 프롬프트에서 이를 어떻게 처리할지 설명합니다.

result = create_image(
    prompt="the person in the first image standing in a Tokyo alley at night, neon reflections, cinematic",
    image_input=["https://example.com/portrait.jpg"],
)

혼합 모달리티를 위한 실용적인 조언:

  • 역할을 명확히 하세요. 여러 이미지를 보낸다면 어느 것이 주체를, 어느 것이 스타일을, 어느 것이 배경을 제공하는지 프롬프트에서 명시하세요. "이 이미지들을 조합하라"는 모호합니다. "이미지 1의 얼굴과 이미지 2의 조명을 사용하라"는 그렇지 않습니다.
  • 접근 가능하고 안정적인 URL을 사용하세요. API가 이미지를 가져올 수 있어야 합니다. 몇 분 후 만료되는 서명 URL은 실시간 호출에는 괜찮지만 나중에 대기 중인 작업을 재시도하면 무효가 됩니다.
  • 깨끗한 참조를 우선하세요. 선명하고 조명이 좋은 인물 사진이 복잡한 단체 사진보다 더 충실한 인물 유사도를 생성합니다. 이미지 조건화에서 쓰레기 입력, 쓰레기 출력은 텍스트보다 더 두드러집니다.
  • 참조 이미지가 아니라 프롬프트를 먼저 반복하세요. 유사도가 맞지 않으면 소스 이미지를 바꾸기 전에 주체를 설명하는 방식을 먼저 조정하세요. 보통 이것이 더 수월한 변경입니다.

참조 이미지에 여러 생성에서 재사용하려는 인물이 포함되어 있다면 캐릭터 일관성의 영역으로 들어가며, 이것이 다음 섹션입니다.

캐릭터 일관성 옵션

캐릭터 일관성은 구체적인 요구를 해결합니다. 동일한 캐릭터나 주체가 등장하는 것처럼 보이는 여러 이미지를 생성하는 것입니다. nano-banana는 이를 별도의 모델이 아니라 선택적 제어로 노출합니다.

고수준에서 트레이드오프는 대략 다음과 같습니다:

  • 일관성 제어 없음. 일회성 이미지에 가장 적합합니다. 빠르고 간단하지만 재생성하면 캐릭터가 흔들릴 수 있습니다. 배경, 사물, 독립 일러스트에 사용하세요.
  • 참조 기반 일관성. 하나 이상의 캐릭터 이미지를 제공하고 일관성 옵션을 설정하여 모델이 이를 고정하도록 합니다. 프레임 간에 정체성이 유지되어야 하는 스토리보드, 만화, 제품 시퀀스에 올바른 선택입니다. 대가는 먼저 좋은 참조 이미지가 있어야 한다는 것입니다.
  • 텍스트 설명 기반 일관성. 참조 없이 각 프롬프트에서 캐릭터를 자세히 설명합니다. 머리색, 의상, 체형, 두드러진 특징 등입니다. 소스 사진이 없을 때 유용하지만 규율이 필요합니다. 설명을 재사용 가능한 상수에 넣어 호출 간에 흔들리지 않게 하세요.

시리즈를 위한 실용적인 워크플로:

  1. 일관성 없이 첫 프레임을 생성하고 캐릭터가 올바르게 보일 때까지 프롬프트를 반복합니다.
  2. 해당 출력을 참조 이미지로 사용합니다.
  3. 일관성 제어를 켜고 참조를 고정한 채 후속 프레임을 생성합니다.
  4. 캐릭터가 여전히 흔들리면 프롬프트를 줄이고 참조가 더 많은 일을 하도록 하세요. 참조와 모순되는 긴 프롬프트는 모델을 혼란스럽게 합니다.

일관성은 다이얼이지 보장이 아닙니다. 잘 튜닝된 파이프라인에서도 출력을 검토하고 소수의 프레임을 재생성할 것을 예상하세요.

비동기 작업 폴링

async: true로 제출하면 작업 id를 받습니다. 폴링은 간단하지만 세부 사항이 보이는 것보다 더 중요합니다.

최소하면서도 올바른 폴러:

def wait_for_job(job_id, timeout=300, initial_delay=2, max_delay=15):
    deadline = time.time() + timeout
    delay = initial_delay
    while time.time() < deadline:
        resp = requests.get(
            f"{BASE}/v1/images/generations/{job_id}",
            headers=HEADERS,
            timeout=30,
        )
        resp.raise_for_status()
        data = resp.json()

        status = data.get("status")
        if status == "succeeded":
            return data
        if status in ("failed", "cancelled"):
            raise RuntimeError(f"job {job_id} ended as {status}: {data}")

        time.sleep(delay)
        delay = min(delay * 1.5, max_delay)

    raise TimeoutError(f"job {job_id} did not finish within {timeout}s")

각 선택의 이유:

  • 상한이 있는 준지수 백오프. 몇 초에서 시작하여 상한까지 1.5를 곱합니다. 30초 작업에 고정 1초 폴링은 수십 개의 요청을 낭비합니다. 고정 30초 폴링은 빠른 작업에 불필요한 지연을 추가합니다.
  • 하드 데드라인. 이것이 없으면 멈춘 작업이 워커를 무기한 차단합니다. 크게 실패하는 편이 낫습니다.
  • 종료 상태 처리. failed와 cancelled를 계속 폴링할 상태가 아니라 예외로 취급하세요. 실패 상태의 작업은 다음 폴링에서 절대 성공하지 않습니다.
  • 매 반복마다 새로운 GET 요청. 첫 응답을 캐시하고 업데이트될 것이라고 가정하지 마세요.

배치 작업의 경우 모든 작업을 먼저 제출하고 id를 수집한 다음 루프에서 폴링하세요. 이렇게 하면 생성 시간이 직렬화되지 않고 작업 간에 겹칩니다.

출력 다운로드 및 검증

작업이 성공하면 결과 페이로드에 출력 URL이 포함됩니다. 다운로드는 일반 GET이지만 확인하기 전에 이 바이트가 이미지라고 가정해서는 안 됩니다.

def download_image(url, path):
    with requests.get(url, stream=True, timeout=60) as r:
        r.raise_for_status()
        content_type = r.headers.get("Content-Type", "")
        if not content_type.startswith("image/"):
            raise RuntimeError(f"unexpected content type: {content_type}")
        with open(path, "wb") as f:
            for chunk in r.iter_content(chunk_size=8192):
                f.write(chunk)
    return path

모든 다운로드에서 할 가치가 있는 점검:

  • Content-Type. 이미지를 요청했는데 application/json 또는 text/html을 받으면 실제로 오류 페이지를 받은 것입니다. 헤더를 확인하면 손상된 파일을 쓰기 전에 이를 잡을 수 있습니다.
  • 스트리밍. 전체 응답 본문을 메모리에 로드하는 대신 디스크에 스트리밍하세요. 병렬 다운로드 시 메모리를 안정적으로 유지합니다.
  • 0이 아닌 크기. 0바이트 파일은 HTTP 상태가 정상이어도 문제가 발생했음을 의미합니다.
  • 로그에 체크섬 또는 바이트 수를 기록하세요. 작업 id와 함께 기록하면 나쁜 파일을 특정 생성으로 추적할 수 있습니다.

출력 URL은 임시일 수 있습니다. 결과를 보관할 계획이라면 나중에 사용하기 위해 링크를 저장하는 대신 같은 실행에서 자체 스토리지로 다운로드하세요.

흔한 실패 지점

대부분의 문제는 몇 가지 범주로 나뉩니다. 모델이 이상하게 동작한다고 가정하기 전에 이것들을 먼저 확인하세요.

인증과 라우팅

  • 누락되거나 형식이 잘못된 Authorization 헤더는 이미지가 아니라 인증 오류를 반환합니다. 헤더가 Bearer <key>로, 사이에 공백이 하나 있는지 확인하세요.
  • 잘못된 model 값을 보내면 잘못된 곳으로 라우팅되거나 바로 실패합니다. 정확히 nano-banana여야 합니다.

요청 본문 문제

  • 모호한 프롬프트. "나쁜 출력"의 가장 흔한 단일 원인입니다. 다른 무엇을 바꾸기 전에 구도, 조명, 스타일 세부 사항을 추가하세요.
  • 접근 불가능한 이미지 URL. 404를 반환하거나 인증이 필요하거나 로컬 경로를 가리키는 참조 URL은 실패하거나 조용히 무시됩니다. URL을 한 번 직접 가져와 작동하는지 확인하세요.
  • async: false로 긴 프롬프트를 보내고 클라이언트 타임아웃에 도달하는 경우. 타임아웃을 늘리는 대신 비동기로 전환하고 폴링하세요.

작업 처리

  • 존재한 적 없는 작업을 폴링. 작업 id의 오타는 실패처럼 보이는 찾을 수 없음 오류를 생성합니다. 제출한 id를 기록하세요.
  • failed를 여전히 실행 중인 것으로 취급. 항상 종료 상태에서 폴링 루프를 종료하세요.
  • 데드라인 없음. 배치 작업에서 가장 비용이 큰 버그입니다. 멈춘 이미지 하나가 전체 실행을 지연시킵니다.

출력 처리

  • Content-Type 미확인. 위에서 언급했듯이 .png 확장자로 저장된 오류 페이지는 나중에 손상된 이미지처럼 보입니다.
  • 생성 몇 시간 후 만료된 결과 URL에 의존. 제때 다운로드하세요.

인증, 요청 본문, 작업 수명 주기, 다운로드 순서로 하나씩 확인하면 대부분의 장애가 몇 분 안에 해결됩니다.

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

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

API 문서 보기