ModelHargaPerusahaan
500+ API Model AI, Semua Dalam Satu API. Hanya Di CometAPI
API Model
Pembangun
Mula PantasDokumentasiPapan Pemuka API
Syarikat
Tentang kamiPerusahaan
Sumber
Model AIBlogLog PerubahanSokongan
Terma PerkhidmatanDasar Privasi
© 2026 CometAPI · All rights reserved
Home/Models/Doubao/Doubao-Seedance-2-0
D

Doubao-Seedance-2-0

Setiap Saat:$0.063
Seedance 2.0 ialah model asas multimodal untuk video generasi seterusnya daripada ByteDance yang memfokuskan pada penjanaan video naratif sinematik berbilang syot. Tidak seperti demonstrasi teks-ke-video syot tunggal, Seedance 2.0 menekankan kawalan berasaskan rujukan (imej, klip pendek, audio), ketekalan watak/gaya yang padu merentas syot, dan penselarasan audio/video natif — dengan matlamat menjadikan video AI berguna untuk aliran kerja kreatif profesional dan pra-visualisasi.
Baru
Penggunaan komersial
Playground
Gambaran Keseluruhan
Ciri-ciri
Harga
API
Versi

Spesifikasi teknikal Doubao Seedance 2.0

ItemButiran
Product familyKeluarga penjanaan video ByteDance Seedance
CometAPI slugdoubao-seedance-2-0
ProviderByteDance / BytePlus ModelArk
Model typeModel penjanaan video
Input modalitiesTeks, imej
Output typeVideo MP4
Output resolution480p, 720p, 1080p
Aspect ratios21:9, 16:9, 4:3, 1:1, 3:4, 9:16
Output duration4–15 saat
API stylePenjanaan video berasaskan tugasan tidak segerak

Apa itu Doubao Seedance 2.0?

Doubao Seedance 2.0 ialah model penjanaan video multimodal utama ByteDance (dikeluarkan pada Februari 2026). Ia menggunakan senibina penjanaan audio-video bersepadu yang membolehkan kawalan pada tahap pengarah dengan merujuk berbilang imej, klip video dan fail audio secara serentak. Ia cemerlang menghasilkan video sinematik yang stabil pergerakannya dengan penyelarasan audio asli — sesuai untuk pencipta profesional yang memerlukan fizik realistik, watak konsisten, dan komposisi adegan yang kompleks.

Ciri utama Doubao Seedance 2.0 di CometAPI

  • Penjanaan multimodal bersatu: Menerima input teks, imej, audio dan video dalam satu aliran kerja, membolehkan pengguna mengarah adegan dengan bahan rujukan yang lebih kaya berbanding penjana teks sahaja.
  • Kawalan gaya pengarah: Model dibina untuk mengikuti prompt bagi persembahan, pencahayaan, bayang, pergerakan kamera, ritma gerakan dan ciri bunyi.
  • Penyuntingan dan peluasan video: Seedance 2.0 bukan terhad kepada penjanaan kali pertama; ia menyokong penyuntingan klip, watak, aksi, dan jalan cerita tertentu, serta peluasan ke hadapan/ke belakang.
  • Penyelarasan audiovisual yang kukuh: ByteDance menonjolkan output stereo dua saluran serta penyelarasan muzik latar, bunyi ambien, dan tingkah laku alih suara untuk hasil yang lebih mengasyikkan.
  • Keboleh kawal tinggi untuk adegan kompleks: Menekankan penambahbaikan dalam pengendalian interaksi kompleks, adegan gerakan, dan kebolehpercayaan fizikal berbanding Seedance 1.5.
  • Output berorientasikan produksi: API menyokong tetapan nisbah, tempoh dan tanda air yang boleh dikonfigurasi, menjadikan model praktikal untuk aliran kerja kandungan berulang.

Prestasi penanda aras

ByteDance menyatakan Seedance 2.0 menggunakan penilaian dalaman SeedVideoBench-2.0 dan berada dalam kelompok teratas merentas dimensi tugas teks-ke-video, imej-ke-video, dan multimodal. Model ini mempertingkatkan kualiti penjanaan, ketepatan fizikal, realisme, dan keboleh kawal berbanding Seedance 1.5, terutamanya dalam interaksi kompleks dan adegan gerakan.

Mod API Seedance 2.0 dan Seedance 2.0 Fast pada CometAPI

