HiAPI
ブログ

チュートリアル

recraft-v4-styles/text-to-image API チュートリアル:curl、Python、非同期ポーリング

HiAPI 上でスタイル参照画像生成を使用するための完全なリクエスト実践

Oct 31, 2026
深蓝底色上铜色细分平行线构成几何带状图案,呼应异步轮询主题的博客封面图

recraft-v4-styles/text-to-image でできること

recraft-v4-styles/text-to-image はスタイル参照画像生成エンドポイントです。見たい内容を記述したテキストプロンプトと、外観のスタイルを記述した1枚以上の参照画像を渡します。モデルはその両者を融合します。プロンプトが内容と構図の意図を担い、参照画像が視覚的スタイルを担います。

エンドポイントを選ぶ際、この違いは重要です。外観を完全に文字で表現できる場合——たとえば「コーヒーカップのフラットベクターイラスト、2色、太い輪郭」——は、プロンプトによる画像生成が適切なツールです。しかし実際のプロダクト作業では、大多数のシナリオが説明するのは難しく見せるのは簡単なブランド外観を伴います。既存のキービジュアル、以前に承認されたレンダリング、あるいはデザインシステムのサンプルは、形容詞の段落よりもはるかに正確にスタイル仕様を定義します。まさにこのエンドポイントが埋める空白がそれです。

開発者の視点では、これは2入力の変換と捉えられます:プロンプト + スタイル参照 -> 画像。これを統合するすべてはこの形から導かれます。単なる文字列のシリアライズではなく、参照画像が一級入力である複数パーツからなる小さなペイロードの組み立てです。リクエスト構築コードはそれらをそのように扱うべきであり、検証レイヤーはタスクがサービスを離れる前に、プロンプトはあるが使用可能なスタイル参照がないタスクを拒否すべきです。

このエンドポイントは非同期です。リクエストを送信するとタスクが返り、そのタスクをポーリングし、最終的に画像はインラインバイトではなく URL として届きます。これは画像ワークロードに対する意図的な設計です。生成には十分時間がかかり、HTTP 接続を開いたままにしておくのは無駄で脆いからです。「送信-ポーリング-ダウンロード」のライフサイクルを受け入れれば、統合の残りは普通の API パイプライン作業です。

機能するリクエストの解剖

コードを書く前に、フィールドのグループ分けを整理しましょう。recraft-v4-styles/text-to-image リクエストは3つの論理的な部分から構成されます。

プロンプト

プロンプトは内容の指示です。画面に含めるべきもの——被写体、構図、フレーミング、オブジェクトの数、背景の処理——を中心に書きます。参照画像がすでに伝えているスタイル形容詞にプロンプトの予算を使うのは避けましょう。プロンプトと参照画像の間の信号の衝突は、しばしば曖昧な結果を生みます。プロンプトは短く、具体的で、テスト可能に保ちましょう。

スタイル参照入力

これがこのエンドポイントを通常のテキストから画像生成の呼び出しと区別する部分です。スタイル参照はプロンプトとともに提供される画像で、視覚言語を定義します。それらを組み立てる際は、雑多な画像の山ではなく、厳選されたセットとして扱うべきです:

  • 一貫性は量に勝る。 同じ首尾一貫した外観を共有する数枚の参照画像は、スタイルがばらばらな多くの参照画像よりもモデルによく教えます。
  • 解像度とフレーミングは重要。 参照画像はサムネイルやひどく切り取られた断片ではなく、望む出力を代表するものであるべきです。
  • アクセス可能でなければならない。 参照画像を URL として渡す場合、それらの URL はリクエスト時に公開取得可能でなければなりません。60秒で期限切れになる署名付きリンクは、遅いタスクを失敗させます。

参照画像セットはコードのあちこちに散らばすのではなく、設定に保管しましょう。そうすればブランド資産と一緒にバージョン管理できます。

出力オプション

残りのフィールドは返してほしい成果物を記述します。これらは内容ではなく返される画像に影響するノブです。正確なパラメータ名と許容値はエンドポイントのリファレンスページに記載されています。推測せずにそこで読み、コード内の1か所にまとめておけば、仕様変更は1ファイルを触るだけで済みます。

有用な習慣:選択した言語で JSON ボディを辞書/オブジェクトとして構築し、初回実行時にデバッグレベルで一度ログ出力し、悪い結果をモデルのせいにする前にその構造を目視確認すること。

curl での呼び出し

curl から始めましょう。あなたとワイヤーフォーマットの間のライブラリ抽象化をすべて取り除くので、リクエストに誤りがあればすぐに気づけます。

