HiAPI
ブログ

チュートリアル

HiAPI API で kling-4.0/text-to-video を使う方法:curl、Python、そして実行可能なリクエスト例

開発者向け実践ガイド:シネマティックなプロンプト、同期オーディオ、非同期ポーリング、出力のダウンロード

Nov 3, 2026
深炭底色上一条宽大的琥珀色光带斜扫而过,下方配一条细窄的暗棕平行条带,整体用于文章封面。

kling-4.0/text-to-video の機能と適用シーン

kling-4.0/text-to-video は HiAPI の統合 API を通じて提供される生成型動画モデルです。テキストプロンプトを渡すと、動画クリップが返されます。動き、カメラワーク、シーン構成はすべてあなたの記述によって決まります。これはテキストから動画へのエンドポイントであり、アニメーション化する元画像は存在しないため、モデルはフレーミングと被写体の見た目について完全な裁量を持ちます。

適用シーン:

  • スクリプトやプロンプトテンプレートから短いシネマティックなクリップを生成する必要がある場合——Bロール、予告編、コンセプトボード、ソーシャルメディア動画など。
  • 同期オーディオを動画と一緒に生成したい場合。後から音楽を付ける必要がある無音ファイルを受け取りたくない場合に。
  • 動画生成が多数のステップ(脚本作成、素材準備、公開)の一つにすぎないパイプラインを構築している場合。そのため Web インターフェースではなく HTTP API が必要です。

ただし、特定の実在する被写体をフレーム単位で正確に制御する必要がある場合(画像から動画への変換や編集モデルの方が適しています)、あるいはユーザーリクエスト内で同期的に応答を得る必要がある場合、このモデルは適していません。動画生成には時間がかかるため、このエンドポイントは設計上非同期です。

すべてのリクエストが HiAPI を経由するため、プラットフォーム上のどのモデルを使用しても、認証情報、リクエスト/レスポンス形式、タスクのライフサイクルは同じです。この一貫性こそが、これを基盤に構築する実際の理由です。将来モデルを追加または置き換えても、認証やポーリング層を書き直す必要はありません。

HiAPI の前提条件と認証

最初のリクエストを送信する前に、以下が揃っていることを確認してください:

  • HiAPI アカウントとプロジェクト API キー。これは機密情報として扱ってください。コードリポジトリにコミットしたり、クライアントコードに含めたりしないでください。
  • 任意の HTTP クライアント。以下の例では curl と Python 3 の requests を使用します。
  • カタログに記載されている通り正確なモデル識別子:kling-4.0/text-to-video。モデル名の誤記は初回呼び出しが失敗する最も一般的な原因です。

認証情報は各リクエスト(ポーリングリクエストを含む)で HTTP ヘッダーとして送信されます。HiAPI の一般的なパターンはベアラートークンです:

export HIAPI_API_KEY="your-api-key-here"

そしてリクエスト内で:

Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json

ベース URL とキーはハードコードせず、環境変数やシークレットマネージャーに保存してください。ローカル開発では、.env ファイルと Python の os.environ 参照で十分です。デプロイ済みのサービスでは、実行時にシークレットを注入してください。

早い段階で身につけるべき設定の習慣:まず小さな「私は誰か」的な呼び出し——任意の軽量な認証リクエスト——を構築し、動画タスクをデバッグする前にキーとベース URL が正しいことを確認します。認証をモデルロジックから分離しておくと、後で時間を節約できます。

実行可能な curl リクエスト

最小限の呼び出しはタスクを作成し、タスク識別子を返します。構造は次のとおりです:

curl -X POST "$HIAPI_BASE_URL/video/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-4.0/text-to-video",
    "prompt": "夜の雨に濡れた東京の路地をゆっくりと空撮で押し進む、ネオンサインが水たまりに反射し、通気口から蒸気が立ち上る、浅い被写界深度、シネマティックなカラーグレーディング",
    "generate_audio": true
  }'

リクエストボディをフィールドごとに解説します:

  • model — モデル識別子。必須。
  • prompt — あなたのシーン記述。品質の大部分はここにあります。プロンプトのセクションを参照してください。
  • generate_audio — 動画とともに同期オーディオを生成するよう要求します。映像トラックのみが必要な場合は省略するか false に設定してください。

レスポンスは完成した動画ではなく、タスクオブジェクトです。ステータスフィールドと、ポーリングに使用する id が含まれることを想定してください。たとえばステータスが queued または processing で、タスク id が付属します。この id はすぐに保存してください。プロセスが終了した場合、この id が進行中の作業の唯一の手がかりになります。

実用的なヒントを2つ。第一に、プロンプトが長くなったら JSON をファイルに保存し、-d @payload.json を使用してください。複数行のプロンプトのシェルクォート処理はよくあるエラーの原因です。第二に、レスポンスボディと HTTP ステータスコードを別々に取得してください(curl -s -w "\n%{http_code}")。拒否されたリクエストとネットワーク障害を区別するためです。