ModelNama Model dalam CometAPITerbaik untukPerbezaan utama
Seedance 2.0doubao-seedance-2-0Penciptaan video multimodal berkualiti tertinggiTindan rujukan paling luas dan keboleh kawal paling kukuh dalam keluarga Seedance 2.0.
Seedance 2.0 fastdoubao-seedance-2-0-fastPenghasilan lebih pantas apabila kualiti boleh dikompromi sedikitByteDance menyatakan ia mengekalkan keupayaan model yang sama seperti Seedance 2.0, tetapi menjana dengan lebih pantas.
Seedance 1.5 Prodoubao-seedance-1-5-proPenciptaan audio-video generasi terdahuluSeedance 1.5 Pro diposisikan sebagai model audio-video gabung asli, manakala Seedance 2.0 memperluas rujukan multimodal dan set penyuntingannya.

Kekuatan vs Pesaing:

  • vs Kling 3.0: Kawalan rujukan multimodal yang lebih baik dan audio asli.
  • vs Sora 2: Ketepatan rujukan dan keupayaan berbilang babak yang lebih unggul; tempoh maksimum sedikit lebih rendah.
  • vs Veo 3.1: Lebih kuat dalam konsistensi watak dan pematuhan prompt untuk aliran kerja berat rujukan; Veo mendahului dalam gred sinematik mentah dan klip lebih panjang.

Cemerlang dalam video berfokus manusia dan berorientasikan persembahan.

Cuba Penjana Video AI Seedance 2.0 di CometAPI

Langkah 1: Langkah 1: Daftar untuk Kunci API

Mulakan terus di CometAPI Playground untuk mengalami Doubao Seedance 2.0 tanpa sebarang persediaan atau pengekodan. Hanya log masuk ke akaun CometAPI anda, pergi ke halaman model untuk doubao-seedance-2-0, muat naik imej rujukan, klip video pendek atau fail audio anda, tambah prompt deskriptif, dan jana video pratonton serta-merta. Ini ialah cara terpantas untuk memahami bagaimana Seedance 2.0 mengendalikan konsistensi pergerakan, rupa watak, pergerakan kamera, dan penyelarasan audio asli.

Langkah 2: Dapatkan Akses API untuk Seedance 2.0 di CometAPI

Cipta atau gunakan kunci CometAPI sedia ada anda untuk mendayakan akses penuh ke Doubao Seedance 2.0. Selepas log masuk, navigasi ke bahagian Token API dalam konsol anda, jana kunci baharu dan salin. Kemudian lawati halaman butiran model Seedance 2.0 dan Dokumen API di CometAPI untuk menyemak parameter yang disokong bagi integrasi ke projek anda.

Langkah 3: Hantar Permintaan Pertama Anda dengan API Seedance 2.0

Gunakan titik akhir CometAPI untuk menghantar permintaan penjanaan video pertama anda dengan prompt teks yang jelas dan fail rujukan pilihan (imej, video atau audio). Sistem akan memproses tugasan secara tidak segerak, memulangkan ID tugasan, dan menyediakan video MP4 yang boleh dimuat turun apabila selesai. Anda kemudian boleh memperhalusi prompt, melaraskan tetapan, dan menskalakan untuk video pemasaran, kandungan media sosial, saluran paip video automatik, atau aplikasi kreatif yang dikuasakan oleh Seedance 2.0.

Aliran kerja ini memberi anda percubaan pantas di playground dan peralihan yang lancar ke penggunaan produksi melalui CometAPI.

Sebab Teratas untuk Memilih Seedance 2.0 di CometAPI

Mengapa Menggunakan CometAPI untuk Seedance 2.0

  • Akses terus melalui API atau Playground
  • Kawalan parameter yang mudah (tempoh, resolusi, format)
  • Menyokong kedua-dua aliran kerja teks-ke-video dan imej-ke-video
  • Pengendalian kerja terbina dalam untuk penjanaan video tidak segerak

API Bersepadu & Mesra Pembangun

CometAPI menawarkan titik akhir yang bersih dan piawai yang berfungsi lancar dengan format gaya OpenAI yang biasa atau titik akhir tugasan video khusus. Anda mendapat penciptaan tugasan, pemantauan (polling), dan muat turun MP4 yang jelas tanpa perlu berurusan dengan pengesahan kompleks atau had serantau Volcengine.

Harga Berkesan Kos

CometAPI lazimnya menawarkan kadar per saat yang lebih kompetitif berbanding penyedia terus, membolehkan anda menjana video berkualiti tinggi pada skala untuk pemasaran, media sosial, atau saluran paip automatik tanpa menjejaskan bajet.

Ujian Pantas dengan Playground

Bereksperimen serta-merta di CometAPI Playground. Muat naik imej, video dan audio rujukan, ubah suai prompt, dan pratonton hasil dalam beberapa minit — sesuai untuk iterasi gaya, gerakan, dan penyelarasan audio sebelum memasuki produksi.

