HiAPI
ブログ

チュートリアル

HiAPI 経由で Imagen 4 API を呼び出す方法:curl と Python のサンプル

Oct 31, 2026
博客封面图:淡灰紫色块与墨黑色块以一条笔直硬边相接,交界处一道细紫缝,构图简洁平静。

Imagen 4 エンドポイントでできること

すでにプロンプトがあり、課金アカウントの登録、キューの構築、使ったことのないプロバイダでのバケット作成をせずに画像を1枚取得したいなら、HiAPI 上の Google-Imagen4 モデルは妥当な出発点です。単一の HTTP エンドポイントにテキストプロンプトを送り、1つの API キーで認証すれば、生成画像への参照(またはポーリング可能なジョブ)が得られます。それ以外のすべて——モデルのホスティング、キャパシティ、プロバイダ側のリトライ——は抽象化されています。

このエンドポイント経由のテキストto画像呼び出しは、実際の利用で気になる3つの点をカバーします:

  • プロンプトから画像へ。プロンプトが主要な入力です。リクエストの設定方法に応じて、モデルは1枚または複数の画像を返します。
  • 出力形状の制御。生成後にトリミングするのではなく、リクエスト時にアスペクト比(正方形、横向き、縦向き)を指定できます。これは聞こえる以上に重要です:生成済み画像をトリミングすると、モデルがすでに計画していた構図が失われます。
  • 非同期実行。長めの生成はジョブとして処理されます。送信し、ステータスをポーリングし、結果を取得します。短い呼び出しはすぐ返るかもしれませんが、クライアントは毎回の呼び出しが非同期であるかのように書くべきです。それが本番トラフィックに耐えられるフローだからです。

このチュートリアルの残りでは、同じリクエストを3つの方法で構築します:ターミナルにそのまま貼り付けられる生の curl 呼び出し、等価な Python クライアント、そしてアスペクト比、ポーリング、永続化、エラー処理を扱う際に必要になる各部分です。1行のシェルコマンドで画像を生成したいなら、これは向いています。inpainting マスクや学習ループを細かく制御する必要があるなら、適していないかもしれません。

始める前に前提が2つあります:HiAPI API キーを持っていること、そしてコードを実行する環境が外向きの HTTPS リクエストを送れることです。それ以外の要件はありません——SDK のインストールは必須ではありませんが、以下の Python サンプルでは requests を使います。

curl で最初のリクエストを送る

キーが使えるか確認する最速の方法は curl 呼び出しです。このエンドポイントは JSON リクエストボディを受け取るため、2つのヘッダーが必要です:Content-Type はボディ用、Authorization はキー用です。キーはコマンドに直接貼り付けず、環境変数から読んでください。そうすればシェル履歴に残りません。

export HIAPI_API_KEY="your-key-here"

curl -sS -X POST "https://api.hiapi.ai/v1/images/generations" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -d '{
    "model": "google-imagen-4",
    "prompt": "a weathered lighthouse on a basalt cliff, morning fog, wide shot",
    "n": 1,
    "aspect_ratio": "16:9"
  }'

このリクエストボディで注目すべき点:

  • model は Google-Imagen4 を選択します。サービスにデフォルト値があっても明示的に書いてください——1年後にもコードが読めるようになります。
  • prompt は唯一必須の創造的入力です。写真家にショットを説明するように書いてください:被写体、環境、光、フレーミング。
  • n は取得する画像枚数を制御します。レスポンス構造を正しく整える段階では1枚から始め、パイプラインを信頼できるようになってから増やしてください。
  • aspect_ratio は後で詳しく説明します。省略するとサービスのデフォルト値にフォールバックします。

成功レスポンスは JSON オブジェクトを返します。関心があるのは画像エントリのリストです。各エントリにはダウンロード可能な参照、またはフロントエンドに渡せる URL が付きます。複数の画像をリクエストした場合は、リクエスト順に対応する複数のエントリを受け取ります。生成に時間がかかりキューに入った場合、レスポンスは識別子とポーリング可能なステータスを返します——そのフローは後述の専用セクションで説明します。

