Unlock exclusive introductory pricing for the newly launched Gemini 3.5 Flash.
D

Doubao-Seedance-2-0

Por Segundo:$0.056
Lançado:Apr 19, 2026

Seedance 2.0 é o modelo base multimodal de vídeo de próxima geração da ByteDance, focado na geração de vídeos narrativos cinematográficos de múltiplos planos. Diferentemente de demonstrações de texto para vídeo de plano único, Seedance 2.0 enfatiza o controle baseado em referências (imagens, clipes curtos, áudio), a consistência de personagens/estilo entre os planos e a sincronização nativa de áudio/vídeo — visando tornar o vídeo com IA útil para fluxos de trabalho criativos profissionais e de pré-visualização.

Novo
Popular
Uso comercial

Playground para Doubao-Seedance-2-0

Explore o Playground do Doubao-Seedance-2-0 — um ambiente interativo para testar modelos e executar consultas em tempo real. Experimente prompts, ajuste parâmetros e itere instantaneamente para acelerar o desenvolvimento e validar casos de uso.

Technical specifications of Doubao Seedance 2.0

ItemDetails
Product familyByteDance Seedance video generation family
CometAPI slugdoubao-seedance-2-0
ProviderByteDance / BytePlus ModelArk
Model typeVideo generation model
Input modalitiesText, image
Output typeMP4 video
Output resolution480p, 720p, 1080p
Aspect ratios21:9, 16:9, 4:3, 1:1, 3:4, 9:16
Output duration4–15 seconds
API styleAsynchronous task-based video generation

What is Doubao Seedance 2.0?

Doubao Seedance 2.0 is ByteDance’s flagship multimodal video generation model (released February 2026). It uses a unified audio-video joint generation architecture that allows precise director-level control by referencing multiple images, video clips, and audio files simultaneously. It excels at producing cinematic, motion-stable videos with native audio synchronization — ideal for professional creators needing realistic physics, consistent characters, and complex scene composition.

Main features of Doubao Seedance 2.0 on CometAPI

  • Unified multimodal generation: It accepts text, image, audio, and video inputs in one workflow, so users can direct a scene with richer reference material than a text-only generator.
  • Director-style control: The model is built to follow prompts for performance, lighting, shadow, camera movement, motion rhythm, and sound characteristics.
  • Video editing and extension: Seedance 2.0 is not limited to first-pass generation; it supports editing specific clips, characters, actions, and storylines, plus forward/backward extension.
  • Strong audiovisual sync: ByteDance highlights dual-channel stereo output and synchronized background music, ambient sound, and voiceover behavior for more immersive results.
  • High controllability for complex scenes: It emphasize improved handling of complex interactions, motion scenes, and physical plausibility compared with Seedance 1.5.
  • Production-oriented output: API supports configurable ratio, duration, and watermark settings, which makes the model practical for repeatable content workflows.

Benchmark performance

ByteDance says Seedance 2.0 uses the internal SeedVideoBench-2.0 evaluation and places in the leading position across text-to-video, image-to-video, and multimodal task dimensions. The model improves generation quality, physical accuracy, realism, and controllability versus Seedance 1.5, especially in complex interaction and motion scenes.

Seedance 2.0 API and Seedance 2.0 Fast API Modes on CometAPI

ModelModel Name in CometAPIBest forMain difference
Seedance 2.0doubao-seedance-2-0Highest-quality multimodal video creationBroadest reference stack and strongest controllability in the Seedance 2.0 family.
Seedance 2.0 fastdoubao-seedance-2-0-fastFaster production when quality can be traded a bitByteDance says it keeps the same model capabilities as Seedance 2.0, but generates faster.
Seedance 1.5 Prodoubao-seedance-1-5-proEarlier-generation audio-video creationSeedance 1.5 Pro is positioned as a native joint audio-video model, while Seedance 2.0 expands the multimodal reference and editing stack.

Strengths vs Competitors:

  • vs Kling 3.0: Better multimodal reference control and native audio.
  • vs Sora 2: Superior reference precision and multi-shot capability; slightly lower max duration.
  • vs Veo 3.1: Stronger in character consistency and prompt adherence for reference-heavy workflows; Veo leads in raw cinematic grading and longer clips.

Excels in human-centric and performance-driven videos.

