モデル料金エンタープライズ
500以上のAI Model API、オールインワンAPI。CometAPIで。
モデルAPI
開発者
クイックスタートドキュメントAPI ダッシュボード
会社
会社概要エンタープライズ
リソース
AIモデルブログ変更履歴サポート
利用規約プライバシーポリシー
© 2026 CometAPI · All rights reserved
Home/Models/Doubao/Doubao-Seedance-2-0
D

Doubao-Seedance-2-0

毎秒:$0.08
Seedance 2.0 は、ByteDance の次世代マルチモーダル動画基盤モデルで、シネマティックかつマルチショットのナラティブ動画生成に特化しています。単一ショットのテキストから動画へのデモとは異なり、Seedance 2.0 は参照ベースのコントロール(画像、短いクリップ、音声)、ショットをまたいだキャラクター/スタイルの一貫性、ネイティブな音声/映像の同期を重視し、プロフェッショナルなクリエイティブおよびプリビジュアライゼーションのワークフローで役立つ AI 動画の実現を目指しています。
新着
商用利用
概要
機能
料金プラン
API
バージョン

Doubao Seedance 2.0 の技術仕様

項目詳細
製品ファミリーByteDance Seedance video generation family
CometAPI スラッグdoubao-seedance-2-0
提供元ByteDance / BytePlus ModelArk
モデル種別動画生成モデル
入力モダリティテキスト、画像、音声、動画
参照上限1回のマルチモーダルリクエストにつき、最大9枚の画像、3本の動画クリップ、3本の音声クリップ
出力タイプMP4 動画
出力解像度480p, 720p, 1080p
アスペクト比21:9, 16:9, 4:3, 1:1, 3:4, 9:16
出力時間4–15秒
API スタイル非同期タスクベースの動画生成

Doubao Seedance 2.0 とは?

Doubao Seedance 2.0 は ByteDance によるフラッグシップのマルチモーダル動画生成モデル(2026年2月リリース)です。統合音声・映像の共同生成アーキテクチャを採用し、複数の画像、動画クリップ、音声ファイルを同時に参照することで、ディレクター級の精密なコントロールを可能にします。シネマティックで動きが安定した動画を、ネイティブな音声同期とともに生成することに長けており、物理的なリアリティ、キャラクターの一貫性、複雑なシーン構成を必要とするプロのクリエイターに最適です。

CometAPI 上の Doubao Seedance 2.0 の主な機能

  • 統合マルチモーダル生成: テキスト、画像、音声、動画を1つのワークフローで受け付けるため、テキストのみのジェネレータよりも豊富な参照素材でシーン演出が可能。
  • ディレクター視点の制御: 演技、ライティング、陰影、カメラワーク、動きのリズム、音の特性に関するプロンプトに忠実に従う設計。
  • 動画編集と拡張: 初回生成に限定されず、特定のクリップ、キャラクター、アクション、ストーリーラインの編集に加え、前後方向の延長に対応。
  • 強力な映像・音声同期: ByteDance は、デュアルチャネルのステレオ出力およびBGM、環境音、ナレーション挙動の同期を強調し、より没入感の高い結果を実現。
  • 複雑シーンに対する高い制御性: Seedance 1.5 と比べて、複雑な相互作用、モーションシーン、物理的妥当性の処理が向上。
  • プロダクション志向の出力: API は、比率、尺、ウォーターマーク設定を構成可能とし、繰り返し可能なコンテンツワークフローに適用しやすい。

ベンチマーク性能

ByteDance によれば、Seedance 2.0 は社内評価である SeedVideoBench-2.0 を用い、テキストから動画、画像から動画、およびマルチモーダルタスクの各次元でトップクラスの位置付けとなっています。特に複雑な相互作用やモーションシーンにおいて、Seedance 1.5 と比較して生成品質、物理的正確性、リアリティ、制御性が改善されています。

CometAPI における Seedance 2.0 API と Seedance 2.0 Fast API モード

モデルCometAPI 上のモデル名最適な用途主な違い
Seedance 2.0doubao-seedance-2-0最高品質のマルチモーダル動画制作Seedance 2.0 ファミリー内で最も広い参照スタックと最強の制御性。
Seedance 2.0 fastdoubao-seedance-2-0-fast多少の品質トレードオフで高速な制作ByteDance によれば Seedance 2.0 と同等のモデル能力を維持しつつ、より高速に生成。
Seedance 1.5 Prodoubao-seedance-1-5-pro旧世代の音声・映像ジョイント生成Seedance 1.5 Pro はネイティブな音声・映像ジョイントモデルという位置付けで、Seedance 2.0 はマルチモーダル参照と編集スタックを拡張。