リクエストを Python に変換する

同じリクエストを Python で書くと次のようになり、実際のスクリプトにそのまま組み込める構造になっています:

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

def create_video_job(prompt: str, generate_audio: bool = True) -> dict:
    payload = {
        "model": "kling-4.0/text-to-video",
        "prompt": prompt,
        "generate_audio": generate_audio,
    }
    resp = requests.post(
        f"{BASE_URL}/video/generations",
        headers=HEADERS,
        json=payload,
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()

if __name__ == "__main__":
    job = create_video_job(
        "夜の雨に濡れた東京の路地をゆっくりと空撮で押し進む、"
        "ネオンサインが水たまりに反射し、通気口から蒸気が立ち上る、"
        "浅い被写界深度、シネマティックなカラーグレーディング"
    )
    print(job)

このように書く理由:

  • requests.post(..., json=payload) はシリアライズとコンテンツタイプをまとめて処理するため、手動の json.dumps が不要になります。
  • raise_for_status() は 4xx/5xx をキャッチ可能な例外に変換します。エラーレスポンスボディをタスクとして黙ってパースしてしまうことがありません。
  • timeout は必須です。これがないと、スタックした接続がワーカーを無期限にブロックします。
  • 設定は環境から読み込まれるモジュールレベルの定数にあるため、この関数はテスト可能で再利用可能です。

この関数はタスクを作成するだけです。タスクハンドルを即座に返します。これはまさに Web ハンドラーやキューコンシューマーで求められる動作です。結果の待ち方については以降のセクションで説明します。

通用するシネマティックなプロンプトを書く

テキストから動画へのモデルは構造化を報います。被写体、カメラ、動き、ムードを指定したプロンプトは、一文だけのアイデアよりも常に優れています。各要素が、モデルが本来ランダムに決定する曖昧さを排除するからです。

使えるテンプレート:

[被写体とシーン]、[カメラ位置と動き]、
[フレーム内の動き]、[ライティング]、[ムードやカラーグレーディング]、[スタイル参照]

適用例:

夜明け、黄色のレインコートを着た孤独なサイクリストが石橋を渡っていく。ローアングルで車輪の高さから並行して追従し、水面には霧が漂う。柔らかなブルーアワーの光に暖かな提灯のアクセント、穏やかでどこか憂いを帯びた雰囲気、ワイドスクリーンのアナモルフィックレンズの質感。

各部分の役割:

  • 被写体とシーン — 抽象的な概念より具体的な名詞。「黄色のレインコートを着た孤独なサイクリスト」はモデルにレンダリングできるものを与えますが、「自由」は何も与えません。
  • カメラ — カメラ位置(ローアングル、空撮、アイレベル)と動き(追従、ゆっくりとしたプッシュイン、静止)は、見た目のプロダクションバリューに最も強く効くレバーです。
  • フレーム内の動き — 霧が漂う、布が揺れる、水面に波紋が広がる。動画には動きが必要です。明示的に伝えてください。
  • ライティングとムード — 時間帯、色温度、感情的トーン。互いに調和させてください。
  • スタイル — レンズやフォーマットの言語(アナモルフィックレンズ、浅い被写界深度、シネマティックなカラーグレーディング)は、監督を指定するよりも確実に質感を形作ります。

プロンプトは、競合するアイデアの寄せ集めではなく、数文の密度の高い記述に保ってください。1つのショットで2つのまったく異なるアクションが必要なら、2つのクリップを生成してください。そして反復してください。一度に1つの変数だけを変える——まずカメラ、次にライティング——そうすればモデルが何に反応するかを推測せずに理解できます。

非同期タスクとポーリングを扱う

動画生成は即時ではないため、パターンはまず作成、次にポーリングです。作成部分はすでに説明しました。以下がループです:

import time

def wait_for_job(job_id: str, timeout: int = 600) -> dict:
    deadline = time.monotonic() + timeout
    delay = 2.0
    while time.monotonic() < deadline:
        resp = requests.get(
            f"{BASE_URL}/video/generations/{job_id}",
            headers=HEADERS,
            timeout=30,
        )
        resp.raise_for_status()
        job = resp.json()
        status = job.get("status")

        if status == "succeeded":
            return job
        if status in ("failed", "cancelled"):
            raise RuntimeError(f"Job {job_id} ended with status {status}: {job}")

        time.sleep(delay)
        delay = min(delay * 1.5, 15.0)  # back off, cap at 15s

    raise TimeoutError(f"Job {job_id} did not finish in {timeout}s")

本番環境で重要な設計上の決定:

タイトループではなくバックオフポーリングを使用する

短い間隔から始めて徐々に増やします。上記の指数バックオフは固定上限で頭打ちになります。継続的な高速ポーリングはレート制限を消費するだけで何の利益もありません。生成時間は早く問い合わせても短くならないからです。

常に締め切りを設定する

すべてのポーリングループには最大実時間と、超過時の明確なエラーが必要です。そうでなければスタックしたタスクがワーカーを静かに永久に占有します。

終端状態は最終結果として扱う

進行中状態(queued、processing)と終端状態(succeeded、failed、cancelled)を区別してください。成功時のみ出力を返します。それ以外の状態はループを続けるのではなく、例外をスローするかリトライパスに移行すべきです。

ポーリングをリクエストハンドラーから分離する

Web サーバーでは、HTTP レスポンスを動画の完了までブロックしないでください。タスクを作成し、id をクライアントに返し、バックグラウンドワーカーやキューコンシューマーからポーリングします。タスク id とその最後に確認した状態を永続化し、再起動後も進行中の作業の追跡を失わないようにしてください。

出力のダウンロードと検証

タスクが succeeded に達すると、レスポンスには生成されたメディアへの参照——通常は完成したファイルへの URL——が含まれます。速やかにダウンロードし、その URL は一時的なものとして扱ってください。取得、保存、そして独自の永続的な場所を記録し、プロバイダーの URL をエンドユーザーに直接渡さないでください。

import pathlib

def download_output(job: dict, dest: pathlib.Path) -> pathlib.Path:
    url = job["output"]["video_url"]
    with requests.get(url, stream=True, timeout=120) as r:
        r.raise_for_status()
        dest.parent.mkdir(parents=True, exist_ok=True)
        with open(dest, "wb") as f:
            for chunk in r.iter_content(chunk_size=1 << 20):
                f.write(chunk)
    return dest

ファイルを誰かに渡す前に実施する価値のある検証手順:

  • 転送が完了したことを確認する。 チャンクでストリーミングし、書き込みサイズと Content-Length(存在する場合)を比較し、読み取り不足時には明示的に失敗させます。
  • 音声トラックを確認する。 generate_audio を要求した場合、ファイルにはオーディオストリームがあるはずです。ffprobe での素早いプローブが最も安価なチェックです:
ffprobe -v error -show_entries stream=codec_type -of csv=p=0 output.mp4

video と audio の両方の行が表示されるはずです。音声が欠けている場合は、そのフラグが作成呼び出しで設定されていたか再確認してください。後から追加することはできません。

  • 長さと解像度を期待値と基本的に照合する。公開前に切り詰めや仕様違いのレンダリングを捕まえるためです。
  • 決定論的なキーで保存する(タスク id とハッシュ)。まず一時パスに書き込み、成功後にリネームし、追跡のためにタスク id をアセットと一緒に保持します。

ダウンロードが転送途中で失敗した場合は、バックオフしてリトライしてください。URL が期限切れの場合は、新しい参照を得るためにタスクレコードを再取得する必要があります。

再利用可能なクライアントとしてカプセル化する

上記の各部分は自然に1つのクラスを構成します。それらをまとめれば、コピーせずにプロジェクト間でインポートできるものが得られます:

class KlingTextToVideo:
    def __init__(self, base_url: str, api_key: str):
        self.base_url = base_url.rstrip("/")
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        }

    def generate(self, prompt: str, generate_audio: bool = True,
                 timeout: int = 600) -> dict:
        job = create_video_job(prompt, generate_audio)  # create half
        return wait_for_job(job["id"], timeout=timeout)  # poll half

