HiAPI
ブログ

チュートリアル

HappyHorse 1.1 参照画像からの動画生成 API:すぐに実行できる curl + Python チュートリアル

Jun 26, 2026
HappyHorse 1.1 参照画像からの動画生成 API:すぐに実行できる curl + Python チュートリアル

HappyHorse 1.1 R2V は、最大 9 枚の参照画像と 1 つのテキストプロンプトを短い動画に変換し、複数のショット間で被写体、服装、シーンのスタイルを一貫させることができます。HiAPI では、このモデルは統一された非同期タスクエンドポイントで提供され、対応するモデル ID は happyhorse-1.1/reference-to-video です。このチュートリアルでは、まず動作する最小限のリクエストを示し、次にコールバック付きの本番向けバージョンを示します。

目標と前提条件

以下の操作を完了します:

  1. 1〜9 枚の参照画像を API がアクセス可能な HTTPS URL にアップロード(またはホスティング)します。
  2. https://api.hiapi.ai/v1/tasks に、これらの URL を参照するタスクを POST します。
  3. タスクが success 状態になったら、data.output[0].url から最終的な MP4 のアドレスを読み取ります。

前提条件:

  • HiAPI アカウント、および sk- で始まる API Key。HiAPI コンソール から取得でき、リクエストヘッダーのルールについては 認証 ドキュメントを参照してください。キーは Authorization: Bearer sk-... の形式で渡す必要があり、クライアントコードに絶対に含めてはいけません。
  • 画像ホスティングの要件:各参照画像は JPEG、PNG、または WEBP 形式で、最短辺が 400px 以上、20MB 以下である必要があります。パブリック CDN URL は使用可能です。署名付き S3 URL も、タスク実行エンジンがアクセスできれば使用できます。

最小限の動作するリクエスト(curl)

これはスキーマが受け入れる最小限のリクエストボディです。デフォルトの 1080p / 16:9 / 5 秒出力を使用するため、prompt と reference_image の 2 つのフィールドを設定するだけで済みます。

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-1.1/reference-to-video",
    "input": {
      "prompt": "[Image 1] のキャラクターが [Image 2] のスタイルのシーンを歩く、映画風のショット",
      "reference_image": [
        "https://static.hiapi.ai/example/ref-1.jpg",
        "https://static.hiapi.ai/example/ref-2.jpg"
      ]
    }
  }'

レスポンスはタスクのエンベロープです。実際に必要な唯一のフィールドは data.taskId です:

{
  "code": 200,
  "data": { "taskId": "task_xxx", "status": "queued" }
}

終了状態になるまでポーリングします:

curl https://api.hiapi.ai/v1/tasks/task_xxx \
  -H "Authorization: Bearer sk-YOUR_KEY"

data.status が success になると、動画 URL は data.output[0].url にあります。この URL には expireAt タイムスタンプがあるため、すぐにファイルをダウンロードするか、永続ストレージに転送してください——あなたのウェブサイトでこのアドレスを直接ホットリンクしないでください。

パラメータ

R2V エンドポイントは入力を厳密に検証します。未知のフィールドは 400 INVALID_REQUEST を返します。完全なスキーマ(POST /v1/tasks に対してライブ検証済み):

フィールド 型 必須 取り得る値 デフォルト値
model string はい happyhorse-1.1/reference-to-video(固定値) -
input.prompt string はい [Image 1]、[Image 2]…… で参照画像を参照し、順序は reference_image と一致させる -
input.reference_image string[] はい 1〜9 個の HTTPS URL、JPEG/PNG/WEBP 形式、最短辺 ≥ 400px、各画像 ≤ 20MB -
input.resolution enum いいえ 720p、1080p 1080p
input.aspect_ratio enum いいえ 16:9、9:16、3:4、4:3、4:5、5:4、1:1、9:21、21:9 16:9
input.duration integer いいえ 3〜15(秒) 5
callback.url string いいえ タスクの終了状態イベントを受信する HTTPS URL -
callback.when enum いいえ final(現在唯一の値) final