競合比での強み:

  • vs Kling 3.0: マルチモーダル参照制御とネイティブ音声で優位。
  • vs Sora 2: 参照精度とマルチショット能力で優位。最大尺はやや短い。
  • vs Veo 3.1: 参照多用ワークフローでのキャラクター一貫性とプロンプト遵守で優位。Veo は生のシネマティックなグレーディングと長尺でリード。

人物中心・パフォーマンス駆動の動画で優秀。

CometAPI で Seedance 2.0 AI Video Generator を試す

ステップ 1: ステップ 1: API キーにサインアップ

セットアップやコーディング不要で Doubao Seedance 2.0 を体験するには、CometAPI Playground から直接開始します。CometAPI アカウントにログインし、doubao-seedance-2-0 のモデルページに移動して参照用の画像、短い動画クリップ、音声ファイルをアップロードし、説明的なプロンプトを追加して、プレビュー動画を即時生成します。これにより、Seedance 2.0 が動きの一貫性、キャラクターの外観、カメラワーク、ネイティブな音声同期をどのように処理するかを最速で把握できます。

ステップ 2: CometAPI 上で Seedance 2.0 の API アクセスを取得

新規の CometAPI キーを作成するか既存のキーを使用して、Doubao Seedance 2.0 へのフルアクセスを有効化します。ログイン後、コンソールの API Token セクションに移動して新しいキーを生成し、コピーします。その後、CometAPI の Seedance 2.0 モデル詳細ページと API ドキュメント を参照して、プロジェクト統合時に使用するサポートパラメータを確認してください。

ステップ 3: Seedance 2.0 API で最初のリクエストを送信

CometAPI のエンドポイントを使って、明確なテキストプロンプトと任意の参照ファイル(画像、動画、音声)を添えて最初の動画生成リクエストを送信します。システムはタスクを非同期で処理し、タスク ID を返した後、完了時にダウンロード可能な MP4 動画を提供します。以降はプロンプトの洗練、設定の調整を行い、マーケティング動画、ソーシャルメディア用コンテンツ、自動化パイプライン、Seedance 2.0 を活用したクリエイティブアプリケーションへとスケールできます。

このワークフローにより、Playground で素早く試行し、そのまま CometAPI を介して本番利用へスムーズに移行できます。

CometAPI で Seedance 2.0 を選ぶ理由

Seedance 2.0 に CometAPI を使う理由

  • API または Playground からのダイレクトアクセス
  • 簡単なパラメータ制御(尺、解像度、フォーマット)
  • text-to-video と image-to-video の両ワークフローに対応
  • 非同期動画生成のジョブ管理を内蔵

統一され開発者フレンドリーな API

CometAPI は、OpenAI スタイルのフォーマットや専用の動画タスクエンドポイントとシームレスに連携する、クリーンで標準化されたエンドポイントを提供します。Volcengine の複雑な認証や地域制限に煩わされることなく、シンプルなタスク作成、ポーリング、MP4 ダウンロードが可能です。

コスト効率の高い料金設定

CometAPI は一般に直接提供者と比較して 1 秒あたりのレートが競争力が高く、予算を圧迫せずに、マーケティング、ソーシャルメディア、自動化パイプライン向けに高品質な動画を大規模に生成できます。

Playground での高速テスト

CometAPI Playground ですぐに試せます。参照用の画像、動画、音声をアップロードし、プロンプトを調整して、数分で結果をプレビュー。プロダクション投入前に、スタイル、動き、音声同期を反復改善するのに最適です。

要するに、Seedance 2.0 の創造力—最高水準の参照制御、自然な動き、ネイティブ音声—を、ByteDance への直接アクセスの手間なしで享受したいなら、CometAPI は現時点で最良のプラットフォームの1つです。

よくある質問

What kinds of inputs does Seedance 2.0 support for video generation?

Seedance 2.0 は、テキストプロンプト、最大 9 枚の画像、最大 3 本の短い動画クリップ、最大 3 つの音声ファイルといったマルチモーダル入力に対応しており、これらを自由に組み合わせて表現力が高く制御可能な生成が行えます。

