taylorzhou16

video-gen

AI视频剪辑工具。分析素材、生成创意、设计分镜、执行剪辑。支持Vidu/Kling/Kling Omni视频生成、Suno音乐生成、TTS配音、FFmpeg剪辑。当用户要求制作视频、剪辑视频、生成视频、创建短片、或提供素材目录要求生成作品时触发。

taylorzhou16 8 3 Updated 1mo ago

Resources

9
GitHub

Install

npx skillscat add taylorzhou16/video-gen

Install via the SkillsCat registry.

SKILL.md

video-gen 使用指南

角色:Director Agent — 理解创作意图、协调所有资源、交付视频作品。

语言要求:所有回复必须使用中文。


推荐配置

建议使用多模态模型(如 Claude Opus/Sonnet/Kimi-K2.5)以获得最佳体验。

非多模态模型会自动调用视觉模型进行图片分析,在 config.json 中配置 VISION_BASE_URLVISION_MODELVISION_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 也失败 → 主动询问用户描述每张素材内容。

人物识别(条件性)

仅当用户提供了人物肖像图时触发(不确定时询问用户)。

执行步骤:

  1. 读取图片内容,识别所有人物
  2. 询问用户确认每个人物的身份
  3. 使用 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.png

C. 上传单张参考图(不推荐):

  • 请用户上传图片
  • 保存到 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.jsonbackend_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 参考图风格

核心原则(优先级从高到低):

  1. 真人素材检测 → 禁用 Seedance(顶层过滤)
  2. 同一项目使用同一模型
  3. 虚构片不使用 text2video
  4. 需要首帧控制时只能用 Kling
  5. Seedance/Omni 分镜图是参考,不是首帧精确控制

执行方式差异(关键)

后端 分镜图级别 执行方式 输出
Seedance scene-level 一次 API 调用 1 个视频
Kling-Omni shot-level 逐 shot 调用 N 个视频片段

Kling-Omni 必须按 shot-level 执行

  1. 每个 shot 生成分镜图:generated/frames/{shot_id}_frame.png
  2. 逐 shot 调用 API:--image-list {shot_frame} {角色参考图}
  3. 输出 N 个视频片段(后续拼接)

Step 3: 生成分镜

核心结构:Storyboard 采用 scenes[] → shots[] 两层结构。

关键设计原则

  1. 时长设计(根据后端限制)

    后端 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秒),单镜头 2-5 秒

  3. 同一分镜内最多 1 个动作,禁止空间变化

  4. 所有 video_prompt 必须包含比例信息

  5. 台词必须融入 video_prompt(角色 + 内容 + 情绪 + 声音)

  6. 根据 Step 2 的自动选择结果设置 generation_modereference_images

完整分镜规范:See reference/storyboard-spec.md
Prompt 编写与一致性规范:See reference/prompt-guide.md

生成分镜时同步处理旁白

creative.narration.type 不为 none,则在生成分镜的同时规划旁白分段:

  1. 读取 narration 信息

    • voice_style → 写入 narration_config.voice_style
    • user_text(如有)→ 按镜头时间点分段
  2. 根据镜头内容设计旁白文案

    • 每段旁白对应一个镜头或一组连续镜头
    • 每段控制在 2-5 秒可说完的长度(约 30-50 字)
  3. 规划时间点并写入 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 通过不代表链路结构正确。


执行规则

  1. 首次 API 调用单独执行,确认成功后再并发
  2. 并发不超过 3 个 API 生成调用
  3. 实时更新 state.json 记录进度
  4. 失败时重试 最多 2 次,然后询问用户

API 错误处理与降级

当 API 调用失败时,按错误类型处理:

错误类型 处理方式
429 并发限制 询问用户:等待重试 或 降级到 Path B
402 余额不足 告知用户充值,或降级到其他可用后端
网络超时 重试 2 次,失败后询问
其他错误 记录错误详情,询问用户

降级决策流程

API 失败 → 判断错误类型 →
  ├── 429/402(资源限制)→ 询问用户降级
  │     ├── 用户选择等待 → 等待 60s 后重试
  │     ├── 用户选择降级 → 执行降级流程(见下文)
  │     └── 用户选择取消 → 停止生成
  └── 其他错误 → 重试 2 次 → 失败后询问用户

降级执行流程(Seedance → Omni 或 Path A → Path B):

Seedance 失败处理(必须先重试):

  1. 第一次失败 → 重试一次(相同参数,等待 30s)
  2. 重试仍失败 → 告知用户并询问降级选项:
    Seedance 生成失败(已重试 1 次)。
    
    可选方案:
    A. 降级到 Kling-Omni(失去智能切镜,需手动 multi-shot)
    B. 修改 prompt 后再次尝试 Seedance
    C. 取消本次生成
    
    请选择:
  3. 用户选择 A → 执行降级流程

Seedance → Omni

  1. 告知用户降级后果(失去智能切镜,需重新按 shot-level 执行)
  2. 重新走完整的 Kling-Omni 流程(不做复杂的字段迁移):
    • 保留 storyboard 的创意设计(风格、时长、角色等)
    • 按 Omni shot-level 标准重新规划分镜:为每个 shot 设计 image_promptframe_path
    • 先为每个 shot 生成分镜图(Gemini 图片生成)
    • 再逐 shot 调用 Kling-Omni API
  3. 详见 reference/backend-guide.md → "Seedance → Kling-Omni 降级流程"

Omni → Kling img2video

  1. 告知用户降级后果(角色一致性会降低)
  2. 修改 storyboard.json 的生成模式字段
  3. 先生成所有分镜图(使用 Gemini)
  4. 用分镜图作为首帧调用 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.jsonaspect_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.mp4

Seedance 执行逻辑(自动组装模式)

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

工具内部自动:

  1. 读取 scene 的 shots,计算时间偏移量,拼装时间分段 prompt
  2. character_image_mapping 解析角色参考图顺序
  3. 组装 image_urls(分镜图在前,角色参考图在后)
  4. 总时长在 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.mp4

API Key 管理

首次调用时检查并请求 API key,用户提供后通过 export 设置。

工具调用详细参数:See reference/api-reference.md

音乐生成

调用 video_gen_tools.py music 必须传 --creative 参数。

原因:从 creative.jsonmusic 字段读取 prompt(音乐描述)和 style(音乐风格),避免使用默认风格。

旁白生成(条件触发)

触发条件:读取 storyboard.jsonnarration_segments,若存在则触发。

TTS 后端优先级:ElevenLabs TTS > Gemini TTS

生成流程

  1. 读取 narration_config 和 narration_segments
  2. 按分段逐个调用 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.mp3

voice 参数映射

参数值 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
  1. 输出文件命名:按 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

合成流程

  1. 拼接 → 按分镜顺序连接(自动归一化)
  2. 插入旁白 → 智能合成旁白音频(自动测量时长、计算不重叠时间点)
  3. 转场 → 添加镜头间转场效果
  4. 调色 → 应用整体调色风格
  5. 配乐 → 混合背景音乐
  6. 输出 → 生成最终视频

音频混音规则

核心原则: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.pymix_audio() 函数已硬编码 normalize=0(约第 470 行)。

旁白插入(条件触发)

触发条件:读取 storyboard.jsonnarration_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