feat(seedance): 加 generate_audio 参数对齐官方 API

火山方舟官方 curl 例子 (CreateContentsGenerationsTasks) body 里有 generate_audio 字段
— Seedance 2.0 旗舰特性,原生 AI 生成背景音 / 角色对白 / 音效。我之前没接,补上。

- yaml 加 default_generate_audio: false (控成本默认关)
- tool execute 加 generate_audio kw + 进 body / meta / usage_events extra_units
- tool banner 加 audio=<bool> 字段
- SKILL 加参数段说明 + prompt 写法变化 (开音轨时要写背景音/对白具体内容)
  + 贴 prompt 模板 + 反模式各加一条

resolution / watermark 官方例子里没发但其他文档源确认 fast 必传 + 有效,保留。
参考媒体 (image_url/video_url/audio_url + role:reference_*) 是 i2v/v2v/r2v 路径,
phase 1 不接,延后。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-05-22 09:44:15 +08:00
parent 7d3a93fc1f
commit da71daa789
3 changed files with 42 additions and 3 deletions

View File

@ -52,6 +52,10 @@ video:
default_ratio: "16:9" # 16:9 / 9:16 / 1:1 / 4:3 / 3:4 / 21:9 / adaptive
default_duration: 5 # 4-15s
default_watermark: false
# generate_audio: Seedance 2.0 旗舰特性 —— 原生 AI 生成背景音效 / 角色对白(无需后期配音)。
# 开启会增加 token 消耗(模型还要算音轨),cost 比纯视频高;默认关闭让 cost 可预测,
# 用户要带音的视频(广告 / 角色对白)时显式传 true。
default_generate_audio: false
# 轮询参数
request_timeout_s: 60 # submit POST 超时(异步,只是提交)

View File