Can Seedance 2.0 maintain character and style consistency across multiple video shots?

はい — Seedance 2.0 は、シーンをまたいでもキャラクター、ビジュアルスタイル、雰囲気の一貫性を保つ整合的なマルチショットのストーリーテリングを念頭に設計されており、AI動画でよく見られるドリフト問題を軽減します。

What outputs and quality levels can I expect from Seedance 2.0 videos?

Seedance 2.0 は、ネイティブ音声、同期されたセリフ、自然なモーション合成を備えたシネマティック級(最大 2K 解像度)の動画を生成でき、通常は 5〜60 秒のクリップです。

How does Seedance 2.0 handle audio and lip synchronization?

このモデルは音声と映像を共同生成し、8 以上の言語で音素レベルのリップシンクに対応したネイティブな音声・映像同期を提供し、自然な話し声や効果音を実現します。

Is Seedance 2.0 suitable for professional creative projects like marketing or narrative shorts?

はい — Seedance 2.0 のマルチモーダル制御、マルチショットの連続性、高忠実度な出力により、マーケティング動画、ナラティブ短編、広告などのプロフェッショナルな用途に適しています。

How do referencing assets (images, video clips) work in Seedance 2.0 prompts?

ユーザーは参照アセットをアップロードし、各アセットが動き、カメラワーク、スタイル要素にどのように影響すべきかを自然言語で指示でき、生成結果をきめ細かく制御できます。

Does Seedance 2.0 allow editing and extension of existing videos?

はい — このモデルは未編集部分を保持しつつ、シーンの追加、キャラクターの差し替え、特定セグメントの変更などのターゲット編集や動画の延長に対応します。

What are known limitations or typical generation lengths with Seedance 2.0?

1 本あたりの典型的な出力長は約 5 秒〜約 60 秒で、多数のアセットを組み合わせたり高解像度設定にしたりすると生成時間が長くなる場合があります。

Doubao-Seedance-2-0の機能

Doubao-Seedance-2-0のパフォーマンスと使いやすさを向上させるために設計された主要機能をご紹介します。これらの機能がプロジェクトにどのようなメリットをもたらし、ユーザーエクスペリエンスを改善するかをご確認ください。

Doubao-Seedance-2-0の料金

Doubao-Seedance-2-0の競争力のある価格設定をご確認ください。さまざまな予算や利用ニーズに対応できるよう設計されています。柔軟なプランにより、使用した分だけお支払いいただけるため、要件の拡大に合わせて簡単にスケールアップできます。Doubao-Seedance-2-0がコストを管理しながら、お客様のプロジェクトをどのように強化できるかをご覧ください。

doubao-seedance Video Generation Pricing

Parameters

ParameterDescription
Duration (seconds)4–15 seconds, default 5 seconds
Aspect Ratio (size)21:9 / 16:9 / 4:3 / 1:1 / 3:4 / 9:16, default 16:9
Resolution480p / 720p / 1080p*, default 720p

*1080p only available for doubao-seedance-1-5-pro and doubao-seedance-1-0-pro

Pricing (Per Second)

Model480p720p1080p
doubao-seedance-2-0$0.08$0.24—
doubao-seedance-2-0-fast$0.064$0.192—
doubao-seedance-1-5-pro$0.018$0.04147$0.09331
doubao-seedance-1-0-pro$0.01875$0.0432$0.0972

💡 Billed per second. Total cost = price per second × video duration (seconds). Duration range: 4–15 seconds.

Doubao-Seedance-2-0のサンプルコードとAPI

Doubao-Seedance-2-0の包括的なサンプルコードとAPIリソースにアクセスして、統合プロセスを効率化しましょう。詳細なドキュメントでは段階的なガイダンスを提供し、プロジェクトでDoubao-Seedance-2-0の潜在能力を最大限に活用できるよう支援します。
POST
/v1/videos
Python
JavaScript
Curl
import json
import os
import time

import requests

# Get your CometAPI key from https://www.cometapi.com/console/token, and paste it here
COMETAPI_KEY = os.environ.get("COMETAPI_KEY") or "<YOUR_COMETAPI_KEY>"
BASE_URL = "https://api.cometapi.com"
OUTPUT_DIR = "./output"
POLL_INTERVAL_SECONDS = 10
RETRY_DELAY_SECONDS = 5
MAX_CREATE_ATTEMPTS = 5
MAX_QUERY_ATTEMPTS = 3
TERMINAL_STATUSES = {"success", "completed", "failed", "error"}
SUCCESS_STATUSES = {"success", "completed"}

