チュートリアル
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——あなたのキーをベアラートークンとして渡します。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:ステータスを尊重する
ステータスフィールドは列挙型として扱いましょう。タスクは実行中か、成功して完了したか、失敗したかのいずれかです。三つのケースすべてを明示的に処理します。成功時はダウンロードに進み、失敗時はエラー情報を読んで入力かプロンプトの問題かを判断し、タイムアウト時はポーリングを停止して後で調査できるようタスク識別子を露出させます。
リトライは二つの層に属する
ネットワークレベルのリトライは、送信呼び出しと各ポーリングリクエストに適用し、試行回数に上限を設けるべきです。タスクレベルのリトライは異なります。タスクが悪いプロンプトや参照画像で失敗した場合、同じペイロードを再送信しても同じように失敗します。タスク自体のリトライは入力を変更した後だけにしましょう。
一般的な本番パターンは、ワーカーがポーリングループを担当し、Web リクエストが生成によってブロックされないようにすることです。API ハンドラーから送信し、タスク識別子をワーカーに渡し、ワーカーが完了したらクライアントに通知します。
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
正しく保存する
本番環境では、レスポンスをローカルディスクに書き込むのではなく直接オブジェクトストレージにストリーミングし、どのワーカーがタスクを処理しても動作が一貫するようにしましょう。データベースにオブジェクトキーとタスク識別子を記録し、コンテンツタイプとファイル拡張子がモデルの生成したものと一致するか確認します。画像を Web ページで提供する場合は、同じパイプラインでサムネイルを生成し、公開ページが完全な 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 のテキストto動画を使用する:curl と Python チュートリアル
リクエスト優先の実践デモ:プロンプトから動画クリップへの呼び出しを構築し、リクエストを送信し、完了状態をポーリングし、結果をダウンロードする