4xx を受け取ったら、まず2つのヘッダーを確認してください:Bearer プレフィックスの欠落や、キー末尾の空白文字が、初回呼び出し失敗のほとんどの原因です。デバッグ時は -i でステータス行とエラーレスポンスボディを確認してください。

Python で同じリクエストを送る

スクリプト内では、呼び出しを小さな関数でラップし、残りのコードが生の HTTP に触れないようにします。この関数はプロンプトとオプションのパラメータを受け取り、リクエストボディを構築し、リクエストを送り、解析済みの JSON を返すべきです。

import os
import requests

HIAPI_BASE = "https://api.hiapi.ai/v1"


def generate_image(prompt: str, aspect_ratio: str = "1:1", n: int = 1) -> dict:
    response = requests.post(
        f"{HIAPI_BASE}/images/generations",
        headers={
            "Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
            "Content-Type": "application/json",
        },
        json={
            "model": "google-imagen-4",
            "prompt": prompt,
            "n": n,
            "aspect_ratio": aspect_ratio,
        },
        timeout=120,
    )
    response.raise_for_status()
    return response.json()


if __name__ == "__main__":
    result = generate_image(
        "a weathered lighthouse on a basalt cliff, morning fog, wide shot",
        aspect_ratio="16:9",
    )
    print(result)

このコードを改変する際に残しておく価値のある設計上の選択が3つあります:

明示的なタイムアウト。requests にはデフォルトのタイムアウトがなく、接続がスタックするとワーカーが無期限にハングする可能性があります。想定される最も遅い生成時間より大きい値を選び、明示的に失敗させてください。

解析前に raise_for_status() を呼ぶ。エラーレスポンスは成功レスポンスと同じスキーマを持つとは限りません。レスポンスボディに触れる前に HTTP ステータスを確認してください。

小さくパラメータ化された関数。ポーリングとダウンロードを追加しても、この関数は送信の唯一の入口であり続け、ライフサイクルロジックはその隣に置かれ、内部に絡み合いません。

解析済みの結果は curl 出力と同じ情報を含みます。同期レスポンスでは画像エントリを反復して URL を取り出します。非同期レスポンスではジョブ識別子を取り出してポーリング関数に渡します。コードは受け取った形状に応じて分岐すべきで、1種類しかないと仮定すべきではありません。

アスペクト比と出力を制御する

アスペクト比は最も頻繁に調整するパラメータで、後からトリミングするのではなく正しく設定する価値があります。正方形の画像をリクエストしてから 16:9 の領域を切り出すと、モデルが意図的に構成した上部と下部が失われます。事前に 16:9 をリクエストすれば、モデルはその画角でショットを計画できます。

リクエストボディでプロンプトと一緒に渡します:

result = generate_image(
    "a sprawling night market, neon signs, steam from food stalls",
    aspect_ratio="16:9",
    n=2,
)

横向き比率はヒーローバナー、ワイドカードのサムネイル、商品撮影に、縦向き比率はモバイル優先のカード、ポスター、キャラクター写真に、正方形比率はアバターやトリミングが予測できないソーシャル投稿に使います。孤立した状態で見栄えがするかではなく、画像が最終的に置かれる場所に基づいて決めてください。

比率を変えたときにレスポンスで変わるのは、返される画像のピクセル寸法です。エントリ数、順序、ダウンロードフローは変わらないため、下流のコードが比率で分岐する必要はありません。UI が画像読み込み前にスペースを確保する場合は、サイズをハードコードせず、レスポンスから寸法を読んで要素に設定してください。

他に知っておく価値のある出力調整項目が2つあります:

  • 画像枚数(n)。リクエストごとにより多くの画像を求めることは、より多くの選択肢を意味しますが、間違っているかもしれないプロンプトにより多くのトークンを使うことも意味します。プロンプトの文言を反復する間は1枚だけリクエストし、プロンプトが安定してからバッチでリクエストしてください。
  • フレーミングのためのプロンプト文言。比率は画角を決め、プロンプトは画角内の構図を決めます。「wide shot」「close-up」「centered」といった言葉は比率パラメータと一緒に実際に効きます。