def is_progress_complete(progress):
    if isinstance(progress, int):
        return progress >= 100
    if isinstance(progress, float):
        return progress >= 100
    if isinstance(progress, str):
        try:
            return float(progress.rstrip("%")) >= 100
        except ValueError:
            return False
    return False

def is_transient_status(status_code):
    return status_code == 429 or 500 <= status_code < 600

def create_task(files):
    for attempt in range(1, MAX_CREATE_ATTEMPTS + 1):
        response = requests.post(
            f"{BASE_URL}/v1/videos",
            headers=headers,
            files=files,
            timeout=30,
        )
        if response.ok:
            return response
        if not is_transient_status(response.status_code) or attempt == MAX_CREATE_ATTEMPTS:
            response.raise_for_status()
        print(f"Create request returned {response.status_code}, retrying...")
        time.sleep(RETRY_DELAY_SECONDS)

    raise SystemExit("Failed to create task.")

def get_task(task_id):
    for attempt in range(1, MAX_QUERY_ATTEMPTS + 1):
        response = requests.get(
            f"{BASE_URL}/v1/videos/{task_id}",
            headers=headers,
            timeout=15,
        )
        if response.ok:
            return response
        if not is_transient_status(response.status_code) or attempt == MAX_QUERY_ATTEMPTS:
            response.raise_for_status()
        print(f"Status request returned {response.status_code}, retrying...")
        time.sleep(RETRY_DELAY_SECONDS)

    raise SystemExit("Failed to query task.")

if COMETAPI_KEY == "<YOUR_COMETAPI_KEY>":
    print("Set COMETAPI_KEY before running this example.")
    raise SystemExit(0)

headers = {"Authorization": f"Bearer {COMETAPI_KEY}"}

create_response = create_task(
    {
        "prompt": (None, "A slow cinematic camera push across a coastal landscape at sunrise."),
        "model": (None, "doubao-seedance-2-0"),
        "seconds": (None, "5"),
        "size": (None, "16:9"),
        "resolution": (None, "720p"),
    }
)
create_response.raise_for_status()
create_result = create_response.json()

task_id = create_result.get("id") or create_result.get("task_id")
if not task_id:
    print(json.dumps(create_result, indent=2))
    raise SystemExit("No task id returned.")

print(f"Task created: {task_id}")
print(f"Initial status: {create_result.get('status')}")

while True:
    task_response = get_task(task_id)
    task_response.raise_for_status()
    task = task_response.json()
    status = str(task.get("status") or "unknown")
    normalized_status = status.lower()
    progress = task.get("progress")
    should_try_download = normalized_status in SUCCESS_STATUSES or (
        normalized_status == "unknown" and is_progress_complete(progress)
    )

    print(f"Status: {status}, progress: {progress}")

    if should_try_download or normalized_status in TERMINAL_STATUSES:
        if should_try_download:
            video_url = task.get("video_url") or ""
            content_url = f"{BASE_URL}/v1/videos/{task_id}/content"
            output_path = os.path.join(OUTPUT_DIR, f"{task_id}.mp4")

            os.makedirs(OUTPUT_DIR, exist_ok=True)
            with requests.get(
                content_url,
                headers=headers,
                timeout=120,
                stream=True,
            ) as video_response:
                video_response.raise_for_status()
                with open(output_path, "wb") as output_file:
                    for chunk in video_response.iter_content(chunk_size=8192):
                        if chunk:
                            output_file.write(chunk)

            print(f"Video URL: {video_url}")
            print(f"Content endpoint: {content_url}")
            print(f"Saved to {output_path}")
            print(f"File size: {os.path.getsize(output_path)} bytes")
        else:
            print(json.dumps(task, indent=2))
            raise SystemExit(1)
        break

    time.sleep(POLL_INTERVAL_SECONDS)

Python Code Example

import json
import os
import time

import requests