送信は POST リクエストで、JSON ボディと HiAPI API キーを運ぶ認証ヘッダーを伴います:

curl -sS -X POST "https://api.hiapi.ai/v1/recraft-v4-styles/text-to-image" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a ceramic coffee cup on a linen tablecloth, soft daylight",
    "style_references": [
      "https://your-cdn.example.com/style/ref-01.png"
    ]
  }'

目にした内容についていくつか補足します:

  • キーは環境変数($HIAPI_API_KEY)に保持し、シェル履歴やコミットされたスクリプトにインラインで書かないこと。
  • -d ペイロードは純粋な JSON です。シェルのクォート規則はよくあるトラブルの元です。パースエラーが出たら、ボディをファイルにエコーして -d @body.json を使いましょう。
  • ここに示すフィールド名は前節のリクエスト解剖に従っています。リリース前に、エンドポイントのリファレンスページで正確な名前と許容される出力オプションを確認してください。

応答は画像ではありません。タスク確認です。今キューに入れた生成を識別する識別子と、まだ完了していないことを示すステータスフィールドです。初回実行時はレスポンスボディを注意深く読み、タスク ID を保存するフィールド名を書き留めましょう。その文字列が以降のすべての操作のハンドルです。保存してください。最初の応答にエラーオブジェクトが含まれていたら、立ち止まってリクエストを修正しましょう。受け取ったことのない ID をポーリングするのは最もよくある行き止まりです。

同じリクエストを Python で実装する

curl 呼び出しを一度 Python に移植すれば、再利用可能なプリミティブが手に入ります。以下の例は requests を使い、リクエストボディを完全にミラーしています。

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1"

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

STYLE_REFERENCES = [
    "https://your-cdn.example.com/style/ref-01.png",
]