クライアントが成熟するにつれて、いくつか追加すべきものがあります:

  • タスク id をキーとした構造化ログ——状態遷移、ポーリング回数、経過時間、失敗。レンダリングに異常が生じたとき、タスク id はログ間を関連付けるキーになります。
  • 一時的なエラー(ネットワーク、5xx)のみに対する有界リトライ。拒否されたリクエストを盲目的にリトライしないでください。形式が正しくないリクエストボディは毎回同じように失敗し、クォータを浪費するだけです。
  • 自分の層で冪等性を実装する。 サービスが同じプロンプトを2回送信する可能性がある場合、作成呼び出しの前に重複排除してください。2つのタスクに対して支払うことになります。
  • プロンプトテンプレートをコードではなくデータとして扱う。 シネマティックなテンプレートを設定ファイルに置けば、プロンプトの反復にデプロイが不要になります。
  • 出力秒数に基づいてコストを計算する。 課金は生成された出力使用量に基づくため、タスクごとに生成された長さを追跡すれば、支出を機能やユーザーに帰属させることができます。

クライアントができれば、パイプラインは短くなります:テンプレートからプロンプトを構築し、generate を呼び出し、出力をダウンロードしてプローブし、保存したファイルをアプリケーションに渡します。将来 HiAPI に他のモデルを追加しても、同じ認証ヘッダー、タスクライフサイクル、ダウンロードパターンがそのまま適用されます。これが抽象化層を一度だけ構築する主な理由です。

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

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

APIドキュメントを読む