このエンドポイントの課金は画像生成そのものに従います——現在の料金はサイトの価格パネルを確認し、コストモデルに何もハードコードしないでください。

非同期ジョブとポーリングを扱う

生成に十分な時間がかかりキューに入ると、エンドポイントは画像が存在する前に返ります。ジョブハンドルを受け取り、あなたの仕事は終状態に達するまでそれを確認することです。今日の呼び出しがすぐ返っても、このフローを書いてください——キャパシティ、プロンプトの複雑さ、画像枚数はすべてレイテンシに影響し、同期シナリオ向けに構築されたクライアントは最初の遅いリクエストで壊れます。

ライフサイクルは3つのステップです:

  1. 送信。通常どおり生成リクエストを送ります。レスポンスがジョブなら、その識別子を抽出します。
  2. ポーリング。その識別子で一定間隔でジョブステータスエンドポイントを呼びます。
  3. 取得。ステータスが成功を報告したら、結果ペイロードから画像参照を読み取ります。
import time


def wait_for_job(job_id: str, interval: float = 2.0, max_attempts: int = 60) -> dict:
    for attempt in range(max_attempts):
        response = requests.get(
            f"{HIAPI_BASE}/images/jobs/{job_id}",
            headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
            timeout=30,
        )
        response.raise_for_status()
        payload = response.json()

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

        time.sleep(interval)

    raise TimeoutError(f"job {job_id} did not finish in time")

このコードを本番環境で安全にする重要な詳細:

  • 無限ループではなく試行回数を制限する。決して完了しないジョブは、永遠にハングするワーカーではなく、アラート可能なタイムアウトエラーとして現れるべきです。max_attempts 掛ける interval が実際の時間予算です——現実的に想定される最も遅い生成時間に基づいて設定してください。
  • 負荷時のバックオフ。固定の2秒間隔は対話的利用には問題ありません。バッチワークロードでは段階的にバックオフするかジッターを加え、多数のワーカーのリトライが同じ秒に同期しないようにしてください。
  • 失敗と不明を区別する。終状態の失敗は failed と cancelled だけです。その他の非成功ステータスは「まだ処理中」として再度ポーリングし、認識できないステータスに即座に例外を投げる分岐を加えると、サービスが新しいステータスを追加したときに問題になります。
  • ネットワークエラー時はポーリングではなく送信をリトライする。送信呼び出し自体がタイムアウトした場合、リトライすると重複ジョブが生まれる可能性があります。API が冪等キーをサポートするなら、各送信に冪等キーを付けてください。そうでなければ、プロンプトのハッシュとタイムスタンプで自分の側で重複排除してください。

ジョブが成功を報告したら、ポーリングを停止してください。結果を永続化し、監査用にジョブハンドルを保持する方が、すでに分かっているステータスを問い続けるより安上がりです。

画像をダウンロードして保存する

生成レスポンスは画像バイトではなく参照を返します。ほとんどの場合、各画像エントリには通常の GET リクエストで取得できる URL が付きます。その URL は一時的なアドレスとして扱ってください:速やかにダウンロードし、検証し、バイトを自分が本当に制御する場所に保存してください。

import pathlib
import uuid


def download_images(payload: dict, out_dir: str = "images") -> list[pathlib.Path]:
    target = pathlib.Path(out_dir)
    target.mkdir(parents=True, exist_ok=True)

    saved = []
    for entry in payload.get("data", []):
        url = entry["url"]
        resp = requests.get(url, timeout=60)
        resp.raise_for_status()

        content_type = resp.headers.get("Content-Type", "")
        if not content_type.startswith("image/"):
            raise ValueError(f"unexpected content type: {content_type}")

        path = target / f"{uuid.uuid4().hex}.png"
        path.write_bytes(resp.content)
        saved.append(path)

    return saved