def submit_generation(prompt: str) -> dict:
    body = {
        "prompt": prompt,
        "style_references": STYLE_REFERENCES,
    }
    resp = requests.post(
        f"{BASE_URL}/recraft-v4-styles/text-to-image",
        headers=HEADERS,
        json=body,
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()

if __name__ == "__main__":
    job = submit_generation(
        "a ceramic coffee cup on a linen tablecloth, soft daylight"
    )
    print(job)

このコードを調整する際に残す価値のある設計選択が2つあります:

  • 常にタイムアウトを設定する。 送信は素早く返るべきです。ハングするなら、スタックしたプロセスではなく例外が欲しいはずです。
  • レスポンスオブジェクトではなくパース済み JSON を返す。 下流のコードは requests の内部実装ではなくタスクペイロードに依存すべきです。これにより後でトランスポート層を差し替えるのが容易になります。

上述したように、参照画像セットはモジュールまたは設定レベルで定義しましょう。ブランド外観が進化したら、呼び出し箇所を探し回るのではなく、1つのリストを更新するだけです。またリクエストボディの構築は単一の関数に保ち、エンドポイントが必要とするフィールドは1か所で追加できるようにしましょう。

非同期結果のポーリング

生成は非同期なので、送信したタスクは完了まで複数の状態を経ます。クライアントには、状態を確認し、確認の間にバックオフし、最終的に諦める待機ループが必要です。

import time

def wait_for_result(job_id: str, timeout_s: int = 300, interval_s: float = 3.0) -> dict:
    deadline = time.monotonic() + timeout_s
    delay = interval_s
    while time.monotonic() < deadline:
        resp = requests.get(
            f"{BASE_URL}/recraft-v4-styles/text-to-image/{job_id}",
            headers=HEADERS,
            timeout=30,
        )
        resp.raise_for_status()
        data = resp.json()
        status = data.get("status")
        if status in ("succeeded", "failed"):
            return data
        time.sleep(delay)
        delay = min(delay * 1.5, 15.0)
    raise TimeoutError(f"job {job_id} did not finish in {timeout_s}s")

このループで重要な点:

  • 未知の状態は保留として扱う。 進行中状態の許可リストと比較するのではなく、明示的な終端状態と比較しましょう。プラットフォームが中間状態を追加しても、ループはクラッシュせず待機を続けます。
  • バックオフ。 5分間毎秒固定でポーリングするのは、5分間の無駄なリクエストです。小さな間隔から始めて倍増させ、上限を設けましょう。
  • 待機時間を制限する。 すべてのループには締め切りが必要で、締め切りは呼び出し側が処理できる例外として現れるべきです。
  • 失敗に応じて分岐する。 終端の失敗状態は診断情報を運びます。レスポンスボディ全体を記録しましょう——これが「壊れた」と「参照 URL が 403 を返した」の違いです。

大量の画像を処理するなら、Web リクエストハンドラ内でスリープしないでください。送信し、タスク ID を永続化し、バックグラウンドワーカーやスケジュールタスクにポーリングを駆動させましょう。エンドポイントのリファレンスページには正確なステータス値とポーリングパスが記載されています。クライアントをアップグレードするたびに確認しましょう。

出力のダウンロードと保存

タスクが終端の成功状態に達すると、応答には生成画像の URL が含まれます。この URL が API とストレージ層の間の受け渡し点です。

バイトとして取得し、必要な場所に書き込みます:

def download_image(url: str, dest_path: str) -> None:
    resp = requests.get(url, timeout=60)
    resp.raise_for_status()
    with open(dest_path, "wb") as f:
        f.write(resp.content)

ローカル実験以外のあらゆる場面では、成果物を返された URL に置き去りにしないでください。生成画像は一時的なポインタとして扱い、自分が管理するストレージ——オブジェクトストレージバケット、CDN オリジン、メディアパイプライン——にコピーしましょう。理由は3つあります:

  1. ライフサイクル。 生成出力 URL が無期限に保持される保証はありません。リトライ中に古い URL から再ダウンロードするのは、潜在的なサイレント障害です。
  2. 安定したキー。 アプリケーションは再生成のたびに変わる URL ではなく、データベース行に格納できる決定論的識別子を必要とします。
  3. 来歴。 プロンプト、スタイル参照セットのバージョン、タスク ID を画像と一緒に保存すれば、後で任意の資産を再現または監査できます。このメタデータは付随レコードやデータベース列に保持しましょう。

オブジェクトストレージにアップロードする際は、大きな画像をメモリに完全にバッファリングせずレスポンスボディをストリーミングし、レスポンスヘッダーからコンテンツタイプを設定しましょう。自分の CDN を経由して画像をクライアントに返す場合、このステップはキャッシュヘッダーを適用する場所でもあります。

初回実行のトラブルシューティング

ほとんどの初回試行はいくつかの予測可能な方法で失敗します。これらを順に確認してください。

リクエストボディが拒否される

400 系のエラーは通常、不正な JSON か必須フィールドの欠落を意味します。まず curl バージョンを実行し、送信している正確なボディを確認しましょう。よくある問題:シェルのクォートが JSON を壊す、API が配列を期待するフィールドを文字列で送る、出力オプションの値が許容範囲外。エンドポイントのリファレンスページがフィールド名と値の権威ある情報源です——ボディをそれと文字通り照合してください。

プロンプトはあるが使用可能なスタイル参照がない

このエンドポイントはスタイル参照を中心に構築されています。リクエストにプロンプトが含まれていても、参照画像が空、アクセス不能、または取得時に認証エラーを返す場合、タスクは拒否されるか、意図した外観を無視した出力を生成します。プラットフォームが使うのと同じ資格情報なしのクライアントで各参照 URL を取得して検証してください。セッション Cookie や署名付きクエリ文字列を必要とする参照画像は壊れているとみなします。

タスク ID が一度も得られない

送信応答は確認であり、画像ではありません。初回応答に画像バイトが含まれると期待するコードを書くと、毎回の実行で失敗します。応答をパースし、タスク ID を抽出してからポーリングを始めましょう。最初の数回の実行では送信応答全体を記録し、その形を確認できるようにしましょう。

ポーリングが頻繁すぎる

1分間に数百回のステータスチェックはタスクを速く完了させず、むしろレート制限を引き起こす可能性が高いです。増加する間隔に上限を設け、タスクごとに単一のワーカープロセスを使いましょう。多数のタスクをディスパッチする場合は、送信のバーストがポーリングのバーストにならないよう、小さな並行制限を追加しましょう。

タスクは完了したがダウンロードが失敗する

出力 URL の取得時に 403 や 404 が出るのは通常、URL が期限切れか、誤読したステータスチェックの後にタスクが失敗したことを意味します。終端状態が成功であることを確認し、応答を読み直して実際の出力フィールドを取得しましょう。成果物が利用可能になったらすぐに保存し、ダウンロードを先延ばしにしないでください。

パイプラインが動く順序——送信、ポーリング、ダウンロード——でこれらの問題を一つずつ解決すれば、初回実行の失敗はほとんど常に明白な修正へと解消されます。エンドポイントのリファレンスとそのリクエストスキーマは、フィールドレベルの疑問を確認する最速の方法です。

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

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

APIドキュメントを読む