広告枠を募集中 ご相談ください

Luma Dream Machine API 連携ガイド:自動動画生成とポーリング実装の実践

365Finds Editorial
Wiki 記事 11,430 本収録

あなたの AI で 365 Wiki を使う

下のプロンプトをコピーして、普段使っている AI に貼り付け、そのまま質問してください。

完全版 Skill をダウンロード

まずはプロンプトでお試しください。よく使う場合は完全版 365Wiki Skill をインストールすると、毎回貼り付ける必要がありません。普段使う AI がなければ、Gemini や Microsoft Copilot のウェブ版でも使えます。

クリエイティブエンジニアリングチームや自動化メディアパイプラインが AI 動画の量産をスケールさせる際、必ず直面するのがブラウザ操作による手動運用の限界です。社内のデジタルアセット管理(DAM)システムや EC 商品カタログ、自動 VFX ワークフローと連携させるには、プログラマブルな API 統合が不可欠です。Luma Dream Machine API は、Ray 2 や Ray 2 Flash をはじめとする高性能な動画生成基底モデルへのプログラムアクセスを提供します。REST エンドポイントおよび公式の Python / Node.js SDK を通じて、認証、テキスト/画像からの動画レンダリング、精密なカメラワーク制御、そして生成アセットの自動収集パイプラインを構築できます。

プログラムによる動画生成は、計算リソースを多く消費する典型的な非同期ジョブです。安定した自動化パイプラインには、「安全な API 認証」「キーフレームとカメラ制御を伴うジョブ投入」「耐障害性を備えた非同期ポーリングまたは Webhook 受信」「生成アセットの永続化ストレージ保存」という 4 つの要素が求められます。


アーキテクチャの全体像

EC の商品画像を 5 秒間のダイナミックなプロモーション動画へ自動変換するバッチ処理フローを例にとると、パイプラインのライフサイクルは次のように進行します。

[公開画像ストレージ (S3 / CDN)] 
              │
              ▼
   [ジョブ投入: POST /generations] ──> [Luma Ray エンジン (キュー待ち / 生成中)]
              │                                      │
              ├──────────────────────────────────────┘
              ▼
[ポーリングループ (指数バックオフ) または Webhook (callback_url)]
              │
              ▼
  [ジョブステータス: Completed / Failed]
              │
              ├─> Failed: failure_reason を記録しモデレーション原因を特定
              └─> Completed: assets.video をストリーミング取得し社内クラウドへ保管
  1. アセットの事前配置: 入力画像は、外部からアクセス可能な HTTPS 経由の CDN または署名付きストレージ URL に配置します。
  2. ジョブの投入: パイプラインが /dream-machine/v1/generations に対して POST リクエストを発行し、プロンプト、モデル種別、カメラ制御概念、キーフレームを指定します。
  3. レンダリング実行: Luma のスケジューラがジョブを待機列(queued)に入れ、動画合成処理(dreaming)を開始し、最終ステータス(completed または failed)へ遷移します。
  4. 完了検知: 指数バックオフとジッターを組み合わせたポーリング、あるいは Webhook コールバックにより結果をキャッチします。
  5. アセットの永続化: 生成された MP4 動画の署名付き URL(assets.video)を取得し、有効期限が切れる前に速やかに内部ストレージへストリーミング保存します。

認証と SDK の環境構築

まず Luma API Platform で API キーを発行します。環境変数に登録して管理するのが安全です。

export LUMAAI_API_KEY="your_luma_api_key_here"

公式 Python SDK を利用すると、認証ヘッダーの付与が自動化されます。

pip install lumaai requests

直接 HTTP リクエストを送信する場合は、標準的な Bearer トークン形式でヘッダーを指定します。

Authorization: Bearer your_luma_api_key_here
Content-Type: application/json

動画生成ジョブの投入

Luma Dream Machine API は、テキストからの動画生成(Text-to-Video)と、画像からの動画生成(Image-to-Video / I2V)の両方に対応しています。EC の商品動線やコンセプトアートの拡張には、keyframes を用いた Image-to-Video が適しています。

主要リクエストパラメータ

パラメータ名型必須説明
promptstring必須動き、質感、照明、背景変化を指示する自然言語プロンプト。
modelstring任意ray-2(高精度な標準フラッグシップ)または ray-flash-2(高速処理モデル)。
aspect_ratiostring任意アスペクト比:16:9、9:16、1:1、4:3、3:4、21:9、9:21。
resolutionstring任意解像度:540p、720p、1080p、4k。
durationstring任意動画の長さ:5s または 9s。
loopboolean任意開始と終了が滑らかにつながるループ動画を生成(true または false)。
keyframesobject任意開始フレーム(frame0)や終了フレーム(frame1)の画像 URL または既存ジョブ ID。
conceptsarray任意カメラワークなどの演出概念(例: [{"key": "dolly_zoom"}])。
callback_urlstring任意ステータス変化を受け取る Webhook エンドポイント URL。

カメラモーション(Camera Motion)の制御方法

Ray エンジンは、映画撮影用語の自然言語プロンプトを高度に認識します。プロンプト内に直接記述するか、カメラモーション一覧 API(GET /dream-machine/v1/generations/camera_motion/list)で取得できる標準語句を使用します。代表的な動きは以下の通りです。

Python による Image-to-Video ジョブ投入例

import os
from lumaai import LumaAI

client = LumaAI(auth_token=os.environ.get("LUMAAI_API_KEY"))

