HiAPI
ブログ

チュートリアル

hailuo 2.3 の Image-to-Video API の使い方:curl、Python、そして実行可能なリクエスト例

Jul 11, 2026
hailuo 2.3 の Image-to-Video API の使い方:curl、Python、そして実行可能なリクエスト例

概要

  • これは何か:hiapi 上で hailuo-2.3/image-to-video API を使うための実行可能なレシピです——静止画像を短い動画に変換します:タスクの作成、タスクのポーリング、.mp4 のダウンロード。
  • エンドポイント:POST https://api.hiapi.ai/v1/tasks。リクエストボディに "model": "hailuo-2.3/image-to-video" を指定し、その後 GET /v1/tasks/<taskId> でタスクが終状態になるまでポーリングします。
  • 2つの必須入力フィールド:prompt と image_url——最初のフレームを指す単一の公開 URL です(配列ではありません)。
  • duration は文字列であり、数値ではありません:"6" または "10"。整数 6 を渡すと 400 で拒否されます。
  • スキーマは厳格です。motion_strength、camera_movement、resolution といったパラメータはありません——渡すと 400 で拒否されます。動きは完全に prompt で制御します。

何を構築するか、そして何を準備するか

静止画像——商品画像、キャラクターのレンダリング、写真——があり、hailuo-2.3 でそれを動かし、まさにこのフレームから始まる動画クリップを生成したいとします。hailuo-2.3 は物理的に信憑性のある動き(布地、髪、身体力学)で知られており、静止画像を生き生きとさせるのに最適です。

必要なものは2つです:

  1. hiapi の API キー。dashboard で作成します。キーは sk-... の形式で、Authorization: Bearer ヘッダーに含めます。
  2. 公開アクセス可能な最初のフレーム画像の URL。API は image_url から画像を取得するため、認証なしでアクセスできる必要があります——S3/R2/CDN のリンクは可、localhost のパスや期限切れの署名付き URL は不可です。

hiapi 上のすべての生成モデルと同様、このモデルも非同期タスクインターフェースを使用します:タスクを POST するとすぐに taskId が返り、その後ポーリングまたはコールバックで結果を受け取ります。動画には同期エンドポイントはありません——クリップのレンダリングには時間がかかり、典型的な HTTP タイムアウトを超えます。

リクエストスキーマ

hailuo-2.3/image-to-video の完全な入力スキーマ——実際の API で検証済み:

フィールド 型 必須 説明
prompt string ✅ シーンではなく動きを記述します——シーンは画像から得られます。
image_url string ✅ 最初のフレームとなる単一の公開 URL です。単数形であり、image_urls ではありません。
duration string 任意 "6" または "10"(秒)。文字列でなければなりません。
prompt_optimizer boolean 任意 生成前にプラットフォームに prompt を拡張させます。

スキーマは厳格です:この表にないものはすべて拒否されます。motion_strength、camera_movement、resolution を送信すると、そのまま次のレスポンスを受け取ります:

{
  "code": 400,
  "error_code": "INVALID_REQUEST",
  "message": "invalid input: <root>: additional properties 'resolution', 'camera_movement', 'motion_strength' not allowed"
}

覚えておくべき2つの帰結:

  • 動き調整のつまみはありません。hailuo-2.3 の動きの物理は prompt によってのみ導かれます——下のプロンプト作成セクションを参照してください。
  • このエンドポイントには解像度やアスペクト比の制御はありません。API が 400 を返すパラメータの UI を構築しないでください。

最小限の実行可能な例:curl

タスクの作成:

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<your-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hailuo-2.3/image-to-video",
    "input": {
      "prompt": "The woman turns toward the camera and smiles; wind gently moves her hair; slow cinematic push-in",
      "image_url": "https://your-cdn.example.com/first-frame.jpg",
      "duration": "6",
      "prompt_optimizer": true
    }
  }'

レスポンス(抜粋)には data.taskId の下にタスク id が含まれます:

{ "data": { "taskId": "..." } }

ポーリング:

curl -s https://api.hiapi.ai/v1/tasks/<taskId> \
  -H "Authorization: Bearer sk-<your-key>"

クリップのレンダリング中、data.status は非終状態を報告します。"success" に変わると、動画 URL は data.output[0].url にあります。"fail" の場合は、data.error.code と data.error.message が理由を示します。

タスク成功後はすぐにファイルをダウンロードしてください。出力 URL は署名付きで有効期限(expireAt)があります——バイトを自分のストレージに保存し、タスク URL をホットリンクしないでください。

最小限の実行可能な例:Python

同じフローの完全なスクリプト——作成、ポーリング、ダウンロード:

import time
import requests

API_BASE = "https://api.hiapi.ai/v1/tasks"
API_KEY = "sk-<your-key>"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}


def create_task() -> str:
    payload = {
        "model": "hailuo-2.3/image-to-video",
        "input": {
            "prompt": (
                "The cat stretches, hops off the windowsill, and walks toward "
                "the camera; soft afternoon light, subtle handheld camera sway"
            ),
            "image_url": "https://your-cdn.example.com/first-frame.jpg",
            "duration": "6",          # string, not int: "6" or "10"
            "prompt_optimizer": True,
        },
    }
    r = requests.post(API_BASE, json=payload, headers=HEADERS, timeout=30)
    task_id = (r.json().get("data") or {}).get("taskId")
    if not task_id:
        raise RuntimeError(f"create failed ({r.status_code}): {r.text[:300]}")
    return task_id