# Get your CometAPI key from https://www.cometapi.com/console/token, and paste it here
COMETAPI_KEY = os.environ.get("COMETAPI_KEY") or "<YOUR_COMETAPI_KEY>"
BASE_URL = "https://api.cometapi.com"
OUTPUT_DIR = "./output"
POLL_INTERVAL_SECONDS = 10
RETRY_DELAY_SECONDS = 5
MAX_CREATE_ATTEMPTS = 5
MAX_QUERY_ATTEMPTS = 3
TERMINAL_STATUSES = {"success", "completed", "failed", "error"}
SUCCESS_STATUSES = {"success", "completed"}


def is_progress_complete(progress):
    if isinstance(progress, int):
        return progress >= 100
    if isinstance(progress, float):
        return progress >= 100
    if isinstance(progress, str):
        try:
            return float(progress.rstrip("%")) >= 100
        except ValueError:
            return False
    return False


def is_transient_status(status_code):
    return status_code == 429 or 500 <= status_code < 600


def create_task(files):
    for attempt in range(1, MAX_CREATE_ATTEMPTS + 1):
        response = requests.post(
            f"{BASE_URL}/v1/videos",
            headers=headers,
            files=files,
            timeout=30,
        )
        if response.ok:
            return response
        if not is_transient_status(response.status_code) or attempt == MAX_CREATE_ATTEMPTS:
            response.raise_for_status()
        print(f"Create request returned {response.status_code}, retrying...")
        time.sleep(RETRY_DELAY_SECONDS)

    raise SystemExit("Failed to create task.")


def get_task(task_id):
    for attempt in range(1, MAX_QUERY_ATTEMPTS + 1):
        response = requests.get(
            f"{BASE_URL}/v1/videos/{task_id}",
            headers=headers,
            timeout=15,
        )
        if response.ok:
            return response
        if not is_transient_status(response.status_code) or attempt == MAX_QUERY_ATTEMPTS:
            response.raise_for_status()
        print(f"Status request returned {response.status_code}, retrying...")
        time.sleep(RETRY_DELAY_SECONDS)

    raise SystemExit("Failed to query task.")

if COMETAPI_KEY == "<YOUR_COMETAPI_KEY>":
    print("Set COMETAPI_KEY before running this example.")
    raise SystemExit(0)

headers = {"Authorization": f"Bearer {COMETAPI_KEY}"}

create_response = create_task(
    {
        "prompt": (None, "A slow cinematic camera push across a coastal landscape at sunrise."),
        "model": (None, "doubao-seedance-2-0"),
        "seconds": (None, "5"),
        "size": (None, "16:9"),
        "resolution": (None, "720p"),
    }
)
create_response.raise_for_status()
create_result = create_response.json()

task_id = create_result.get("id") or create_result.get("task_id")
if not task_id:
    print(json.dumps(create_result, indent=2))
    raise SystemExit("No task id returned.")

print(f"Task created: {task_id}")
print(f"Initial status: {create_result.get('status')}")

while True:
    task_response = get_task(task_id)
    task_response.raise_for_status()
    task = task_response.json()
    status = str(task.get("status") or "unknown")
    normalized_status = status.lower()
    progress = task.get("progress")
    should_try_download = normalized_status in SUCCESS_STATUSES or (
        normalized_status == "unknown" and is_progress_complete(progress)
    )

    print(f"Status: {status}, progress: {progress}")

    if should_try_download or normalized_status in TERMINAL_STATUSES:
        if should_try_download:
            video_url = task.get("video_url") or ""
            content_url = f"{BASE_URL}/v1/videos/{task_id}/content"
            output_path = os.path.join(OUTPUT_DIR, f"{task_id}.mp4")

            os.makedirs(OUTPUT_DIR, exist_ok=True)
            with requests.get(
                content_url,
                headers=headers,
                timeout=120,
                stream=True,
            ) as video_response:
                video_response.raise_for_status()
                with open(output_path, "wb") as output_file:
                    for chunk in video_response.iter_content(chunk_size=8192):
                        if chunk:
                            output_file.write(chunk)

            print(f"Video URL: {video_url}")
            print(f"Content endpoint: {content_url}")
            print(f"Saved to {output_path}")
            print(f"File size: {os.path.getsize(output_path)} bytes")
        else:
            print(json.dumps(task, indent=2))
            raise SystemExit(1)
        break

    time.sleep(POLL_INTERVAL_SECONDS)

JavaScript Code Example

import fs from "fs";
import path from "path";

