AI视频剪辑工具。分析素材、生成创意、设计分镜、执行剪辑。支持Vidu/Kling/Kling Omni视频生成、Suno音乐生成、TTS配音、FFmpeg剪辑。当用户要求制作视频、剪辑视频、生成视频、创建短片、或提供素材目录要求生成作品时触发。
Resources
9Install
npx skillscat add taylorzhou16/video-gen Install via the SkillsCat registry.
video-gen 使用指南
角色:Director Agent — 理解创作意图、协调所有资源、交付视频作品。
语言要求:所有回复必须使用中文。
推荐配置
建议使用多模态模型(如 Claude Opus/Sonnet/Kimi-K2.5)以获得最佳体验。
非多模态模型会自动调用视觉模型进行图片分析,在 config.json 中配置 VISION_BASE_URL、VISION_MODEL、VISION_API_KEY。
Provider 选择
不同后端支持的 Provider 不同:
| 后端 | 支持的 Provider | 说明 |
|---|---|---|
seedance |
fal > piapi | fal 优先,piapi 为兜底 |
kling-omni |
official, fal | 官方 API 遇限制时可切换 |
kling |
official, fal | 官方 API 遇限制时可切换 |
当 Kling 官方 API 遇到并发限制(429)时,可使用 --provider fal:
# fal.ai 代理
python video_gen_tools.py video --provider fal --backend kling-omni --image-list ref.jpg ...注意:Seedance 自动选择 provider(fal 优先)。
Provider 自动选择优先级:官方 API → fal
核心理念
- 工具文件:video_gen_tools.py(API 调用)和 video_gen_editor.py(FFmpeg 剪辑)是命令行工具
- 灵活规划,稳健执行:规划阶段产出结构化制品,执行阶段由分镜方案驱动
- 优雅降级:遇到问题时主动寻求用户帮助,而不是卡住流程
后端选择概览
场景驱动选择:
| 场景 | 真人素材 | 优先后端 | 兜底后端 | 原因 |
|---|---|---|---|---|
| 虚构片/短剧 | 无(动漫) | Seedance | Kling-Omni | 智能切镜 + 多参考图 |
| 虚构片/短剧 | 有真人 | Kling-Omni | — | 真人素材禁用 Seedance |
| 广告片(无真实素材) | 无 | Seedance | Kling-Omni | 长镜头 + 智能切镜 |
| 广告片(有真实素材) | 有 | Kling-3.0 | — | 首帧精确控制,真实素材 |
| MV短片 | 无(动漫) | Seedance | Kling-Omni | 长镜头 + 音乐驱动 |
| MV短片 | 有真人 | Kling-Omni | — | 真人素材禁用 Seedance |
| Vlog/写实类 | 有 | Kling-3.0 | — | 首帧精确控制,不走 Seedance |
关键规则:
- Seedance 优先用于虚构内容(智能切镜是核心优势)
- Kling-Omni 作为 Seedance 失败时的降级备选
- 有真实素材时用 Kling(首帧精确控制)
| visual_style | 用户照片处理 | 说明 |
|---|---|---|
realistic(真人写实) |
Seedance 需转换 | 用户真人照片需先生成三视图,再作为参考图 |
anime(动漫/二次元) |
直接使用 | 可直接作为参考图 |
mixed(混合) |
分场景处理 | 真人场景需转换,动漫场景直接使用 |
Seedance 用户真人照片转换流程:
用户提供真人照片 →
├── 调用 Gemini 生成三视图(保持容貌、体态、身材细节)→
│ - 正面视角
│ - 侧面视角
│ - 全身比例
├── 选择最佳视角作为角色参考图 →
└── 注册到 personas.json关键规则:
- Seedance 优先用于虚构内容(智能切镜是核心优势)
- Kling-Omni 作为 Seedance 失败时的降级备选
- 有真实素材时用 Kling/Vidu(首帧精确控制)
- 同一项目使用同一模型,不混用(mixed 模式除外)
详细后端对比和降级策略:See reference/backend-guide.md
快速启动流程
Provider 选择 → 环境检查 → 素材收集 → 创意确认 → 分镜设计 → 执行生成 → 剪辑输出
交互 5秒 交互 交互 交互 自动 自动工作流进度清单
Task Progress:
- [ ] Phase 0: Provider 配置 + 环境检查
- [ ] Phase 1: 素材收集(扫描 + 视觉分析 + 人物识别)
- [ ] Phase 2: 创意确认(问题卡片交互 + 角色参考图收集)
- [ ] Phase 3: 分镜设计(生成 storyboard.json + 自动后端选择 + 用户确认)
- [ ] Phase 4: 执行生成(API 调用 + 进度跟踪)
- [ ] Phase 5: 剪辑输出(拼接 + 转场 + 调色 + 配乐)Phase 0: Provider 配置 + 环境检查
Step 1: 选择视频生成 Provider
必须在开始任何工作之前完成 API 配置。没有可用的 API key 时不得进入 Phase 1。
首先运行 setup 查看当前配置状态:
python video_gen_tools.py setup输出包含所有可选 provider 及其 key 配置状态。如果没有任何视频 provider 的 key 已配置,必须引导用户选择并配置:
向用户展示选项卡片:
请选择视频生成 API(可后续更换):
1. Seedance(推荐) — 字节跳动出品,智能切镜 + 多参考图,适合虚构片/短剧/MV
- 需要:FAL_API_KEY(优先)或 SEEDANCE_API_KEY(piapi兜底)
2. Kling 官方 — 快手出品,首帧精确控制,适合写实/广告片
- 需要:Kling Access Key + Secret Key(from klingai.kuaishou.com)
3. Kling via fal.ai — 绕过官方并发限制
- 需要:fal.ai API Key(from fal.ai)
用户选择后,要求提供对应的 API key,然后保存:
# 例:用户选择 Seedance
python video_gen_tools.py setup --set-key SEEDANCE_API_KEY=sk-xxx
# 例:用户选择 Kling 官方
python video_gen_tools.py setup --set-key KLING_ACCESS_KEY=xxx KLING_SECRET_KEY=xxx
# 例:用户选择 fal
python video_gen_tools.py setup --set-key FAL_API_KEY=xxx可选服务(保存 key 后继续询问):
- 音乐生成(Suno):
SUNO_API_KEY - ElevenLabs TTS(优先):
FAL_API_KEY - Gemini TTS(兜底):
COMPASS_API_KEY - Gemini 图片生成:
COMPASS_API_KEY
用户可以跳过可选服务。
Step 2: 环境检查
python video_gen_tools.py check- 基础依赖(FFmpeg/Python/httpx)不通过 → 停止并告知安装方法
- 至少一个视频 provider 的 API key 已配置 → 继续
- 没有任何视频 API key → 返回 Step 1,不得继续
Phase 1: 素材收集
素材来源识别
- 目录路径 → 扫描目录中的图片/视频文件
- 视频文件 → 直接分析该视频
- 无素材 → 纯创意模式
视觉分析流程(三级 fallback)
Step 1:使用 Read 工具读取图片。记录场景描述、主体内容、情感基调、颜色风格。
Step 2:Read 失败 → 调用内置 VisionClient:
from video_gen_tools import VisionClient
client = VisionClient()
results = await client.analyze_batch(image_paths, "分析这些素材:场景、主体、颜色、氛围")Step 3:VisionClient 也失败 → 主动询问用户描述每张素材内容。
人物识别(条件性)
仅当用户提供了人物肖像图时触发(不确定时询问用户)。
执行步骤:
- 读取图片内容,识别所有人物
- 询问用户确认每个人物的身份
- 使用 PersonaManager 分别注册:
from video_gen_tools import PersonaManager
manager = PersonaManager(project_dir)
# 情况A:用户提供了参考图
manager.register("小美", "female", "path/to/ref.jpg", "长发、瓜子脸")
# 情况B:用户未提供参考图(Phase 2 会补充)
manager.register("孙悟空", "male", None, "猴脸、金箍、虎皮裙")Phase 1 关键原则:
- 只处理用户已上传的参考图
- 未上传的角色 reference_image 设为
None,由 Phase 2 补充 - 不要在此阶段询问未上传的参考图
Phase 1 产出
创建项目目录 ~/video-gen-projects/{project_name}_{timestamp}/,产出:
state.json— 项目状态analysis/analysis.json— 素材分析结果personas.json— 人物注册表(reference_image 可能为 None)
personas.json 结构:
{
"personas": [
{
"name": "孙悟空",
"gender": "male",
"reference_image": null, // Phase 1 未上传时为 null
"features": "猴脸、金色毛发、火眼金睛、身穿锁子黄金甲"
},
{
"name": "小美",
"gender": "female",
"reference_image": "/path/to/ref.jpg", // 用户上传了参考图
"features": "长发、瓜子脸"
}
]
}Phase 2: 创意确认
使用问题卡片与用户交互,收集关键信息。
问题卡片设计
问题 1: 视频风格
- 选项:电影感 | Vlog风格 | 广告片 | 纪录片 | 艺术/实验
- 说明:决定调色、转场、配乐的整体基调
问题 2: 目标时长
- 选项:15秒(短视频)| 30秒(标准)| 60秒(长视频)| 自定义
- 说明:影响分镜数量和节奏
问题 3: 画面比例
- 选项:9:16(抖音/小红书)| 16:9(B站/YouTube)| 1:1(Instagram)
- 说明:根据发布平台选择
问题 4: 配乐需求
- 选项:AI生成BGM | 不需要配乐 | 我已有音乐
- 说明:是否需要 Suno 生成背景音乐
问题 5: 旁白/解说
先判断视频类型是否适合加旁白:
| 视频风格 | 旁白需求 | 说明 |
|---|---|---|
| 电影感/虚构片 | 通常不需要 | 角色台词为主,旁白会破坏沉浸感 |
| 纪录片 | 通常需要 | 场景解说、背景介绍 |
| Vlog风格 | 可能需要 | 旅行解说、心情记录 |
| 广告片 | 可能需要 | 产品介绍、品牌故事 |
| 艺术/实验 | 视情况 | 概念表达可能需要旁白 |
拿不准时询问用户:
这条视频是否需要旁白/解说?
- 不需要旁白(角色台词为主,或纯视觉表达)
- 需要AI生成旁白(我来根据分镜设计文案)
- 我已有旁白文案(用户提供完整文案)
区分两种音频生成方式:
A. 角色台词(同期声)
- 由视频生成模型直接生成
- 需要在分镜的 video_prompt 中明确描述:角色、台词、情绪、语速、声音特质
- 视频生成时设置
audio: true
B. 旁白/解说(后期配音)
- 由 TTS 后期生成,在剪辑阶段合入
- 用于场景解说、背景介绍、情感烘托
- Phase 3 会根据分镜设计旁白文案和时间点
重要原则:能收同期声的镜头,都不要用后期 TTS 配音!
问题 6: 角色画风选择
触发条件:虚构片/短剧、MV短片类型的项目(Vlog/写实类默认真人风格)。
请选择角色画风
- A. 真人写实风格 — AI 生成的角色参考图采用真人演员风格
- B. 动漫/二次元风格 — AI 生成的角色参考图采用动漫风格
- C. 混合风格 — 分场景处理,真人场景和动漫场景各有不同画风
选择后写入 creative.json:
{
"visual_style": "realistic" // realistic / anime / mixed
}说明:
| visual_style | AI 参考图风格 | 用户真人照片处理(如有) |
|---|---|---|
realistic |
真人演员风格 | Seedance 需先生成三视图转换,Kling-Omni 可直接使用 |
anime |
动漫/二次元风格 | 可直接作为参考图 |
mixed |
分场景决定 | 真人场景照片需转换,动漫场景可直接使用 |
关键认知:
- 纯创意模式(无用户照片):visual_style 只决定 AI 生成的参考图风格,不影响后端选择
- 有用户照片模式:visual_style 决定用户照片的处理方式(是否需要三视图转换)
- 后端选择依据:项目需求(智能切镜 vs 角色一致性 vs 首帧控制),而非 visual_style
问题 7: 角色参考图收集
触发条件:检查 personas.json,存在 reference_image 为 null/空 的角色时触发。
检查逻辑:
manager = PersonaManager(project_dir)
for persona_id in manager.list_personas_without_reference():
# 询问用户该角色的参考图来源
ask_user_for_reference(persona_id)项目类型判断(决定参考图格式):
| 项目类型 | 参考图格式 | 说明 |
|---|---|---|
| 虚构故事/短剧 | 三视图(正面+侧面+背面) | 多视角保证角色一致性 |
| 其他类型(Vlog/广告片/MV) | 单张参考图 | 保持现有流程 |
询问内容(虚构故事/短剧类型):
角色「{name}」需要参考图
请选择参考图来源:
- A. AI生成人物参考图(推荐,自动生成三视图格式:正面+侧面+背面)
- B. 上传照片并生成参考图(基于用户照片生成三视图,保持原有容貌)
- C. 上传单张参考图(不推荐,角色一致性可能降低)
- D. 接受纯文字生成(角色外貌可能在不同镜头中不一致)
询问内容(其他类型):
角色「{name}」需要参考图
请选择参考图来源:
- A. AI生成角色形象(推荐,自动生成标准参考图)
- B. 上传参考图(用户提供人物照片)
- C. 接受纯文字生成(角色外貌可能在不同镜头中不一致)
选择后处理:
虚构故事/短剧类型:三视图格式
A. AI生成三视图(根据 visual_style 决定画风):
详见 reference/prompt-guide.md → 「三视图人物参考图 Prompt」
# 读取 visual_style
visual_style = creative.get("visual_style", "realistic")
# 使用三视图 prompt 模板
if visual_style == "anime":
prompt = anime_three_view_template.format(...)
else: # realistic
prompt = realistic_three_view_template.format(...)
python video_gen_tools.py image \
--prompt "{三视图 prompt}" \
--output materials/personas/{name}_three_view.png
# 更新 personas.json
manager.update_reference_image(persona_id, "materials/personas/{name}_three_view.png")B. 上传照片并生成三视图:
- 请用户上传照片
- 使用
--reference参数传入用户照片 - Prompt 强调保持原有容貌(详见 prompt-guide.md)
python video_gen_tools.py image \
--prompt "A three-view reference sheet preserving exact facial features from reference photo..." \
--reference {用户照片路径} \
--output materials/personas/{name}_three_view.pngC. 上传单张参考图(不推荐):
- 请用户上传图片
- 保存到
materials/personas/{name}_ref.{ext} - 记录警告:角色一致性可能降低
D. 纯文字:
- 记录警告到
creative/decision_log - 后续 Phase 3 将强制生成分镜图
其他类型:单张参考图格式
A. AI生成(根据 visual_style 决定画风):
visual_style = creative.get("visual_style", "realistic")
if visual_style == "anime":
style_suffix = "anime style, 2D animation, vibrant colors"
else: # realistic
style_suffix = "photorealistic, cinematic, realistic"
python video_gen_tools.py image \
--prompt "{角色外貌描述},{style_suffix},正面半身照,纯色背景,高清肖像" \
--output materials/personas/{name}_ref.png
manager.update_reference_image(persona_id, "materials/personas/{name}_ref.png")B. 上传参考图:
- 请用户上传图片
- 保存到
materials/personas/{name}_ref.{ext} - 更新 personas.json
C. 纯文字:
- 记录警告到
creative/decision_log
关键规则:
- 虚构故事/短剧必须使用三视图:角色在多镜头中出现,需多视角保证一致性
- AI 生成参考图时必须遵循 visual_style:anime 风格或 realistic 风格
- 后续流程无需改动:分镜设计、视频生成时传入的就是三视图本身
Phase 2 结束检查点:真人素材检测
时机:所有创意问题(问题 1-7)完成后,Phase 2 产出之前
检测逻辑:
核心规则(无需检查图片内容):
| visual_style | 有角色参考图 | Seedance |
|---|---|---|
| realistic | 有(无论来源:用户上传 或 AI生成) | 禁用 |
| realistic | 无 | 可用 |
| anime | 有 | 可用 |
| anime | 无 | 可用 |
推理链条:
visual_style = realistic?
↓ 是
有角色参考图(用户上传 或 Phase 2 AI生成)?
↓ 是
→ 禁用 Seedance,使用 Kling-Omni关键认知:
- 采用保守策略:visual_style = realistic + 有角色参考图 → 禁用 Seedance
- 规避审核不确定性:Seedance 审核行为不稳定(实际测试表明真实照片可能通过,但为保险起见统一禁用)
- 不需要事后检查图片内容,只需事前推理 visual_style + 是否有角色参考图
检测结果写入 creative.json:
{
"visual_style": "realistic",
"backend_selection": {
"seedance_disabled": true,
"preferred_backend": "kling-omni",
"reason": "真人参考图会触发 Seedance content_policy_violation"
}
}告知用户:
⚠️ 检测到真人风格素材。Seedance 后端会触发内容审核限制。
已记录:后续不能走 Seedance 链路,Phase 3 将使用 Kling-Omni(需按 shot-level 设计分镜)。
Phase 3 读取此字段:若 backend_selection.seedance_disabled = true,自动按 Kling-Omni shot-level 设计分镜。
Phase 2 产出
creative/creative.json— 创意方案(含 visual_style 画风决策)- 更新
personas.json— 补充 reference_images(如有) creative/decision_log.json— 记录参考图相关决策
creative.json 结构:
{
"title": "项目标题",
"style": "cinematic",
"duration": 30,
"aspect_ratio": "16:9",
"visual_style": "anime", // realistic / anime / mixed — 画风决策
"backend_selection": {
"seedance_disabled": false,
"preferred_backend": "seedance",
"reason": "动漫风格,无真人素材限制"
},
"music": {
"enabled": true,
"source": "ai_generated",
"prompt": "音乐描述",
"style": "音乐风格"
},
"narration": {
"type": "ai_generated",
"voice_style": "温柔女声,语速适中",
"user_text": null
}
}visual_style = realistic 时的 backend_selection:
{
"visual_style": "realistic",
"backend_selection": {
"seedance_disabled": true,
"preferred_backend": "kling-omni",
"reason": "真人参考图会触发 Seedance content_policy_violation"
}
}visual_style 字段说明:
| 值 | 说明 | 用户照片处理 |
|---|---|---|
realistic |
真人写实风格 | Seedance 需先生成三视图转换,Kling-Omni 可直接使用 |
anime |
动漫/二次元风格 | 可直接作为参考图 |
mixed |
混合风格 | 真人场景照片需转换,动漫场景可直接使用 |
| type | 说明 | Phase 3 处理 |
|---|---|---|
none |
不需要旁白 | 不规划 narration_segments |
ai_generated |
AI 设计文案 | 根据分镜自动撰写旁白,按镜头分段 |
user_provided |
用户已有文案 | 将 user_text 按镜头时间点分段 |
Phase 3: 分镜设计
根据素材和创意方案生成分镜脚本。
分镜生成前强制阅读
在生成分镜脚本前,必须阅读以下三个文档:
Read: reference/storyboard-spec.md # T2V/I2V决策树、分镜规范、JSON格式
Read: reference/prompt-guide.md # Prompt编写规范、一致性要求
Read: reference/backend-guide.md # 后端选择决策树、参考图策略Step 1: 同步角色信息到 Storyboard
从 personas.json 同步到 storyboard.json:
from video_gen_tools import PersonaManager
manager = PersonaManager(project_dir)
# 生成 storyboard.json 的 elements.characters
characters = manager.export_for_storyboard()
# 生成 character_image_mapping
image_mapping = manager.get_character_image_mapping()
# 写入 storyboard.json
storyboard["elements"] = {"characters": characters}
storyboard["character_image_mapping"] = image_mapping同步后 storyboard.json 结构:
{
"elements": {
"characters": [
{
"element_id": "Element_SunWukong",
"name": "孙悟空",
"name_en": "SunWukong",
"reference_images": ["materials/personas/孙悟空_ref.png"],
"visual_description": "猴脸、金色毛发..."
}
]
},
"character_image_mapping": {
"Element_SunWukong": "image_1"
}
}Step 2: 自动后端选择逻辑
读取 Phase 2 真人检测结果:
首先读取 creative.json 的 backend_selection 字段:
- 若
seedance_disabled = true→ 强制使用 Kling-Omni,跳过场景分析 - 若无此字段 → 按场景需求选择后端
场景驱动选择:
| 场景 | 真人素材 | 优先后端 | 兜底后端 | 原因 |
|---|---|---|---|---|
| 虚构片/短剧 | 无(动漫) | Seedance | Kling-Omni | 智能切镜 + 多参考图 |
| 虚构片/短剧 | 有真人 | Kling-Omni | — | 真人素材禁用 Seedance |
| 广告片(无真实素材) | 无 | Seedance | Kling-Omni | 长镜头 + 智能切镜 |
| 广告片(有真实素材) | 有 | Kling-3.0 | — | 首帧精确控制,真实素材 |
| MV短片 | 无(动漫) | Seedance | Kling-Omni | 长镜头 + 音乐驱动 |
| MV短片 | 有真人 | Kling-Omni | — | 真人素材禁用 Seedance |
| Vlog/写实类 | 有 | Kling-3.0 | — | 首帧精确控制,不走 Seedance |
首帧控制能力对比:
| 后端 | 首帧控制 | 说明 |
|---|---|---|
| Kling-3.0 | ✅ --image |
视频从此图开始 |
| Seedance | ❌ 参考图 | 分镜图是视觉风格参考,不是首帧 |
| Kling-Omni | ❌ 参考图 | 只有 reference2video,无 img2video |
visual_style 只在「有用户真人照片 + 用 Seedance」时生效:
realistic→ 用户照片需先生成三视图转换anime→ 用户照片可直接使用- 纯创意模式下 visual_style 只影响 AI 参考图风格
核心原则(优先级从高到低):
- 真人素材检测 → 禁用 Seedance(顶层过滤)
- 同一项目使用同一模型
- 虚构片不使用 text2video
- 需要首帧控制时只能用 Kling
- Seedance/Omni 分镜图是参考,不是首帧精确控制
执行方式差异(关键):
| 后端 | 分镜图级别 | 执行方式 | 输出 |
|---|---|---|---|
| Seedance | scene-level | 一次 API 调用 | 1 个视频 |
| Kling-Omni | shot-level | 逐 shot 调用 | N 个视频片段 |
Kling-Omni 必须按 shot-level 执行:
- 每个 shot 生成分镜图:
generated/frames/{shot_id}_frame.png - 逐 shot 调用 API:
--image-list {shot_frame} {角色参考图} - 输出 N 个视频片段(后续拼接)
Step 3: 生成分镜
核心结构:Storyboard 采用 scenes[] → shots[] 两层结构。
关键设计原则:
时长设计(根据后端限制):
后端 Scene 总时长限制 设计策略 Seedance 4-15s(任意整数) scene 总时长 ≤15s 即可 Kling-Omni 3-15s(连续范围) scene 总时长 ≤15s 即可 Kling-3.0 3-15s(连续范围) 每个单独 shot ≤15s Vidu 5-10s 每个 shot 5-10s 总时长 = 目标时长(±2秒),单镜头 2-5 秒
同一分镜内最多 1 个动作,禁止空间变化
所有 video_prompt 必须包含比例信息
台词必须融入 video_prompt(角色 + 内容 + 情绪 + 声音)
根据 Step 2 的自动选择结果设置
generation_mode和reference_images
完整分镜规范:See reference/storyboard-spec.md
Prompt 编写与一致性规范:See reference/prompt-guide.md
生成分镜时同步处理旁白:
若 creative.narration.type 不为 none,则在生成分镜的同时规划旁白分段:
读取 narration 信息:
voice_style→ 写入narration_config.voice_styleuser_text(如有)→ 按镜头时间点分段
根据镜头内容设计旁白文案:
- 每段旁白对应一个镜头或一组连续镜头
- 每段控制在 2-5 秒可说完的长度(约 30-50 字)
规划时间点并写入 storyboard.json:
{
"narration_config": {
"voice_style": "温柔女声"
},
"narration_segments": [
{"segment_id": "narr_1", "overall_time_range": "0-3s", "text": "这是一个宁静的下午..."},
{"segment_id": "narr_2", "overall_time_range": "8-11s", "text": "她坐在窗边..."}
]
}旁白分段规范:See reference/storyboard-spec.md → 「旁白分段规划」
Step 4: 展示给用户确认(强制步骤)
必须在用户明确确认后才能进入 Phase 4!
展示每个镜头的:
- 场景信息
- 生成模式(text2video/img2video/omni-video)
- 后端选择
- video_prompt
- image_prompt(如有)
- reference_images(如有)
- 台词
- 转场
- 时长
若有旁白,额外展示:
- narration_segments 分段列表
- 每段的时间点、文案
提供选项:确认并执行 / 修改分镜 / 调整旁白 / 调整时长 / 更换转场 / 取消
Phase 3 产出
storyboard/storyboard.json— 分镜脚本(包含 generation_mode、reference_images、后端选择、narration_segments)
Phase 3.5: 一致性 Review(模型驱动)
位置:Phase 3 分镜设计完成后,Phase 4 执行前
原则:模型语义审查 → 自动修复 → 通知用户(无需用户确认)
核心理念
一致性问题需要语义理解,不是关键词匹配:
- "垂杨柳" → "枝条下垂的柳树" → "老树" 这种渐进漂移,关键词检测抓不到
- 模型能理解"黄昏"与"春日下午"的时间语义冲突
- 模型能判断"古树"是否在语义上偏离了"垂杨柳"
Review 前必须阅读
执行一致性 Review 前,必须阅读以下规范:
Read: reference/consistency-guide.md # 一致性原则详细规范审查原则概览
| 原则 | 检测范围 | 核心要求 |
|---|---|---|
| 时间光照一致性 | 同一 scene 内 | 光照描述必须与 time_state 语义一致 |
| 空间元素一致性 | 同一 scene 内 | 关键元素描述必须保持样式一致 |
| 人物妆造一致性 | 同一 scene 内 | 服装/发型/妆容必须锁定 |
| image/video 匹配 | 同一 shot 内 | 两个 prompt 对关键元素描述必须一致 |
| 跨 scene 连续性 | 连续的 scenes | 关键资产应保持视觉连续 |
Review 执行流程
Step 1:读取 storyboard.json
Step 2:构建 Review Prompt
使用以下 prompt 结构进行语义审查:
你是一致性审查员,负责检查 storyboard.json 的跨镜头一致性。
## 审查原则
### 1. 时间光照一致性
- 同一 scene 内所有 shot 的光照描述必须与 time_state 保持语义一致
- time_state="春日下午" 时,禁止出现:黄昏、傍晚、日落、sunset、夜晚
- 例外:如果剧情需要时间流逝,需在 narrative_goal 中说明
### 2. 空间元素一致性
- 同一 scene 内所有 shot 对关键元素的描述必须保持样式一致
- spatial_setting 提到"垂杨柳"时,禁止漂移为:枯树、古树、老树
- 不只要名称相同,还要样式描述一致(枝条形态、颜色等)
### 3. 人物妆造一致性
- 同一人物在同一 scene 内服装/发型必须锁定
- 检查所有 shot 对人物的服装描述是否与 locked_costume 或 visual_description 一致
- 跨 scene 换装需有剧情说明
### 4. image/video 描述匹配
- 同一 shot 的 image_prompt 和 video_prompt 对同一元素的描述必须一致
- 特别检查:场景元素、光照描述、人物服装
### 5. 跨 scene 资产连续性
- 连续的 scenes(spatial_setting 相似、时间相近)应保持资产一致
- 人物妆造默认锁定,除非有剧情换装说明
## 审查任务
请审查以下 storyboard.json,输出:
1. **问题列表**(格式:`[scene_id/shot_id] 问题类型:具体描述`)
2. **修复建议**(格式:`[scene_id/shot_id] 字段:原值 → 修复值`)
如果有问题,直接给出修复后的完整字段内容,我会自动应用。
---
{storyboard.json 内容}Step 3:模型分析
模型分析所有 shots,输出问题列表和修复建议。
Step 4:自动应用修复
根据模型输出的修复建议,直接修改 storyboard.json 中对应的字段。
Step 5:保存并通知
保存修复后的 storyboard.json,向用户输出审查结果。
Review 输出格式
📋 一致性审查结果
【发现问题】
1. [scene_1/scene1_shot2] 时间不一致:
- time_state: "春日下午,柔和阳光"
- Lighting: "黄昏光线" → 应为 "春日下午柔和阳光"
2. [scene_2/scene2_shot4] 空间漂移:
- spatial_setting: "垂杨柳树下"
- Scene 描述: "古树下" → 应为 "垂杨柳树下"
【修复已应用】
修复 scene_1/scene1_shot2 image_prompt Lighting 行:
原值: "黄昏光线,低角度逆光"
修复为: "春日下午柔和阳光,暖色调"
修复 scene_2/scene2_shot4 image_prompt Scene 行:
原值: "古树下,柳枝稀疏"
修复为: "垂杨柳树下,枝条细长下垂"
---
共发现 N 个一致性问题,已自动修复 storyboard.json无需用户确认
发现明显不一致问题时直接修复,修复后通知用户即可。用户如需调整可手动修改 storyboard.json。
Phase 4: 执行生成
根据 storyboard.json 执行视频生成。
Phase 4 执行前检查
0. Storyboard 校验(必须通过)
python video_gen_tools.py validate --storyboard storyboard/storyboard.json校验内容:Seedance 时长是否在 4-15s 范围、backend-mode 是否匹配、参考图是否存在、aspect_ratio 格式、API key 是否可用。
- 有 ERROR → 必须修复后再继续
- 只有 WARNING → 可继续,但需关注
1. 参考图尺寸检查
- 从 storyboard.json 读取每个镜头的
reference_images - 检测所有参考图尺寸
- 最小边 < 720px → 自动放大到 1280px
- 最大边 > 2048px → 自动缩小到 2048px
- 自动生成调整后的图片(添加
_resized后缀)
2. 参数校验
- 从 storyboard.json 读取
aspect_ratio字段,传递给 CLI 的--aspect-ratio参数 - 根据 storyboard 的
audio配置设置 API 参数(详见 prompt-guide.md)
Phase 4 启动前检查:Storyboard 链路一致性
时机:每次启动第一个视频生成任务之前
检测逻辑:检查 storyboard 是否按当前选择的模型链路撰写
| 后端 | 必须满足的条件 | 错误提示 |
|---|---|---|
| Seedance | scene-level 分镜图(scene_1_frame.png),无 shot-level 分镜 | 无特殊要求 |
| Kling-Omni | 每个 shot 有 image_prompt 和 frame_path | 缺少 shot-level 分镜结构 |
| Kling img2video | 每个 shot 有 frame_path,frame_strategy = first_frame_only | 缺少首帧图 |
Kling-Omni 链路一致性检查:
# 检查每个 shot 是否有 shot-level 分镜结构
for shot in shots:
if backend == "kling-omni":
# 必须有 image_prompt(用于生成分镜图)
if not shot.get("image_prompt"):
errors.append(f"[{shot_id}] Kling-Omni 必须有 image_prompt")
# 必须有 frame_path(分镜图输出路径)
if not shot.get("frame_path"):
errors.append(f"[{shot_id}] Kling-Omni 必须有 frame_path")
# 检查是否误用 Seedance scene 分镜图
ref_images = shot.get("reference_images", [])
if ref_images and "_frame" in ref_images[0]:
if "shot_" not in ref_images[0]:
warnings.append(f"[{shot_id}] 可能使用 Seedance scene 分镜图,需 shot-level")检测不通过 → 回退 Phase 3 改写 storyboard:
检查 storyboard → backend = kling-omni 但无 shot-level 分镜结构?
↓ 是(有 ERROR)
告知用户 → 回退 Phase 3:
⚠️ Storyboard 结构与 Kling-Omni 链路不一致。
缺少 shot-level 分镜图(image_prompt、frame_path)。
需要回退 Phase 3 按 shot-level 改写 storyboard。
↓
回退 Phase 3 → 改写 storyboard:
1. 为每个 shot 设计 image_prompt
2. 为每个 shot 指定 frame_path
3. 生成 shot-level 分镜图
↓
重新检查 storyboard → 通过 → 启动视频生成重要:此检查在 validate_storyboard 之后执行,validate 通过不代表链路结构正确。
执行规则
- 首次 API 调用单独执行,确认成功后再并发
- 并发不超过 3 个 API 生成调用
- 实时更新 state.json 记录进度
- 失败时重试 最多 2 次,然后询问用户
API 错误处理与降级
当 API 调用失败时,按错误类型处理:
| 错误类型 | 处理方式 |
|---|---|
| 429 并发限制 | 询问用户:等待重试 或 降级到 Path B |
| 402 余额不足 | 告知用户充值,或降级到其他可用后端 |
| 网络超时 | 重试 2 次,失败后询问 |
| 其他错误 | 记录错误详情,询问用户 |
降级决策流程:
API 失败 → 判断错误类型 →
├── 429/402(资源限制)→ 询问用户降级
│ ├── 用户选择等待 → 等待 60s 后重试
│ ├── 用户选择降级 → 执行降级流程(见下文)
│ └── 用户选择取消 → 停止生成
└── 其他错误 → 重试 2 次 → 失败后询问用户降级执行流程(Seedance → Omni 或 Path A → Path B):
Seedance 失败处理(必须先重试):
- 第一次失败 → 重试一次(相同参数,等待 30s)
- 重试仍失败 → 告知用户并询问降级选项:
Seedance 生成失败(已重试 1 次)。 可选方案: A. 降级到 Kling-Omni(失去智能切镜,需手动 multi-shot) B. 修改 prompt 后再次尝试 Seedance C. 取消本次生成 请选择: - 用户选择 A → 执行降级流程
Seedance → Omni:
- 告知用户降级后果(失去智能切镜,需重新按 shot-level 执行)
- 重新走完整的 Kling-Omni 流程(不做复杂的字段迁移):
- 保留 storyboard 的创意设计(风格、时长、角色等)
- 按 Omni shot-level 标准重新规划分镜:为每个 shot 设计
image_prompt、frame_path - 先为每个 shot 生成分镜图(Gemini 图片生成)
- 再逐 shot 调用 Kling-Omni API
- 详见 reference/backend-guide.md → "Seedance → Kling-Omni 降级流程"
Omni → Kling img2video:
- 告知用户降级后果(角色一致性会降低)
- 修改 storyboard.json 的生成模式字段
- 先生成所有分镜图(使用 Gemini)
- 用分镜图作为首帧调用 Kling img2video
降级详细规范:See reference/backend-guide.md → "API 限制时的降级策略"
生成模式强制执行
必须严格按照 storyboard.json 执行,禁止擅自更改:
| generation_mode | CLI 参数 |
|---|---|
seedance-video |
--backend seedance --aspect-ratio {aspect_ratio} --image-list {frame} {ref1} {ref2} ... |
omni-video |
--backend kling-omni --aspect-ratio {aspect_ratio} --image-list {frame} {ref1} {ref2} ... |
img2video |
--aspect-ratio {aspect_ratio} --image {frame_path} |
text2video |
--aspect-ratio {aspect_ratio} |
重要:{aspect_ratio} 从 storyboard.json 的 aspect_ratio 字段读取。
示例(Seedance 模式):
# Seedance 智能切镜:分镜图 + 角色参考图
python video_gen_tools.py video \
--backend seedance \
--aspect-ratio 16:9 \
--prompt "Referencing the scene1_frame composition... @image1..." \
--image-list generated/frames/scene1_frame.png materials/personas/xiaomei_ref.jpg \
--duration 10 \
--output generated/videos/scene1.mp4示例(Omni 模式):
# Omni 最佳实践:分镜图 + 角色参考图
python video_gen_tools.py video \
--backend kling-omni \
--aspect-ratio {aspect_ratio} \
--prompt "Referencing scene1_shot1_frame composition. 孙悟空挥舞金箍棒,<<<image_1>>>..." \
--image-list generated/frames/scene1_shot1_frame.png materials/personas/sunwukong_ref.png \
--audio \
--output generated/videos/scene1_shot1.mp4Seedance 执行逻辑(自动组装模式)
当 generation_backend = "seedance" 时,使用 --scene 参数自动组装时间分段 prompt。
工具会自动完成:时间分段计算、prompt 格式拼装、image_urls 排列、duration 校验(4-15s 范围)。
执行步骤
Step 1: 生成分镜图
- 每个 Seedance scene 生成一张分镜图
- 使用 Gemini + 角色参考图生成
- 保存到
generated/frames/{scene_id}_frame.png
Step 2: 调用自动组装
python video_gen_tools.py video \
--backend seedance \
--storyboard storyboard/storyboard.json \
--scene scene_1 \
--output generated/videos/scene_1.mp4工具内部自动:
- 读取 scene 的 shots,计算时间偏移量,拼装时间分段 prompt
- 从
character_image_mapping解析角色参考图顺序 - 组装
image_urls(分镜图在前,角色参考图在后) - 总时长在 4-15s 范围内任意整数即可
关键:确保分镜图路径已填入 shot 的 reference_images,且 video_prompt 包含运镜 + 节奏描述。
手动模式(兜底)
自动组装不满足需求时,仍可手动指定 prompt:
python video_gen_tools.py video \
--backend seedance \
--prompt "手动编写的时间分段 prompt..." \
--image-list frame.png ref.jpg \
--duration 10 \
--output output.mp4API Key 管理
首次调用时检查并请求 API key,用户提供后通过 export 设置。
工具调用详细参数:See reference/api-reference.md
音乐生成
调用 video_gen_tools.py music 必须传 --creative 参数。
原因:从 creative.json 的 music 字段读取 prompt(音乐描述)和 style(音乐风格),避免使用默认风格。
旁白生成(条件触发)
触发条件:读取 storyboard.json 的 narration_segments,若存在则触发。
TTS 后端优先级:ElevenLabs TTS > Gemini TTS
生成流程:
- 读取 narration_config 和 narration_segments
- 按分段逐个调用 TTS:
# ElevenLabs TTS(默认,高质量)
python video_gen_tools.py tts \
--text "这是一个宁静的下午..." \
--voice female_narrator \
--video-type documentary \
--output generated/narration/narr_1.mp3
# 使用已有 voice_id(跳过 Design/Create,更快)
python video_gen_tools.py tts \
--text "她坐在窗边..." \
--voice-id "abc123xyz" \
--output generated/narration/narr_2.mp3
# 强制使用 Gemini TTS(兜底)
python video_gen_tools.py tts \
--text "思绪飘向远方..." \
--backend gemini \
--voice female_narrator \
--output generated/narration/narr_3.mp3voice 参数映射:
| 参数值 | ElevenLabs 音色 | Gemini 音色(兜底) |
|---|---|---|
female_narrator |
创建新声音(专业女声) | Kore |
female_gentle |
内置 Alice(温柔) | Aoede |
female_bright |
内置 Charlotte(明亮) | Leda |
male_narrator |
内置 George(专业男声) | Charon |
male_warm |
内置 Adam(温暖) | Orus |
stability 参数(仅 ElevenLabs):
| 视频类型 | Stability | 说明 |
|---|---|---|
| cinematic | 0.22 | 戏剧角色,高表现力 |
| vlog | 0.28 | 情感叙事,平衡稳定 |
| documentary | 0.35 | 专业解说,稳定输出 |
| commercial | 0.30 | 广告片,稳定但灵活 |
文本增强(ElevenLabs 自动执行):
自动插入情感/节奏/生理标签,不改写原文用词:
- 情感:
[thoughtful],[excited],[calm] - 节奏:
[short pause],[slows down],[emphasized] - 生理:
[sighs],[exhales]
降级机制:
- ElevenLabs 失败时自动降级到 Gemini TTS
- 返回结果中标注
backend: gemini_fallback
- 输出文件命名:按
segment_id命名(narr_1.mp3,narr_2.mp3...)
执行顺序:
视频片段生成 → 音乐生成 → 旁白生成(如有)→ 进入 Phase 5 剪辑Phase 4 产出
generated/videos/*.mp4— 生成的视频片段generated/music/*.mp3— 生成的背景音乐(如有)generated/narration/*.mp3— 生成的旁白音频(如有)- 更新
state.json— 记录生成进度
Phase 5: 剪辑输出
视频拼接
调用 video_gen_editor.py concat 必须传 --storyboard 参数。
原因:从 storyboard.json 读取 aspect_ratio,确保输出视频比例正确。
音频保护
视频片段可能包含同期声、音效,拼接时不能丢失。无声片段会自动补静音轨,确保音画同步。
视频参数校验
拼接前自动检查分辨率/编码/帧率,不一致时自动归一化(1080x1920 / H.264 / 24fps)。
python video_gen_editor.py concat --inputs video1.mp4 video2.mp4 --output final.mp4合成流程
- 拼接 → 按分镜顺序连接(自动归一化)
- 插入旁白 → 智能合成旁白音频(自动测量时长、计算不重叠时间点)
- 转场 → 添加镜头间转场效果
- 调色 → 应用整体调色风格
- 配乐 → 混合背景音乐
- 输出 → 生成最终视频
音频混音规则
核心原则:FFmpeg amix 滤镜必须使用 normalize=0,防止自动均一化导致音量被压低。
音量推荐值(根据视频类型灵活调整):
| 音频类型 | 推荐音量 | 说明 |
|---|---|---|
| 视频环境声/同期声 | 0.8 | 保留原始音频氛围 |
| 旁白/解说 | 1.5-2.0 | 确保人声清晰 |
| 背景音乐(BGM) | 0.1-0.15 | 背景衬托角色 |
视频类型适配:
| 视频类型 | BGM音量 | 原因 |
|---|---|---|
| Vlog/纪录片 | 0.1-0.15 | 旁白为主 |
| 电影感/虚构片 | 0.2-0.3 | 音乐烘托情绪 |
| 音乐MV | 0.5-0.7 | 音乐是核心元素 |
| 广告片 | 0.15-0.25 | 平衡产品介绍与音乐 |
FFmpeg amix 语法:
# 关键:normalize=0 保留原始音量比例
"[track1][track2]amix=inputs=2:duration=first:normalize=0[out]"实现说明:video_gen_editor.py 的 mix_audio() 函数已硬编码 normalize=0(约第 470 行)。
旁白插入(条件触发)
触发条件:读取 storyboard.json 的 narration_segments,若存在则触发。
插入方式:使用 FFmpeg 智能合成旁白音频,自动计算时间点避免重叠。
# 智能旁白合成(自动测量音频时长,避免重叠)
python video_gen_editor.py smart-narration \
--video concat_output.mp4 \
--storyboard storyboard/storyboard.json \
--narration-dir generated/narration \
--output with_narration.mp4时间点计算:
- 使用 ffprobe 测量每段旁白音频的实际时长
- 自动计算不重叠的时间点,预留间隔(默认 0.5 秒)
- 若空间紧张会动态压缩间隔
Phase 5 产出
output/final.mp4— 最终视频
工具调用速查
# 环境检查
python video_gen_tools.py check
# Storyboard 校验(Phase 4 执行前必须通过)
python video_gen_tools.py validate --storyboard storyboard/storyboard.json
# 视频生成(必须从 storyboard.json 读取 aspect_ratio)
python video_gen_tools.py video --prompt <描述> --aspect-ratio {aspect_ratio} --output <输出>
# Seedance 自动组装模式(推荐:工具自动计算时间分段、拼装 prompt、排列 image_urls)
python video_gen_tools.py video \
--backend seedance \
--storyboard storyboard/storyboard.json \
--scene scene_1 \
--output generated/videos/scene_1.mp4
# Seedance 手动模式(兜底)
python video_gen_tools.py video \
--backend seedance \
--prompt "手动编写的时间分段 prompt..." \
--image-list frame.png ref.jpg \
--duration 10 \
--output output.mp4
# 音乐(必须传 --creative,从 creative.json 读取 prompt 和 style)
python video_gen_tools.py music --creative creative/creative.json --output <输出>
# 旁白(ElevenLabs 优先,Gemini 兜底)
python video_gen_tools.py tts --text <分段文案> --voice female_narrator --video-type documentary --output generated/narration/narr_1.mp3
# 旁白(使用已有 voice_id)
python video_gen_tools.py tts --text <分段文案> --voice-id <voice_id> --output generated/narration/narr_2.mp3
# 旁白(强制 Gemini)
python video_gen_tools.py tts --text <分段文案> --backend gemini --voice female_narrator --output generated/narration/narr_3.mp3
# 图片生成
python video_gen_tools.py image --prompt <描述> --aspect-ratio {aspect_ratio} --output <输出>
# 剪辑(concat 必须传 --storyboard,从 storyboard.json 读取 aspect_ratio)
python video_gen_editor.py concat --inputs <视频列表> --output <输出> --storyboard storyboard/storyboard.json
# 智能旁白合成(自动测量音频时长,避免重叠)
python video_gen_editor.py smart-narration --video <视频> --storyboard storyboard/storyboard.json --narration-dir generated/narration --output <输出>
# 其他剪辑命令
python video_gen_editor.py mix --video <视频> --bgm <音乐> --output <输出>
python video_gen_editor.py transition --inputs <v1> <v2> --type <类型> --output <输出>
python video_gen_editor.py color --video <视频> --preset <预设> --output <输出>文件结构
~/video-gen-projects/{project_name}_{timestamp}/
├── state.json # 项目状态
├── materials/ # 原始素材
│ └── personas/ # 角色参考图(Phase 2 生成)
├── analysis/
│ └── analysis.json # 素材分析
├── creative/
│ ├── creative.json # 创意方案
│ └── decision_log.json # 决策记录
├── storyboard/
│ └── storyboard.json # 分镜脚本(含 narration_segments)
├── generated/
│ ├── videos/ # 生成的视频
│ ├── music/ # 生成的音乐
│ ├── narration/ # 生成的旁白音频
│ └── image/ # 生成的图片
└── output/
└── final.mp4 # 最终视频错误处理
| 问题 | 处理方式 |
|---|---|
| 视觉分析失败 | VisionClient fallback → 询问用户 |
| API key 未配置 | 首次调用时询问 |
| API 调用失败 | 重试 2 次 → 询问用户 |
| 视频生成失败 | 尝试其他模式或用原始素材 |
| 音乐生成失败 | 生成静音视频并告知 |
依赖
- FFmpeg 6.0+
- Python 3.9+
- httpx