直感的ではない検証ルールがいくつかあり、トラブルになる前に知っておく価値があります:

  • 参照画像 URL が 1 枚だけでも、reference_image は配列として渡す必要があります。文字列を直接渡すと reference_image: got string, want array が返ります。
  • duration は 3 から 15(含む)までの整数である必要があります。999 と 1 はどちらも明確な境界エラーメッセージを返します。
  • トップレベルには seed、negative_prompt、fps、cfg_scale、steps は存在しません。API は未知のプロパティを拒否します。

解像度と長さの組み合わせごとの完全な価格については、HiAPI 料金ページ を参照してください——料金は resolution と duration の 2 つのパラメータの両方によって変動します。

Python:エンドツーエンド + ポーリング

以下のコードブロックは自己完結型のジェネレーターで、タスクを送信し、終了状態までポーリングし、動画をダウンロードします。依存関係をゼロ(requests のみ使用)に意図的に抑えているため、どのサービスにもコピーして使えます。より完全なリクエストライフサイクルの説明は クイックスタート を参照してください。

import os
import time
import requests

API = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}


def submit_r2v(prompt: str, reference_images: list[str], duration: int = 5,
               resolution: str = "1080p", aspect_ratio: str = "16:9") -> str:
    if not 1 <= len(reference_images) <= 9:
        raise ValueError("reference_image must contain 1-9 URLs")
    payload = {
        "model": "happyhorse-1.1/reference-to-video",
        "input": {
            "prompt": prompt,
            "reference_image": reference_images,
            "resolution": resolution,
            "aspect_ratio": aspect_ratio,
            "duration": duration,
        },
    }
    r = requests.post(API, json=payload, headers=HEADERS, timeout=60)
    r.raise_for_status()
    data = r.json()
    if data.get("code") != 200:
        raise RuntimeError(f"create failed: {data}")
    return data["data"]["taskId"]


def wait_for_video(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> str:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30)
        r.raise_for_status()
        task = r.json()["data"]
        status = task["status"]
        if status == "success":
            return task["output"][0]["url"]
        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} did not finish in {timeout_s}s")


def download(url: str, path: str) -> None:
    with requests.get(url, stream=True, timeout=300) as r:
        r.raise_for_status()
        with open(path, "wb") as f:
            for chunk in r.iter_content(1 << 16):
                f.write(chunk)


if __name__ == "__main__":
    task_id = submit_r2v(
        prompt="[Image 1] の被写体デザインを保ち、[Image 2] の雰囲気の中で歩く",
        reference_images=[
            "https://static.hiapi.ai/example/char.jpg",
            "https://static.hiapi.ai/example/mood.jpg",
        ],
        duration=5,
        resolution="720p",
        aspect_ratio="9:16",
    )
    print("submitted", task_id)
    video_url = wait_for_video(task_id)
    print("ready", video_url)
    download(video_url, "out.mp4")

このコードは意図的に以下のことを行っています:

  • キーを HIAPI_API_KEY 環境変数から読み取るため、git やコンテナログに決して残りません。
  • r.raise_for_status() を使用して、JSON を解析する前に転送エラーを捕捉します。
  • success と fail のみを終了状態とみなします——それ以外のすべての状態(queued、processing など)はループを継続させます。
  • 出力 URL をすぐにダウンロードします。出力 URL は署名付きアドレスであり期限切れになるため、後でファイルが必要な場合は 永続ストレージに転送するか、自分のストレージバケットにコピーしてください。

本番環境:ポーリングから webhook への切り替え

5 秒ごとのポーリングは、ノート PC や低トラフィックのワーカーでは問題ありません。実際のサービスでは、タスク作成時にコールバックを登録し、HiAPI が終了状態イベントをあなたのエンドポイントにプッシュするようにしてください——そうすればワーカーはアイドル状態を保て、空の GET リクエストに料金を払う必要もなくなります。完全なリクエストスキーマは タスクの作成、フォールバックポーリングは タスク詳細の取得 を参照してください。