def dispatch_ecommerce_render(image_url: str, product_title: str) -> str:
    """
    開始キーフレームとカメラワークを指定して Image-to-Video ジョブを投入
    """
    prompt = (
        f"Cinematic studio commercial presentation of {product_title}, "
        "dramatic rim light, revolving product podium, camera orbit right slowly"
    )
    
    generation = client.generations.create(
        prompt=prompt,
        model="ray-2",
        resolution="720p",
        duration="5s",
        aspect_ratio="16:9",
        loop=True,
        keyframes={
            "frame0": {
                "type": "image",
                "url": image_url
            }
        }
    )
    
    print(f"ジョブを送信しました (ID: {generation.id})")
    return generation.id

堅牢な非同期ポーリングメカニズムの実装

動画レンダリングにはモデルやサーバー混雑度に応じて 30 秒から数分程度かかります。API は即座に UUID v4 形式のジョブ ID を返すため、バックグラウンドワーカーは GET /dream-machine/v1/generations/{id} を定期的に呼び出して進捗を追跡する必要があります。

単純なポーリングで生じやすい問題点

  1. 高頻度リクエストによるレート制限: ミリ秒単位の間隔で連続問い合わせを行うと、HTTP 429 エラーとなり IP 制限を受けるリスクがあります。
  2. タイムアウト未設定によるプロセスの固着: 一時的なキュー遅延や異常終了に対しタイムアウトを設けていない場合、ワーカープロセスが解放されなくなります。
  3. コンテンツ安全フィルターのエラー見落とし: 不適切表現や規約違反により失敗した場合、generation.state は failed となります。ネットワークエラーとして一括処理せず、generation.failure_reason を確認する必要があります。

実運用向け Python ポーリング&ダウンロード実装

以下のコードは、指数バックオフ、ランダムジッター、タイムアウト制御、ストリーミングファイル書き込みを実装した例です。

import os
import time
import random
import requests
from lumaai import LumaAI

def wait_and_download_render(
    generation_id: str,
    output_filename: str,
    base_interval: float = 4.0,
    max_interval: float = 16.0,
    timeout_seconds: float = 360.0
) -> str:
    """
    ジョブの完了をポーリングで監視し、完了後に MP4 動画をディスクへ保存
    """
    client = LumaAI(auth_token=os.environ.get("LUMAAI_API_KEY"))
    start_time = time.time()
    current_interval = base_interval

    while True:
        elapsed = time.time() - start_time
        if elapsed > timeout_seconds:
            raise TimeoutError(f"ジョブ {generation_id} がタイムアウトしました({timeout_seconds}秒経過)")

        generation = client.generations.get(id=generation_id)
        state = generation.state

        if state == "completed":
            video_url = generation.assets.video
            print(f"レンダリング完了(所要時間: {elapsed:.1f}秒)。ダウンロードを開始します...")
            
            # メモリ枯渇を防ぐためストリーミング方式で保存
            response = requests.get(video_url, stream=True, timeout=30)
            response.raise_for_status()
            with open(output_filename, "wb") as f:
                for chunk in response.iter_content(chunk_size=1024 * 1024):
                    if chunk:
                        f.write(chunk)
                        
            print(f"動画を保存しました: {output_filename}")
            return output_filename

        elif state == "failed":
            reason = getattr(generation, "failure_reason", "原因不明")
            raise RuntimeError(f"Luma ジョブ {generation_id} が失敗しました: {reason}")

        elif state in ("queued", "dreaming"):
            print(f"ステータス: [{state}]({elapsed:.1f}秒経過)。{current_interval:.1f}秒後に再確認します...")
            time.sleep(current_interval + random.uniform(0.1, 0.9))
            current_interval = min(current_interval * 1.5, max_interval)

        else:
            print(f"未知のステータス '{state}' です。待機中...")
            time.sleep(current_interval)

大規模処理での選定:ポーリング vs Webhook

1 日に数百件〜数千件以上の動画をレンダリングする大規模システムでは、同期的なポーリング待機スレッドがサーバーリソースを無駄に圧迫する可能性があります。

callback_url によるイベント駆動設計

ジョブ投入時に callback_url を付与することで、完了通知を自動受信できます。

generation = client.generations.create(
    prompt="A commercial bottle rotating against a minimalist background",
    model="ray-2",
    callback_url="https://api.yourcompany.com/webhooks/luma"
)

Webhook の仕様と運用ルール


本番運用のベストプラクティス

  1. アセットの即時取り込み: assets.video の URL は有効期限付きの CDN 署名リンクです。自社データベースに直リンクを保存するのではなく、生成完了直後に社内の Amazon S3、Google Cloud Storage、Cloudflare R2 などへコピーしてください。
  2. キーフレーム画像の配信品質: keyframes に渡す画像 URL は、パブリックインターネットから安定して高速に到達できる必要があります。画像ホストの認証拒否や DNS 解決遅延があると、ジョブは即時失敗します。
  3. レート制限と冪等性管理: アカウントに割り当てられた RPM(1分間あたりのリクエスト数)および同時実行ジョブ数を把握し、バッチ投入時には冪等キーを用いて二重課金を防止してください。
  4. モデルの使い分け戦略: アイデア出しや SNS 用の短尺大量バリエーション作成には、低コストで高速な ray-flash-2 が有効です。高画質 1080p や 4k の本番向け広告クリエイティブには ray-2 を採用するという段階的な使い分けがコストパフォーマンスを高めます。

参考資料