// Get your CometAPI key from https://www.cometapi.com/console/token, and paste it here
const api_key = process.env.COMETAPI_KEY || "<YOUR_COMETAPI_KEY>";
const base_url = "https://api.cometapi.com";
const output_dir = "./output";
const poll_interval_ms = 10_000;
const retry_delay_ms = 5_000;
const max_create_attempts = 5;
const max_query_attempts = 3;
const terminal_statuses = new Set(["success", "completed", "failed", "error"]);
const success_statuses = new Set(["success", "completed"]);

function is_progress_complete(progress) {
  if (typeof progress === "number") {
    return progress >= 100;
  }

  if (typeof progress === "string") {
    const numeric = Number(progress.replace(/%$/, ""));
    return Number.isFinite(numeric) && numeric >= 100;
  }

  return false;
}

function is_transient_status(status) {
  return status === 429 || status >= 500;
}

async function fetch_with_retry(url, options, attempts, label) {
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    const response = await fetch(url, options);
    if (response.ok) {
      return response;
    }

    if (!is_transient_status(response.status) || attempt === attempts) {
      return response;
    }

    console.log(`${label} returned ${response.status}, retrying...`);
    await new Promise((resolve) => setTimeout(resolve, retry_delay_ms));
  }

  throw new Error(`${label} failed`);
}

if (api_key === "<YOUR_COMETAPI_KEY>") {
  console.log("Set COMETAPI_KEY before running this example.");
  process.exit(0);
}

const headers = {
  Authorization: `Bearer ${api_key}`,
};

const form = new FormData();
form.set("prompt", "A slow cinematic camera push across a coastal landscape at sunrise.");
form.set("model", "doubao-seedance-2-0");
form.set("seconds", "5");
form.set("size", "16:9");
form.set("resolution", "720p");

const create_response = await fetch_with_retry(`${base_url}/v1/videos`, {
  method: "POST",
  headers,
  body: form,
}, max_create_attempts, "Create request");

if (!create_response.ok) {
  console.log(await create_response.text());
  process.exit(1);
}

const create_result = await create_response.json();
const task_id = create_result.id || create_result.task_id;

if (!task_id) {
  console.log(JSON.stringify(create_result, null, 2));
  process.exit(1);
}

console.log(`Task created: ${task_id}`);
console.log(`Initial status: ${create_result.status}`);

while (true) {
  const task_response = await fetch_with_retry(`${base_url}/v1/videos/${task_id}`, {
    headers,
  }, max_query_attempts, "Status request");

  if (!task_response.ok) {
    console.log(await task_response.text());
    process.exit(1);
  }

  const task = await task_response.json();
  const status = String(task.status || "unknown");
  const normalized_status = status.toLowerCase();
  const progress = task.progress;
  const should_try_download = success_statuses.has(normalized_status) || (
    normalized_status === "unknown" && is_progress_complete(progress)
  );

  console.log(`Status: ${status}, progress: ${progress}`);

  if (should_try_download || terminal_statuses.has(normalized_status)) {
    if (should_try_download) {
      const video_url = task.video_url || "";
      const content_url = `${base_url}/v1/videos/${task_id}/content`;
      const output_path = path.join(output_dir, `${task_id}.mp4`);

      if (!fs.existsSync(output_dir)) {
        fs.mkdirSync(output_dir, { recursive: true });
      }

      const video_response = await fetch(content_url, { headers });
      if (!video_response.ok) {
        console.log(await video_response.text());
        process.exit(1);
      }

      const video_buffer = Buffer.from(await video_response.arrayBuffer());
      fs.writeFileSync(output_path, video_buffer);

      console.log(`Video URL: ${video_url}`);
      console.log(`Content endpoint: ${content_url}`);
      console.log(`Saved to ${output_path}`);
      console.log(`File size: ${fs.statSync(output_path).size} bytes`);
    } else {
      console.log(JSON.stringify(task, null, 2));
      process.exit(1);
    }
    break;
  }

  await new Promise((resolve) => setTimeout(resolve, poll_interval_ms));
}

Curl Code Example

#!/bin/bash

set -euo pipefail

# Get your CometAPI key from https://www.cometapi.com/console/token
# Export it as: export COMETAPI_KEY="your-key-here"

if [[ -z "${COMETAPI_KEY:-}" ]]; then
  echo "Set COMETAPI_KEY before running this example."
  exit 0
fi

BASE_URL="https://api.cometapi.com"
OUTPUT_DIR="./output"
POLL_INTERVAL_SECONDS=10
RETRY_DELAY_SECONDS=5
MAX_CREATE_ATTEMPTS=5
MAX_QUERY_ATTEMPTS=3

