チュートリアル
hiapi API で happyhorse-1.1/image-to-video を呼び出す方法:curl と Python ガイド
このエンドポイントの役割と利用すべき場面
happyhorse-1.1/image-to-video は、1 枚の静止画像を短い動画に変換します。このエンドポイントに最初のフレーム画像を送信すると、モデルはそのフレームから前方に向かってアニメーションを生成します。実用的な意味は連続性にあります。開始画像に含まれる被写体、構図、外観が、生成されるクリップへと引き継がれます。これがここで言うアイデンティティ保持です。モデルはテキストプロンプトだけから新しいシーンをゼロから作り出すのではなく、すでに画像で作り上げたシーンを継続するのです。
したがって、即興性よりも視覚的アイデンティティが重要な場合に、このエンドポイントは非常に適しています:
- 参照用の静止フレーム(人物写真、商品写真、キャラクター設定画など)がすでにあり、その静止フレームに忠実な動きを生成したい。
- パイプライン内で短編を制作しており、そこでの他のすべての素材がまず画像として設計されている。
- ストーリーボードのフレームから動画コンテやモーションプレビューを作成する必要がある。
モデルにシーンをゼロから自由に再解釈させたい場合や、出力を固定する静止フレームがない場合には、あまり適していません。そうした場合、画像優先のワークフローでは通常、まずアンカーとなる画像を生成し、その結果をこのエンドポイントに渡します。
呼び出し自体は非同期です。ジョブを送信し、動画の準備ができるまでポーリングします。本ガイドの残りの部分では、このライフサイクルを最初から最後まで説明します。
リクエストを送信する前に
最初の呼び出しの前に 2 つのことを準備する必要があります。
API キー
すべての呼び出しは hiapi プラットフォーム経由で行われ、API キーはベアラー認証情報として付加されます。キーはソースコード管理ではなく環境変数に保存してください。そうすれば同じコードをローカル開発でも CI でもそのまま使えます:
export HIAPI_API_KEY="your_key_here"
Python では、実行時に os.environ["HIAPI_API_KEY"] で読み取ります。生のヘッダー値をログに記録しないでください。
参照可能な最初のフレーム画像
このエンドポイントには開始画像が必要です。事前にどのように渡すかを決めてください。プラットフォームが取得できる URL としてか、アップロード済み・base64 エンコード済みの素材としてかは、あなたのアカウントとエンドポイントドキュメントがサポートする方法によります。重要なのは、その参照が送信時に安定してアクセス可能であることです。ジョブがキューに並ぶ可能性があるなら、5 分後に期限切れになる署名付き URL は悪い選択です。
呼び出し前に、想定する出力のアスペクト比と長さを把握しておくことも役立ちます。最初のフレームが通常それらを制約するからです。この決定を事前に済ませておけば、後で再送信する手間を避けられます。
キーをエクスポートし、画像参照が確定したら、送信できます。
最初のフレーム入力の構築
最初のフレームは、モデルがその後に生成するすべてのもののアンカーです。実際には、これをアイデンティティの契約と見なすべきです。その画像にはっきりと見えるもの(顔、服装、ロゴ、配色、カメラアングル)はすべて、モデルが従わなければならない内容です。静止フレーム内の細部がぼやけていたり隠れていたりすれば、出力もぼやけます。
具体的なモデルパラメータにかかわらず、次の準備原則が当てはまります:
- 鮮明で照明の良いフレームを選ぶ。 圧縮アーティファクトや強いノイズは、モデルが保持できる内容を減らします。シャープで均一に照らされた画像は、ドラマチックでもぼやけた画像よりも優れたアンカーです。
- 動きを開始したい位置に被写体を置く。 静止フレーム内でトリミングして構図を決めるほうが、モデルが再フレーミングすることを期待するより効率的です。
- 想定する出力のアスペクト比を保つ。 最終動画が横向きなら、横向きのアンカー画像を用意してください。後からパディングしても失われた構図は戻りません。
- 矛盾する手がかりを避ける。 ある意味に読めるのに、画面外の動作を暗に示す静止フレームは、モデルに不安定な出発点を与えます。
エンドポイントドキュメントにないモデル固有のパラメータを想定しないでください。最も安全な方法は、意図を画像自体に持たせ、リクエストフィールドには明示的にカバーされている内容だけを扱わせることです。
curl で動作するリクエストを送る
ジョブの送信は 1 回の POST で済みます。構造は次のとおりです。認証済みリクエストをエンドポイントに送信し、JSON リクエストボディにモデル識別子と画像入力を含めます。
curl -sS -X POST "https://api.hiapi.ai/v1/video/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "happyhorse-1.1/image-to-video",
"input": {
"image": "https://your-bucket.example.com/first-frame.jpg"
}
}'
手順ごとの説明:
- エンドポイント。 POST の送信先は hiapi API 上の動画生成ルートです。複数の環境向けにスクリプトを書く場合は、これを変数に入れてください。
- 認証ヘッダー。
Authorization: Bearer $HIAPI_API_KEY。シェルが先ほどエクスポートした環境変数を展開します。 - コンテンツタイプ。 リクエストボディが JSON なので
application/jsonです。 - リクエストボディ。
modelでhappyhorse-1.1/image-to-videoを選択し、input.imageが最初のフレーム参照です。あなたのアカウントで受け入れられる正確な画像フィールド名と構造については、エンドポイントリファレンスを参照してください。
成功時のレスポンスは動画そのものではなく、ジョブハンドルです。識別子とステータスフィールドが返り、通常は queued や processing のような値になります。この ID を控えてください。以降のステップでポーリングに使います。まずコマンドを 1 回実行してレスポンスを出力し、スクリプトを書き始める前にその構造を確認しましょう。
Python で同じリクエストを送る
Python 版は単純な移植であり、新しい統合ではありません。同じルート、同じヘッダー、同じ JSON リクエストボディです。
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
URL = "https://api.hiapi.ai/v1/video/generations"
payload = {
"model": "happyhorse-1.1/image-to-video",
"input": {
"image": "https://your-bucket.example.com/first-frame.jpg"
},
}
resp = requests.post(
URL,
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
resp.raise_for_status()
job = resp.json()
print(job)
対応関係の説明:
json=payloadを使うrequestsは、curl の-d文字列と同様に辞書をシリアライズします。json=を使う場合はContent-Typeを手動で設定しないでください。ライブラリが処理します。上記の明示的なヘッダーは無害ですが冗長です。raise_for_status()は、存在しないジョブをポーリングし始める前に、HTTP レイヤーの失敗を早い段階で例外に変換します。timeoutは送信呼び出しに対するクライアント側の保護にすぎません。生成はサーバー側で実行され、これに制約されません。
payload は変数に保存して再利用してください。後でモデルや画像を変更するときは、2 つの並行実装ではなく 1 つの辞書だけを編集すればよいようにします。
非同期ジョブの処理とポーリング
画像から動画への生成は、リクエスト/レスポンスのサイクルよりも時間がかかります。そのため API は即座にジョブ参照を返し、後で問い合わせることを想定しています。ライフサイクルは、送信、ID 受け取り、ステータスポーリング、結果取得です。
送信レスポンスからジョブ ID を抽出します。フィールド名はこのエンドポイントでドキュメント化されたレスポンススキーマによります。したがって、一度読んで、値ではなくキー参照をハードコードしてください:
job_id = job["id"] # check the endpoint docs for the exact field
次に間隔を空けてポーリングします:
import time
poll_url = f"https://api.hiapi.ai/v1/video/generations/{job_id}"
while True:
status = requests.get(
poll_url,
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
).json()
if status["status"] == "succeeded":
break
if status["status"] == "failed":
raise RuntimeError(status)
time.sleep(5)
ポーリングを適切に保つためのルール:
- タイトなループではなく固定間隔でポーリングする。 この規模のジョブでは、数秒おきの確認で十分です。エンドポイントを連打しても負荷が増すだけで、結果が早く出るわけではありません。
- 総待機時間に上限を設ける。 上限のない
while Trueは遅かれ早かれハングします。経過時間を追跡し、妥当な予算を超えたら大きな声で失敗させてください。 - 両方の終端状態を処理する。 成功も失敗も答えです。未知のステータス文字列は非終端として扱いますが、パターンの変化に気づけるようログに記録してください。
- 1 つのジョブを複数の並列ワーカーからポーリングしない。 ジョブごとに 1 つのポーラーにするか、キューで調整してください。
ステータスが終端になったら、結果のダウンロードに進みます。
出力のダウンロードと保存
完了した動画は、完了済みジョブのレスポンス内に素材として公開されます。通常は URL で、期限付きの場合もあります。ポーリング成功後の最初のステップは、その参照を取得し、バイト列を自分が管理するストレージにコピーすることです。
video_url = status["output"]["video_url"] # inspect the real response shape
with requests.get(video_url, stream=True, timeout=120) as r:
r.raise_for_status()
with open(f"out/{job_id}.mp4", "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 20):
f.write(chunk)
あらゆるパイプラインに当てはまる保存の指針:
- 永続的な成果物はリンクではなくコピーする。 署名付きや期限付きの URL は転送手段であり、ストレージではありません。ファイルを永続化し、データベースにジョブ ID とともに自分のオブジェクトキーを保存してください。
- 大きなファイルはストリーミングで処理する。
iter_contentはメモリ使用量を安定させます。動画全体を変数に読み込むと、メモリ上限が素材サイズに縛られます。 - 来歴を記録する。
job_id、入力画像参照、モデル識別子を素材と一緒に保存してください。クリップを再現する必要が生じたとき、その記録がレシピになります。 - 書き込み前に HTTP ステータスを確認する。 エラーレスポンスによる部分書き込みは、有効なファイルに見えるため、きれいな失敗より悪いです。
ファイルがディスクまたはオブジェクトストレージに置かれれば、パイプラインは閉じ、次のフレームの処理に進めます。
注意すべきエラーと落とし穴
このエンドポイントでの失敗のほとんどは予測可能です。簡単なチェックリストを以下に示します:
- 最初のフレーム入力の形式が不正、または到達不能。 送信が拒否される最も一般的な原因です。画像 URL が公網から解決できるか、形式がエンドポイントで受け入れられるか、payload で画像フィールドが正しくネストされているかを確認してください。curl 呼び出しで再現して、認証の問題か payload の問題かを切り分けます。
- ジョブが存在する前にポーリングする。 誤ったフィールドから ID を読み取ったり、送信レスポンスと一致しないルートをポーリングしたりすると、ジョブ失敗に見える 404 が発生します。送信レスポンスを一度出力し、それに基づいてキー参照を固定してください。
- 無制限の待機。 タイムアウトがないということは、スタックしたジョブがワーカーを無期限にハングさせることを意味します。予算を設定し、失敗させてアラートを出してください。
- 素材リンクの喪失。 生成は成功したものの、URL を一度消費した後にコピーしなかった場合です。取得時にバイト列を保存し、自分のキーを保持してください。返されたリンクを長期ストレージとして依存しないでください。
- 認証情報の漏洩。 キーを notebook に貼り付けて誤ってコミットするのは繰り返し起こる問題です。環境から読み込み、疑わしければローテーションしてください。
- エンドポイントでドキュメント化されていないパラメータを想定する。 記載されていないパラメータが必要なら、それは存在しません。意図は最初のフレーム画像とドキュメント化されたフィールドだけで表現してください。
これらを適切に処理すれば、非同期フローはありふれたものになります。それが本番パイプラインで望ましいことです。エンドポイント固有のフィールド名と許容値については、構築中にエンドポイントリファレンスを開いたままにしてください。
関連記事
すべての記事を見る →-
チュートリアル
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 チュートリアル
リクエスト優先の実践デモ:プロンプトから動画クリップへの呼び出しを構築し、リクエストを送信し、完了状態をポーリングし、結果をダウンロードする