Ringkasnya, jika anda mahukan kuasa kreatif Seedance 2.0 — kawalan rujukan terbaik dalam kelasnya, pergerakan semula jadi, dan audio asli — tanpa kerumitan akses terus ByteDance, CometAPI pada masa ini ialah salah satu platform terbaik untuk menggunakannya.

Soalan Lazim

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

Seedance 2.0 menyokong input multimodal termasuk prompt teks, sehingga 9 imej, sehingga 3 klip video pendek, dan sehingga 3 fail audio, yang boleh digabungkan secara bebas untuk penjanaan yang kaya dan boleh dikawal.

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

Ya — Seedance 2.0 direka untuk penceritaan berbilang bidikan yang koheren dengan watak, gaya visual, dan suasana yang konsisten merentasi babak, sekali gus mengurangkan masalah hanyutan video AI yang biasa.

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

Seedance 2.0 boleh menjana video bertaraf sinematik (sehingga resolusi 2K) dengan audio natif, dialog terselaras, dan sintesis gerakan yang semula jadi, lazimnya dalam klip berdurasi 5–60 saat.

How does Seedance 2.0 handle audio and lip synchronization?

Model ini menjana audio dan video secara serentak, menawarkan penyegerakan audio-visual natif dengan penyegerakan bibir pada tahap fonem dalam 8+ bahasa untuk pertuturan dan kesan bunyi yang semula jadi.

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

Ya — kawalan multimodal, kesinambungan berbilang bidikan, dan output fideliti tinggi Seedance 2.0 menjadikannya sesuai untuk video pemasaran, karya pendek naratif, iklan, serta aplikasi profesional yang lain.

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

Pengguna boleh memuat naik aset rujukan dan kemudian menerangkan dalam bahasa semula jadi bagaimana setiap satunya perlu mempengaruhi gerakan, pergerakan kamera, atau elemen gaya, sekali gus memberikan kawalan yang terperinci ke atas kandungan yang dijana.

Does Seedance 2.0 allow editing and extension of existing videos?

Ya — model ini menyokong peluasan video dan penyuntingan bersasar seperti menambah babak, menggantikan watak, atau mengubah segmen tertentu sambil mengekalkan bahagian yang tidak disunting.

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

Panjang output lazimnya antara ~5 hingga ~60 saat bagi setiap video, dan menggabungkan banyak aset atau tetapan resolusi tinggi boleh meningkatkan masa penjanaan.

Harga untuk Doubao-Seedance-2-0

Terokai harga yang kompetitif untuk Doubao-Seedance-2-0, direka bentuk untuk memenuhi pelbagai bajet dan keperluan penggunaan. Pelan fleksibel kami memastikan anda hanya membayar untuk apa yang anda gunakan, menjadikannya mudah untuk meningkatkan skala apabila keperluan anda berkembang. Temui bagaimana Doubao-Seedance-2-0 boleh meningkatkan projek anda sambil mengekalkan kos yang terurus.

doubao-seedance Video Generation Pricing

Parameters

ParameterDescription
Duration (seconds)4–15 seconds, default 5 seconds
sizeRefer to documentation

*1080p is available for all models except doubao-seedance-2-0-fast

Pricing (Per Second)

Model480p720p1080p
doubao-seedance-2-0$0.063$0.1368$0.3366
doubao-seedance-2-0-fast$0.0504$0.108—
doubao-seedance-1-5-pro$0.024$0.052$0.118
doubao-seedance-1-0-pro$0.032$0.084$0.1992

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

Kod contoh dan API untuk Doubao-Seedance-2-0

Akses kod sampel yang komprehensif dan sumber API untuk Doubao-Seedance-2-0 bagi memperlancar proses integrasi anda. Dokumentasi terperinci kami menyediakan panduan langkah demi langkah, membantu anda memanfaatkan potensi penuh Doubao-Seedance-2-0 dalam projek anda.
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"),
    }
)
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"),
    }
)
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");

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"')

    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

Versi Doubao-Seedance-2-0

Sebab Doubao-Seedance-2-0 mempunyai berbilang snapshot mungkin merangkumi faktor berpotensi seperti variasi output selepas kemas kini yang memerlukan snapshot lama untuk konsistensi, menyediakan tempoh peralihan untuk penyesuaian dan migrasi kepada pembangun, serta snapshot berbeza yang sepadan dengan endpoint global atau serantau untuk mengoptimumkan pengalaman pengguna. Untuk perbezaan terperinci antara versi, sila rujuk dokumentasi rasmi.
version
doubao-seedance-2-0
doubao-seedance-2-0-fast