チュートリアル
HappyHorse 1.1 参照画像からの動画生成 API:すぐに実行できる curl + Python チュートリアル
HappyHorse 1.1 R2V は、最大 9 枚の参照画像と 1 つのテキストプロンプトを短い動画に変換し、複数のショット間で被写体、服装、シーンのスタイルを一貫させることができます。HiAPI では、このモデルは統一された非同期タスクエンドポイントで提供され、対応するモデル ID は happyhorse-1.1/reference-to-video です。このチュートリアルでは、まず動作する最小限のリクエストを示し、次にコールバック付きの本番向けバージョンを示します。
目標と前提条件
以下の操作を完了します:
- 1〜9 枚の参照画像を API がアクセス可能な HTTPS URL にアップロード(またはホスティング)します。
https://api.hiapi.ai/v1/tasksに、これらの URL を参照するタスクを POST します。- タスクが
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 つのことを組み込む必要があります:
taskIdによる冪等処理。successとfailはどちらも終了状態であり、HiAPI のリトライ(または独自のリトライ層による重複)は同じtaskIdを再配信します。副作用(S3 コピー、Slack メッセージ、課金イベント)をトリガーする前に必ず重複排除してください。- フォールバックの照合ポーリング。 エンドポイントがダウンしていると、コールバックは失われます。最悪の生成時間を超えても
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 が含まれます。タスク成功後すぐにダウンロードするか、永続ストレージに転送してください。
関連記事
すべての記事を見る →-
チュートリアル
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 チュートリアル
リクエスト優先の実践デモ:プロンプトから動画クリップへの呼び出しを構築し、リクエストを送信し、完了状態をポーリングし、結果をダウンロードする