チュートリアル
hiapi API で minimax-h3-max を使ったマルチアングル画像→動画プロンプトの書き方
カメラアングルのパラメータは存在しません。以下のプロンプト記述法を使えば、1枚の写真からマルチショットのクリップを生成できます。
minimax-h3-max は1枚の写真を5~15秒の動画に変換できますが、そのエンドポイントには「カメラアングル」「マルチビュー」「ショット数」といったパラメータは一切ありません。パラメータリファレンスに記載されている対応入力フィールドは prompt、first_frame_image、last_frame_image、duration、resolution、aspect_ratio です。カメラの指示は prompt に記述してください。このフィールドは最大7,000文字まで受け付けます。
つまり、「マルチアングル」なクリップ——ワイドな確立ショットからクローズアップへ切り替わり、さらにトラッキングショットへ切り替わる——は、設定するパラメータではなく、書き出すプロンプトそのものです。このチュートリアルでは、リクエスト構造、1つの生成クリップ内で複数のカメラアングルを要求するプロンプトパターン、そしてそれを取り巻くプロダクション向けのワークフローを扱います。
このプロンプトで生成 → 10秒と768Pを選択してください。画像→動画を行う場合は、フレーム画像を追加し aspect_ratio を省略してください。
前提条件
hiapi コンソールから API キーを取得してください。以下の各呼び出しは Authorization: Bearer YOUR_API_KEY で共有非同期タスクエンドポイント POST https://api.hiapi.ai/v1/tasks に対して認証を行います。
最小例:1枚の写真から3つのカメラアングル
first_frame_image は被写体とシーンを固定し、モデルがそこから切り替えてまた戻ってくる具体的な内容を持てるようにします。プロンプトは各ショットを明確な番号付きカットとして記述します。このバイクのプロンプトはコード例であり、レンダリングサンプルは添付されていません。
夕暮れ時の濡れた都会の街路に駐車された赤いヴィンテージバイク、ネオンサインが路面に反射している。ショット 1 - ローアングルワイド:カメラは静止したワイドショットを保ち、バイク全体を捉える。雨が静かに降っている。ショット 2 - クローズアップにカット:カメラはクロームのヘッドライトと前輪にぐっと寄り、ゆっくりと右へトラッキングする。ショット 3 - オーバーヘッド俯瞰にカット:カメラは真上からバイクを真下に見下ろし、ゆっくりと回転する。テキストや字幕はなし。
このプロンプトで生成 → 公開アクセス可能なご自身のバイク画像を追加し、10秒と768Pを選択して、aspect_ratio を省略してください。
import os
import requests
import time
API_KEY = os.environ["HIAPI_API_KEY"]
BASE = "https://api.hiapi.ai/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
payload = {
"model": "minimax-h3-max",
"input": {
"prompt": (
"A red vintage motorcycle parked on a wet city street at dusk, neon signs reflecting on the pavement. "
"Shot 1 - low wide angle: the camera holds a static wide shot of the full motorcycle, rain lightly falling. "
"Cut to Shot 2 - close-up: the camera pushes in tight on the chrome headlight and front wheel, tracking slowly right. "
"Cut to Shot 3 - overhead top-down: the camera looks straight down at the motorcycle from above, slowly rotating. "
"No text or subtitles."
),
"first_frame_image": "https://your-cdn.example.com/motorcycle-source.jpg",
"duration": 10,
"resolution": "768P",
},
}
# Frame images and aspect_ratio are mutually exclusive.
def response_data(response):
response.raise_for_status()
body = response.json()
if not isinstance(body, dict) or body.get("code") != 200:
raise ValueError("Expected a JSON object with code=200")
data = body.get("data")
if not isinstance(data, dict):
raise ValueError("Expected data to be an object")
return data
# Submit once. An uncertain POST response is not a reason to submit again.
try:
resp = requests.post(
f"{BASE}/tasks", headers=HEADERS, json=payload, timeout=(10, 60)
)
created = response_data(resp)
task_id = created.get("taskId")
if not isinstance(task_id, str) or not task_id.strip():
raise ValueError("Missing data.taskId")
except (requests.RequestException, ValueError) as exc:
raise RuntimeError(
"Could not confirm task creation. Check task records before resubmitting."
) from exc
print("taskId:", task_id, flush=True)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
try:
resp = requests.get(
f"{BASE}/tasks/{task_id}", headers=HEADERS, timeout=(10, 60)
)
task = response_data(resp)
except (requests.RequestException, ValueError) as exc:
raise RuntimeError(
f"Query failed; retain taskId={task_id} and resume GET for this ID."
) from exc
state = task.get("status")
if state == "fail":
raise RuntimeError(f"Task {task_id} failed: {task.get('error')}")
if state == "success":
outputs = task.get("output")
if not isinstance(outputs, list):
raise RuntimeError(f"Task {task_id}: missing output array")
video = next(
(item for item in outputs
if isinstance(item, dict) and item.get("type") == "video"
and isinstance(item.get("url"), str) and item["url"]),
None,
)
if video is None:
raise RuntimeError(f"Task {task_id}: no video URL in output")
print(video["url"])
print("expireAt (Unix seconds):", video.get("expireAt"))
break
if state not in {"queued", "handling", "archiving"}:
raise RuntimeError(f"Task {task_id}: unexpected status {state!r}")
time.sleep(min(3, max(0, deadline - time.monotonic())))
else:
raise TimeoutError(f"Polling timed out; continue GET with taskId={task_id}")
first_frame_image を実際の公開アクセス可能な HTTPS 画像 URL に置き換えるか、完全に削除してテキストだけで同じマルチアングルシーケンスを生成してください——minimax-h3-max は同じ prompt フィールドでテキスト→動画と画像→動画の両方を処理します。
プロンプトの書き方:番号付きショットパターン
3つの選択が、目指すショットシーケンスを明確にします:
- シーンを確立する一文、その後に番号付きショット。まず被写体とシーンを一度だけ記述し、次に各カメラアングルをそれぞれラベル付きのビートとして列挙します:
ショット 1 - [構図]:[アクション]。ショット 2 - [構図]:[アクション]にカット。「ショット N にカット」はカメラアングルの変更を明確に要求します。 - 標準的な映画撮影用語を使う。
ローアングルワイドショット、オーバーヘッド俯瞰ショット、クローズアップ、スロープッシュイン、横方向トラッキングショット、ハンドヘルド——これらの語が求める構図と動きを指定します。「別のかっこいいアングル」のような曖昧な表現は一貫性のない結果を生みます。 - 尺に合わせてショット数を計画する。
durationは5~15秒の整数です。2~3ショットが現実的です。5つの異なるアングルを5秒のクリップに詰め込むと、各ショットは1秒未満になり、カットではなくグリッチのように見えることがよくあります。
first_frame_image と last_frame_image はどちらも任意で、互いに独立しています——片方だけ、両方、あるいはどちらも設定しないこともできます。いずれかを指定する場合は aspect_ratio をスキップしてください。これらのフィールドは排他的で、フレーム画像が出力のアスペクト比を決定します。また、アングル間で厳密な3D的・幾何学的な一貫性は保証されないことに注意してください——これは生成型動画モデルであり、フォトグラメトリのパイプラインではないため、最初のフレームで固定しても、ショット間で被写体の細部がわずかにドリフトすることを想定してください。
プロダクション向けにする
- スクリプト規模を超えたら、ポーリングではなくコールバックを優先する。リクエストボディに
"callback": {"url": "https://your-domain.com/hiapi/callback", "when": "final"}を追加すると、タスクが終端状態に達したときに hiapi が POST で通知します。ループ内でGET /v1/tasks/{taskId}をポーリングする必要はありません。 taskIdで重複排除する。ポーリング応答とコールバックはどちらも同じtaskIdをキーにします——同じ ID の重複した終端通知は、複数の独立したタスクではなく冪等なものとして扱ってください。- 出力をすぐにダウンロードする。成功したタスクは一時ストレージ用の
data.output[].urlを返します。typeがvideoの出力項目を選択し、そのexpireAtUnix タイムスタンプ(秒)を確認してください。終端状態を処理する同じハンドラ内で、自分のストレージに再アップロードしてください。 - 2種類の失敗形態を処理する。不正なリクエストボディ(未対応フィールド、範囲外の
duration、形式不正な画像 URL)は送信時に即座に失敗し400 INVALID_REQUESTを返します。認証の問題は401を返し、error.code: "permission_denied"が付きます。生成中に失敗したタスクは、ポーリング/コールバック応答で"status": "fail"を報告します——outputを信頼する前にstatusを確認してください。
関連記事
- minimax-h3-max モデルページ——リアルタイムの価格、パラメータ、そしてブラウザでプロンプトを試してからコードに組み込めるプレイグラウンド。
- minimax-h3-max API ドキュメント——完全なパラメータリファレンスとコールバックの詳細。
- H3 と H3 Max の価格——解像度別の料率とショート動画の予算。
- hiapi の価格——各モデルの現在の秒単価。
よくある質問
minimax-h3-max には専用のマルチアングルやマルチカメラのパラメータがありますか?
いいえ。ドキュメントの入力フィールドは prompt、first_frame_image、last_frame_image、duration、resolution、aspect_ratio です。カメラアングルのフィールドを追加するのではなく、prompt 内で複数のショットを記述してください。
aspect_ratio を first_frame_image や last_frame_image と一緒に設定できますか?
いいえ。aspect_ratio はどちらのフレーム画像フィールドとも排他的です。指定した画像が出力比率を決定します。いずれかのフレーム画像を渡す場合は、aspect_ratio を省略してください。
マルチアングルのクリップはどれくらいの長さにできますか?
duration は5~15の整数秒を受け付けます。2~3つの異なるカメラアングルならこの範囲に余裕を持って収まります。それを超えると、各ショットが数分の一秒に圧縮されることがよくあります。
被写体はアングル間で完全に一貫しますか?
保証されません。minimax-h3-max は生成型動画モデルであるため、first_frame_image が冒頭フレームを固定しても、細部(正確なテクスチャ、微妙なプロポーション)がショット間でドリフトする可能性があります。ピクセル単位で正確なマルチビュー再構成ではなく、創作上の強い一貫性として捉えてください。
元画像なしで、テキストだけでマルチアングルのクリップを生成できますか?
はい——first_frame_image と last_frame_image を省略し、prompt でシーンとショットを記述してください。テキストのみの生成はデフォルトの横向きキャンバスを使用します。縦向きの構図にしたい場合は、aspect_ratio を設定せずに縦向きのフレーム画像を提供するか、エディタで保存済み動画をクロップ/パディングしてください。
認証失敗はどのように表示されますか?
HTTP 401 で、レスポンスボディは {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}} のようになります。Authorization: Bearer ヘッダーと、キーがコンソールから取り消されていないかを確認してください。
バイクのショットシーケンスをコピーしてこのプロンプトで生成 → 10秒と768Pを選択してください。冒頭の構図を導くためにフレーム画像を追加してください。
関連記事
すべての記事を見る →-
チュートリアル
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 チュートリアル
リクエスト優先の実践デモ:プロンプトから動画クリップへの呼び出しを構築し、リクエストを送信し、完了状態をポーリングし、結果をダウンロードする