Try Seedance 2.0 AI Video Generator on CometAPI

Step 1: Step 1: Sign Up for API Key

Start directly in the CometAPI Playground to experience Doubao Seedance 2.0 without any setup or coding. Simply log into your CometAPI account, go to the model page for doubao-seedance-2-0, upload your reference images, short video clips, or audio files, add a descriptive prompt, and generate preview videos instantly. This is the fastest way to understand how Seedance 2.0 handles motion consistency, character appearance, camera movements, and native audio synchronization.

Step 2: Get API Access for Seedance 2.0 on CometAPI

Create or use your existing CometAPI key to enable full access to Doubao Seedance 2.0. After logging in, navigate to the API Token section in your console, generate a new key, and copy it. Then visit the Seedance 2.0 model detail page and API doc on CometAPI to review the supported parameters integrating into your projects.

Step 3: Send Your First Request with Seedance 2.0 API

Use the CometAPI endpoint to submit your first video generation request with a clear text prompt and optional reference files (images, video, or audio). The system will process the task asynchronously, return a task ID, and provide a downloadable MP4 video once completed. You can then refine your prompts, adjust settings, and scale up for marketing videos, social media content, automated video pipelines, or creative applications powered by Seedance 2.0.

This workflow gives you quick experimentation in the playground and smooth transition into production use via the CometAPI.

Top Reasons to Choose Seedance 2.0 on CometAPI

Why Use CometAPI for Seedance 2.0

  • Direct access via API or Playground
  • Easy parameter control (duration, resolution, format)
  • Supports both text-to-video and image-to-video workflows
  • Built-in job handling for asynchronous video generation

Unified & Developer-Friendly API

CometAPI offers a clean, standardized endpoint that works seamlessly with familiar OpenAI-style formats or dedicated video task endpoints. You get straightforward task creation, polling, and MP4 downloads without dealing with Volcengine’s complex authentication or regional limitations.

Cost-Effective Pricing

CometAPI typically delivers more competitive per-second rates compared to direct providers, allowing you to generate high-quality videos at scale for marketing, social media, or automated pipelines without breaking your budget.

Fast Testing with Playground

Experiment immediately in the CometAPI Playground. Upload reference images, videos, and audio files, tweak prompts, and preview results in minutes — perfect for iterating on style, motion, and audio sync before going into production.

In short, if you want the creative power of Seedance 2.0 — best-in-class reference control, natural motion, and native audio — without the hassle of direct ByteDance access, CometAPI is currently one of the best platforms to use it.

FAQ

Preços para Doubao-Seedance-2-0

Explore preços competitivos para Doubao-Seedance-2-0, projetado para atender diversos orçamentos e necessidades de uso. Nossos planos flexíveis garantem que você pague apenas pelo que usar, facilitando o dimensionamento conforme suas necessidades crescem. Descubra como Doubao-Seedance-2-0 pode aprimorar seus projetos mantendo os custos gerenciáveis.

Model480p720p1080p4k
doubao-seedance-2-0$0.056$0.1216$0.2992$0.624
doubao-seedance-2-0-fast$0.0448$0.096
doubao-seedance-2-0-mini$0.032$0.064
doubao-seedance-1-5-pro$0.0192$0.0416$0.0928
doubao-seedance-1-0-pro$0.0192$0.0416$0.0976
doubao-seedance-1-0-pro-fast$0.008$0.016$0.0384

Código de exemplo e API para Doubao-Seedance-2-0

Acesse código de exemplo abrangente e recursos de API para Doubao-Seedance-2-0 para otimizar seu processo de integração. Nossa documentação detalhada fornece orientação passo a passo, ajudando você a aproveitar todo o potencial do Doubao-Seedance-2-0 em seus projetos.

#!/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 $'
%{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 $'
%{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

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

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));
}

Versões do Doubao-Seedance-2-0

O motivo pelo qual Doubao-Seedance-2-0 possui múltiplas versões instantâneas pode incluir fatores como variações na saída após atualizações que exigem versões antigas para consistência, fornecendo aos desenvolvedores um período de transição para adaptação e migração, e diferentes versões correspondentes a endpoints globais ou regionais para otimizar a experiência do usuário. Para diferenças detalhadas entre versões, consulte a documentação oficial.

Version
doubao-seedance-2-0
doubao-seedance-2-0-fast