payload = {
    "model": "happyhorse-1.1/reference-to-video",
    "input": {
        "prompt": "[Image 1] のキャラクターが [Image 2] の街路を歩く",
        "reference_image": [
            "https://cdn.example.com/char.jpg",
            "https://cdn.example.com/street.jpg",
        ],
        "resolution": "1080p",
        "aspect_ratio": "16:9",
        "duration": 8,
    },
    "callback": {
        "url": "https://your-domain.com/hiapi/callback",
        "when": "final",
    },
}

受信エンドポイントには 2 つのことを組み込む必要があります:

  1. taskId による冪等処理。 success と fail はどちらも終了状態であり、HiAPI のリトライ(または独自のリトライ層による重複)は同じ taskId を再配信します。副作用(S3 コピー、Slack メッセージ、課金イベント)をトリガーする前に必ず重複排除してください。
  2. フォールバックの照合ポーリング。 エンドポイントがダウンしていると、コールバックは失われます。最悪の生成時間を超えても processing 状態にあるすべてのタスクに対して GET /v1/tasks/<id> を呼び出す、軽量な照合ジョブを用意してください。

実際に遭遇するエラー

以下は明示的に処理する価値があります。それ以外は一時的な 5xx であり、SDK または HTTP クライアントがバックオフ付きでリトライすべきものです。

  • 401 permission_denied——Authorization ヘッダーの欠落、形式の誤り、またはキーが失効しています。ヘッダーを修正するのではなく、コンソールからキーを再発行してください。
  • 400 INVALID_REQUEST とフィールドパス——エラーメッセージはどこで失敗したかを正確に示します。例えば reference_image: maxItems: got 10, want 9 や aspect_ratio: value must be one of ... などです。ワーカーが送信する前にローカルで早期に失敗できるよう、入力を検証してください。
  • task failed(終了状態)——ポーリング/コールバックが status: "fail" を返し、error.code と error.message が付属します。一般的な原因:ワーカーが取得できない参照画像 URL、NSFW 審査への抵触、画像の最短辺が 400px のしきい値を下回っているなど。

よくある質問

9 枚を超える画像を参照できますか? いいえ。スキーマは reference_image を最大 9 枚に制限しています。より多くのバリエーションが必要な場合は、プラットフォーム外でより高密度な参照画像(グリッド画像や絵コンテ画像)を合成し、単一の入力として使用してください。

プロンプトで [Image N] マーカーは必須ですか? これらのマーカーは特定の参照画像を指す方法です。プロンプトで画像を一度も指定しなくても合法ですが、モデルはすべての参照画像を自由に混ぜ合わせます——マルチショットの一貫性が必要なシーンでは、通常望ましい結果ではありません。

なぜ 503 nsfw_moderation_unavailable が返るのですか? これは審査サービスに起因するプラットフォームの一時的なエラーであり、あなたのリクエストとは関係ありません。短いバックオフの後に再試行してください。

720p と 1080p のどちらを使うべきですか? 1080p はデフォルト値で画質が良いですが、料金が高く、レンダリングも遅くなります。プレーヤー側でダウンサンプリングされる縦型ソーシャルメディア用のクリップには、720p と aspect_ratio: 9:16 の組み合わせが通常より適切なトレードオフです。

出力を再現可能にするために seed を渡せますか? 現在はできません。API は seed を未知のプロパティとして拒否します。再現性が必要な場合は、prompt、reference_image、aspect_ratio、resolution、duration を正確に固定し、実行間の多少の差異を受け入れてください。

出力 URL はどこに保存され、どのくらい有効ですか? 短い TTL を持つ署名付き URL であり、レスポンスには expireAt が含まれます。タスク成功後すぐにダウンロードするか、永続ストレージに転送してください。

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

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

APIドキュメントを読む