is_progress_complete() {
  local progress="$1"
  local normalized="${progress%%%}"

  if [[ -z "$normalized" ]]; then
    return 1
  fi

  [[ "$normalized" =~ ^[0-9]+([.][0-9]+)?$ ]] || return 1
  awk -v value="$normalized" 'BEGIN { exit !(value >= 100) }'
}

create_task() {
  local attempt=1
  while (( attempt <= MAX_CREATE_ATTEMPTS )); do
    local response
    local status_code
    response=$(curl -sS -w $'\n%{http_code}' "${BASE_URL}/v1/videos" \
      -H "Authorization: Bearer $COMETAPI_KEY" \
      -F 'prompt="A slow cinematic camera push across a coastal landscape at sunrise."' \
      -F 'model="doubao-seedance-2-0"' \
      -F 'seconds="5"' \
      -F 'size="16:9"' \
      -F 'resolution="720p"')

    status_code=$(echo "$response" | tail -n 1)
    CREATE_RESPONSE=$(echo "$response" | sed '$d')

    if [[ "$status_code" =~ ^2 ]]; then
      return 0
    fi

    if [[ "$status_code" == "429" || "$status_code" =~ ^5 ]] && (( attempt < MAX_CREATE_ATTEMPTS )); then
      echo "Create request returned ${status_code}, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      (( attempt += 1 ))
      continue
    fi

    echo "$CREATE_RESPONSE"
    return 1
  done
}

get_task() {
  local task_id="$1"
  local attempt=1
  while (( attempt <= MAX_QUERY_ATTEMPTS )); do
    local response
    local status_code
    response=$(curl -sS -w $'\n%{http_code}' "${BASE_URL}/v1/videos/${task_id}" \
      -H "Authorization: Bearer $COMETAPI_KEY")

    status_code=$(echo "$response" | tail -n 1)
    TASK_RESPONSE=$(echo "$response" | sed '$d')

    if [[ "$status_code" =~ ^2 ]]; then
      return 0
    fi

    if [[ "$status_code" == "429" || "$status_code" =~ ^5 ]] && (( attempt < MAX_QUERY_ATTEMPTS )); then
      echo "Status request returned ${status_code}, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      (( attempt += 1 ))
      continue
    fi

    echo "$TASK_RESPONSE"
    return 1
  done
}

create_task

TASK_ID=$(echo "$CREATE_RESPONSE" | jq -r '.id // .task_id // empty')

if [[ -z "$TASK_ID" ]]; then
  echo "$CREATE_RESPONSE" | jq .
  echo "No task id returned."
  exit 1
fi

echo "Task created: $TASK_ID"
echo "Initial status: $(echo "$CREATE_RESPONSE" | jq -r '.status // empty')"

while true; do
  get_task "$TASK_ID"

  STATUS=$(echo "$TASK_RESPONSE" | jq -r '.status // empty')
  NORMALIZED_STATUS=$(echo "$STATUS" | tr '[:upper:]' '[:lower:]')
  PROGRESS=$(echo "$TASK_RESPONSE" | jq -r '.progress // empty')
  SHOULD_TRY_DOWNLOAD=0

  if [[ "$NORMALIZED_STATUS" == "success" || "$NORMALIZED_STATUS" == "completed" ]]; then
    SHOULD_TRY_DOWNLOAD=1
  elif [[ "$NORMALIZED_STATUS" == "unknown" ]] && is_progress_complete "$PROGRESS"; then
    SHOULD_TRY_DOWNLOAD=1
  fi

  echo "Status: ${STATUS}, progress: ${PROGRESS}"

  if [[ "$SHOULD_TRY_DOWNLOAD" == "1" || "$NORMALIZED_STATUS" == "failed" || "$NORMALIZED_STATUS" == "error" ]]; then
    if [[ "$SHOULD_TRY_DOWNLOAD" == "1" ]]; then
      VIDEO_URL=$(echo "$TASK_RESPONSE" | jq -r '.video_url // empty')
      CONTENT_URL="${BASE_URL}/v1/videos/${TASK_ID}/content"
      OUTPUT_PATH="${OUTPUT_DIR}/${TASK_ID}.mp4"

      mkdir -p "$OUTPUT_DIR"
      curl -fsS "$CONTENT_URL" \
        -H "Authorization: Bearer $COMETAPI_KEY" \
        -o "$OUTPUT_PATH"

      if [[ ! -s "$OUTPUT_PATH" ]]; then
        echo "Failed to download video"
        exit 1
      fi

      echo "Video URL: ${VIDEO_URL}"
      echo "Content endpoint: ${CONTENT_URL}"
      echo "Saved to ${OUTPUT_PATH}"
      echo "File size: $(wc -c < "$OUTPUT_PATH" | tr -d ' ') bytes"
    else
      echo "$TASK_RESPONSE" | jq .
      exit 1
    fi
    break
  fi

  sleep "$POLL_INTERVAL_SECONDS"