def wait_task(task_id: str, timeout_s: int = 900, poll_s: int = 10) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS, timeout=30)
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task
        if status == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")


def main() -> None:
    task_id = create_task()
    print("task created:", task_id)
    task = wait_task(task_id)
    url = task["output"][0]["url"]
    # The URL is signed and expires -- download immediately, store the bytes yourself.
    video = requests.get(url, timeout=120).content
    with open("hailuo-output.mp4", "wb") as f:
        f.write(video)
    print("saved hailuo-output.mp4")


if __name__ == "__main__":
    main()

動画タスクは画像タスクより明らかに実行時間が長いため、スクリプトは10秒ごとにポーリングし、15分の余裕ある上限を設定しています。約5秒より頻繁にポーリングしないでください——レンダリングが速くなるわけではありません。

動きを制御できる prompt の書き方

動きのパラメータが一切ないため、prompt が唯一のハンドルです——そして hailuo-2.3 にとってそれで十分です。3つの経験則:

  • 見た目ではなく動きを記述する。モデルはすでにあなたの画像を見ています。"a beautiful woman in a red dress" は prompt を無駄にします。"she turns her head slowly to the left as the camera pushes in" なら有効に使えます。
  • カメラの動きは平易な言葉で指定する。"slow push-in"、"orbit right"、"handheld sway"、"static camera"——これらは(存在しない)camera_movement フィールドではなく、prompt テキストに書くべきです。
  • 迷ったら prompt_optimizer に任せる。"prompt_optimizer": true を設定すると、プラットフォームが生成前に短い prompt を拡張します——短い入力には良いデフォルトです。慎重に設計した表現に厳密に従わせたい場合はオフにしてください。

本番環境の注意点

ポーリングよりコールバックを優先する。タスク作成時にコールバックを付けると、hiapi が終状態の結果をあなたのエンドポイントに POST するため、オープンなループを維持する必要がありません:

{
  "model": "hailuo-2.3/image-to-video",
  "input": { "...": "..." },
  "callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}

"when": "final" は終状態でのみ一度だけ発火します。ポーリングはスクリプトや notebook に適していますが、コールバックがサーバーの正しい形です——動画レンダリングは十分に長く、ポーリングでブロックするワーカーは実質的なコストになります。

これらのエラーを明示的に処理する:

  • 401 かつ "code": "permission_denied"——キーに問題があるか、そのキーにこのモデルを使用する権限がありません。メッセージには request_id が含まれ、サポートチームに送れます。
  • 400 INVALID_REQUEST——スキーマ違反。メッセージは正確で、例えば duration: got number, want string や image_url: missing required field "image_url" です。そのまま記録してください。
  • タスク作成時の 402——残高不足。動画はタスクごとの課金が画像より高いため、画像タスクはまだ正常に動くキーが先に動画作成で失敗し始めることがあります。チャージするか、dashboard で使用量を確認してください。
  • タスクが "fail" になる——生成側の失敗です。data.error を確認してください。特に image-to-video でよくある原因:image_url を取得できない(プライベートバケット、期限切れの署名付き URL)。

リトライを考慮して冪等にする。プロセスが作成とダウンロードの間で死んだ場合、単純な再起動は2回目のレンダリングを作成(そして課金)してしまいます。create_task が返した直後に taskId を永続化し、再起動時は再作成せずポーリングを続けてください。

関連記事

よくある質問

hailuo-2.3 image-to-video はどのような長さをサポートしていますか? 2つ:"6" と "10" 秒で、文字列として渡します。それ以外の値——または同じ値を数値で書いた場合——は 400 INVALID_REQUEST を返します。

なぜ "duration": 6 は失敗し、"duration": "6" は成功するのですか? スキーマは duration を文字列の列挙として定義しています。API は明確に伝えます:duration: got number, want string。これはこのエンドポイントで最もよくある 400 です。

出力の解像度やアスペクト比を設定できますか? いいえ。エンドポイントは resolution や aspect_ratio フィールドを公開しておらず、いずれかを送信すると 400 になります——スキーマは未知のプロパティを無視せず拒否します。

カメラの動きや動きの強さを制御するには? prompt 経由です。camera_movement や motion_strength パラメータはありません——カメラと動きの指示を平易な言葉で書いてください("slow push-in"、"she walks toward the camera")。

複数の参照画像を渡せますか? いいえ——image_url は単一の文字列で、最初のフレームです。これは image_urls 配列を受け取る hiapi 上の他のモデルとは異なります。スキーマはモデルごとに定義されているため、必ずモデルページを確認してください。

最初のフレームはどの画像形式をサポートしていますか? 標準的な Web 形式(JPEG/PNG)を、公開アクセス可能な URL から提供します。プラットフォームがその URL を取得できない場合、タスクは作成後に失敗します——送信前にリンクが公開アクセス可能か検証してください。

これは hailuo-2.3/text-to-video とどう違いますか? text-to-video はあなたの prompt のみからシーンを発明します。image-to-video は最初のフレームを画像に固定し、そこからアニメーション化します。タスクのライフサイクルはまったく同じで、入力スキーマだけが異なります(ここでは image_url が必須で、text-to-video には画像フィールドがまったくありません)。

費用はいくらですか? 動画は出力秒数で課金され、料率は変動します——現在の数値は hailuo-2.3/image-to-video モデルページと料金ページをご確認ください。

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

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

APIドキュメントを読む