@ -115,11 +115,12 @@ description: 用豆包 Seedance 2.0 Fast 生视频(`seedance` tool)。**任何
> ratio: 16:9(ppt 横版)
> duration: 5 秒
> watermark: false
> generate_audio: false(静音视频,后期 ppt 加 BGM)
> 预计花费: ¥4.00
> 预计等待: 30-90 秒
> ````
>
> 这样开烧?要改什么?(改 prompt 文字 / 改时长 / 换比例 / 降到 480p 省钱)
> 这样开烧?要改什么?(改 prompt 文字 / 改时长 / 换比例 / 降到 480p 省钱 / 开 audio 加 AI 配音)
然后 ⛔ **BLOCKING:等用户明确回复**
@ -169,6 +170,21 @@ description: 用豆包 Seedance 2.0 Fast 生视频(`seedance` tool)。**任何
|---|---|
| `false` | 默认无水印(申报 / ppt / 客户交付都不该带);仅当用户明确说"加水印"才传 `true` |
### `generate_audio`(Seedance 2.0 旗舰特性)
| 默认 | 何时开 |
|---|---|
| `false` | 默认关 —— 控成本 + 大多数 ppt / 申报场景用静音视频(后期配音 / 当背景视频)。**模型还要算音轨,开启 cost 会高于纯视频估算**(具体增幅未实测,首次开时盯一下返回的 tokens)。 |
| `true` | 用户明确要**带声音的视频**:广告 / 短剧 / 角色对白 / 配乐场景。**调用前必须告诉用户**"开启 audio,cost 会高于估算 ¥X"并等确认。 |
prompt 写法变化:开 `generate_audio=true` 时,prompt 里要描述**声音是什么**(背景音 / 音效 / 对白台词具体说啥 / 音色),否则模型随机配,效果难控:
```
... 背景音「鲜切现摇」,女生音色,轻快鼓点卡点
```
参考火山方舟官方 r2v 例子(`r2v_tea_*`):每个镜头段都明示"背景音 XX / 卡点 XX / 音效 XX"。**不写 = 不可预期**。
## 调用范式
**前置条件**:用户已经看过最终 prompt + 所有参数,明确回复"可以" / "OK" / "出片吧" 之类。**没看到这个确认就不要调**。
@ -232,6 +248,7 @@ seedance(
- ❌ prompt 里写否定 "no shaking, not blurry" —— Seedance 不支持 negative,反向起效
- ❌ 让用户在 seedream / seedance 之间默默替他决定 —— 模糊就一句话问明白
- ❌ phase 1 拿用户已生成的图试图 i2v —— **当前不支持**,明确告诉用户
- ❌ 用户没说要声音就把 `generate_audio` 设 true —— 多花钱且大概率配出不合用户预期的随机音效;开它前必须问"要 AI 配音吗?cost 会高于估算"
- ❌ 用 `run_python``requests` 裸打豆包 API —— 走 `seedance` tool(已封装异步轮询 + 计费 + 落盘 + meta + cancel)
## 输出

View File

@ -102,6 +102,13 @@ class SeedanceTool(Tool):
"type": "boolean",
"description": "是否打豆包水印。默认 false(申报/PPT 场景反需求)。",
},
"generate_audio": {
"type": "boolean",
"description": (
"是否同步生成 AI 背景音 / 对白(Seedance 2.0 旗舰特性)。默认 false 控成本;"
"广告 / 短剧 / 角色对白等场景传 true,模型会一并算音轨,cost 高于纯视频。"
),
},
},
"required": ["prompt"],
}
@ -135,6 +142,7 @@ class SeedanceTool(Tool):
ratio: Optional[str] = None,
duration: Optional[int] = None,
watermark: Optional[bool] = None,
generate_audio: Optional[bool] = None,
) -> str:
if not (prompt or "").strip():
return "[Error] prompt 不能为空"
@ -145,6 +153,9 @@ class SeedanceTool(Tool):
chosen_ratio = ratio or cfg.get("default_ratio", "16:9")
chosen_duration = int(duration) if duration is not None else int(cfg.get("default_duration", 5))
chosen_watermark = bool(cfg.get("default_watermark", False)) if watermark is None else bool(watermark)
chosen_generate_audio = (
bool(cfg.get("default_generate_audio", False)) if generate_audio is None else bool(generate_audio)
)
fps = int(cfg.get("fps", 24))
submit_timeout = float(cfg.get("request_timeout_s", 60))
@ -162,6 +173,7 @@ class SeedanceTool(Tool):
"resolution": chosen_resolution,
"duration": chosen_duration,
"watermark": chosen_watermark,
"generate_audio": chosen_generate_audio,
}
t0 = time.monotonic()
@ -232,6 +244,7 @@ class SeedanceTool(Tool):
"duration_s": chosen_duration,
"fps": fps,
"watermark": chosen_watermark,
"generate_audio": chosen_generate_audio,
"tokens": tokens_actual,
"tokens_estimated": tokens_estimated,
"price_cny_per_mtoken": price_t2v,
@ -258,7 +271,11 @@ class SeedanceTool(Tool):
price_cny_per_mtoken=price_t2v,
has_video_input=False, # phase 1 仅 t2v;i2v 接入后这里读 body 判断
watermark=chosen_watermark,
extra_units={"cgt_id": cgt_id, "elapsed_s": round(elapsed, 1)},
extra_units={
"cgt_id": cgt_id,
"elapsed_s": round(elapsed, 1),
"generate_audio": chosen_generate_audio,
},
)
except Exception as e:
print(f"[seedance] record_video_usage failed: {type(e).__name__}: {e}", flush=True)
@ -268,7 +285,8 @@ class SeedanceTool(Tool):
# 前端 extractMediaBanner 已 whitelist seedance,正则抓 key=value 挂徽章
return (
f"[seedance] model={model_id} · resolution={chosen_resolution} · ratio={chosen_ratio} · "
f"duration={chosen_duration}s · cost=¥{cost_cny:.2f} · elapsed={elapsed:.1f}s\n"
f"duration={chosen_duration}s · audio={chosen_generate_audio} · "
f"cost=¥{cost_cny:.2f} · elapsed={elapsed:.1f}s\n"
f"saved: {disp}\n"
f"prompt={prompt!r}\n"
f"watermark={chosen_watermark} cgt_id={cgt_id}"