ジョブを完了と見なす前に、いくつかの確認をしてください:

  • コンテンツタイプとサイズ。一部の環境では、エラーページへのリダイレクトが 200 と HTML を返します。永続ストレージに書き込む前に、Content-Type が image/ で始まり、レスポンスボディのサイズが取るに足らないものではないことを検証してください。
  • 命名。ダウンロードのたびに新しい名前を生成し、プロンプトから派生させないでください。プロンプトは重複し、衝突し、ファイルシステムが拒否する文字を含みます。
  • プロンプトをファイルと一緒に保存する。プロンプト、パラメータ、ジョブ識別子を自分のデータベースまたはサイドカーメタデータファイルに保存してください。半年後、画像だけではどのリクエストがそれを生成したか分かりません。
  • 永続ストレージにはコピーではなく移動する。まず一時的な場所に書き込み、検証してからストレージバケットまたは CDN 対応ストレージに移動してください。永続ストレージ内の書きかけファイルは、失敗したジョブよりも悪いです。

パイプラインが多くの画像を生成するなら、ダウンロードステップを生成ステップから分離してください。生成は高コストでレート制限のある部分です。ダウンロードのリトライは安価で、再生成を引き起こすべきではありません。

よくあるエラーとデバッグチェックリスト

初日の失敗のほとんどは少数のカテゴリに収まります。次の順序で確認してください——各チェックは次のものより高速です。

認証失敗(401、403)

キーが間違っている、欠落している、または形式が正しくありません。ヘッダー値が正確に Bearer とキーであり、貼り付け時の改行による改行文字がなく、環境変数が実際にコードを実行するシェルまたはプロセスでエクスポートされていることを確認してください。ダッシュボードでローテーションされたキーは古いキーを即座に無効にします——別のサービスがちょうど失敗し始めたなら、誰かがキーをローテーションしたか尋ねてください。

パラメータ拒否(400、422)

リクエストボディがスキーマと一致しません。よくある原因:model 識別子のスペルミス、aspect_ratio 文字列形式がエンドポイントに受け入れられない、または n がサポート範囲外。エラーレスポンスボディを出力してください——問題のあるフィールドを指し示すことがよくあります。JSON を動作する curl サンプルと比較し、フィールドごとに diff を取ってください。

タイムアウト

混同しやすい2つの異なるタイムアウトがあります。クライアントタイムアウトは HTTP 呼び出しが諦めたことを意味し、ジョブはまだ実行中の可能性があります。ジョブが終状態に達しないことは、ポーリング予算が小さすぎるか、リクエストが実際に失敗したことを意味します。クライアントタイムアウトは想定される最も遅い生成時間より大きく設定し、ポーリング予算はさらに大きく設定してください。送信中のクライアントタイムアウトが発生した場合、盲目的なリトライは作業を重複させる可能性があります——再送信する前に既存のジョブがないか確認してください。

成功したように見えて実際はそうでないダウンロード

200 ステータスなのに HTML レスポンスボディ、またはゼロバイトファイルは、通常、画像 URL が期限切れか、取得時に正しいアクセス権限がないことを意味します。ジョブ成功後すぐにダウンロードし、上記のようにコンテンツタイプとサイズを検証してください。

レート制限(429)

ループを締めるのではなく、バックオフしてリトライしてください。ジッター付き指数バックオフが標準的な答えです。リトライ回数を制限し、持続する失敗を監視に晒してください。

身につける価値のあるデバッグ習慣

各リクエストについて4つをログに記録してください:モデル識別子、キーを除いた完全なリクエストボディ、ジョブ識別子(同期呼び出しならレスポンスステータス)、そして経過時間。本番環境で問題が起きたとき、これら4つのフィールドは通常1分以内に、問題がクライアント側か、パラメータか、キューかを判断できます。

curl 呼び出しから始め、まず1枚の画像を取得し、次にロジックを Python クライアントに移し、その周りにポーリングと永続化を加えてください。この道筋は、すべての失敗を小さく、原因を特定できる範囲に保ちます。

永続的なAIアーティファクトで開発を始める

APIキーを取得して、タスクベースの1つのAPIで画像・動画・音声モデルを呼び出せます。

APIドキュメントを読む