done

Doubao-Seedance-2-0のバージョン

Doubao-Seedance-2-0に複数のスナップショットが存在する理由としては、アップデート後の出力変動により旧版スナップショットの一貫性維持が必要な場合、開発者に適応・移行期間を提供するため、グローバル/リージョナルエンドポイントに対応する異なるスナップショットによるユーザー体験最適化などが考えられます。各バージョンの詳細な差異については、公式ドキュメントをご参照ください。
version
doubao-seedance-2-0
doubao-seedance-2-0-fast

その他のモデル

O

Sora 2 Pro

毎秒:$0.24
Sora 2 Pro は、当社で最も高度かつ強力なメディア生成モデルで、音声と同期した動画を生成できます。自然言語または画像から、精細でダイナミックな動画クリップを生成します。
O

Sora 2

毎秒:$0.08
効果音に対応し、チャット形式をサポートする超高性能な動画生成モデル。
M

mj_fast_video

リクエストごと:$0.6
Midjourney video generation
X

Grok Imagine Video

毎秒:$0.04
テキストプロンプトから動画を生成し、静止画像をアニメーション化し、自然言語で既存の動画を編集できます。APIは生成される動画の再生時間、アスペクト比、解像度の設定に対応し、SDKが非同期ポーリングを自動的に処理します。
G

Veo 3.1 Pro

毎秒:$0.25
Veo 3.1-Pro は、Google の Veo 3.1 ファミリーの上位機能向けアクセス/設定を指します—より豊かなネイティブ音声、改善されたナラティブ/編集コントロール、シーン拡張ツールを追加した短尺の音声対応ビデオモデルの世代です。
G

Veo 3.1

毎秒:$0.05
Veo 3.1 は、Google の Veo テキストおよび画像→動画ファミリーに対する段階的だが重要なアップデートで、より豊かなネイティブオーディオ、より長くより制御しやすい動画出力、そしてより細かな編集やシーンレベルのコントロールを追加します。

関連ブログ

Seedance 2.0 APIの使い方
Apr 17, 2026

Seedance 2.0 APIの使い方

Seedance 2.0 APIは、ByteDanceの最新のマルチモーダルAI動画生成モデル(2026年4月9日リリース)です。単一のリクエストでテキスト、画像、動画クリップ、音声を受け付け、ネイティブな音声同期、監督レベルのカメラ制御、優れた動きの一貫性を備えた、シネマティックな4〜15秒のMP4動画を生成します。使い方:CometAPI.comでサインアップし、APIキーを取得し、REST経由で非同期タスクを送信し、完了をポーリングし、動画URLをダウンロードします。
HappyHorse-1.0とは何ですか?Seedance 2.0を比較するにはどうすればよいですか?
Apr 11, 2026
seedance-2-0

HappyHorse-1.0とは何ですか?Seedance 2.0を比較するにはどうすればよいですか?

HappyHorse-1.0とは何か、なぜArtificial Analysisの動画リーダーボードでトップに立ったのか、Seedance 2.0との比較、そして最新のランキングがAI動画生成にとって何を意味するのかを学ぶ。
Seedance 2.0とは何か? 包括的な分析
Mar 24, 2026
seedance-2-0

Seedance 2.0とは何か? 包括的な分析

Seedance 2.0は、ByteDanceが開発した次世代のマルチモーダルAI動画生成モデルであり、テキスト、画像、音声、参照動画から高品質でシネマティックな動画を生成できます。音声と映像の共同生成、モーションの安定性、参照ベースの編集機能を備えており、Artificial Analysisのリーダーボードのような世界的なベンチマークで急速に順位を上げ、2026年のトップAI動画モデルの一つとしての地位を確立しています。