feat(video-from-script): 重构工作流为子Agent分步执行并新增提示词模板系统

将视频制作工作流拆分为独立子步骤:分镜 → 图片提示词 → 生图 → 视频提示词 → 生视频 → 成片,每步由子Agent独立执行。引入prompts/目录统一管理提示词模板(分镜.md、图片提示词.md、视频提示词.md),通过account.json的storyboardPrompt/imageStylePrompt/videoStylePrompt字段引用。

变更内容:
- 新增confirmed机制和pipeline.js confirm命令,生图后必须人工确认才能继续
- manifest schema改用shotDesc/narration/duration/directorRef替代旧字段
- 文件命名规则从keyword改为slug(从shotDesc/narration派生)
- 删除旧的storyboard-rules.md和prompt-rules.md
- pipeline.js脚本拆分为lib/目录下的独立模块(cmd-init/cmd-confirm/cmd-validate/phase-*)
- 新增cmd-create-account支持一键创建带prompts目录的账号
- capcut_assemble支持narration字段替代text作为字幕源
- 新增.gitclaude/settings.json权限配置
This commit is contained in:
2026-04-30 21:18:31 +08:00
parent 7f955647fe
commit 86b9b7948d
32 changed files with 2826 additions and 1292 deletions

View File

@@ -11,12 +11,18 @@
accounts/ # 项目根目录下
├── _template/ # 新账号模板(复制此目录创建新账号)
│ ├── account.json
│ ├── prompts/ # 提示词模板目录(子 Agent 系统提示词)
│ │ └── .gitkeep
│ ├── references/ # 参考图目录
│ │ └── .gitkeep
│ └── styles/ # 风格文件目录(可多个)
│ └── .gitkeep
└── {account}/ # 用户创建的账号(目录名 = account.json 的 id输出目录用 name 命名)
├── account.json
├── prompts/ # 提示词模板(账号专属)
│ ├── 分镜.md # 口播文案 → 分镜表
│ ├── 图片提示词.md # shotDesc → imagePrompt
│ └── 视频提示词.md # shotDesc → videoPrompt
├── references/ # 参考图(所有风格共用)
│ ├── ref_001.png
│ └── ref_002.png
@@ -38,6 +44,9 @@ accounts/ # 项目根目录下
"imageModel": "gemini",
"videoModel": "kling",
"batchSize": 30,
"storyboardPrompt": "prompts/分镜.md",
"imageStylePrompt": "prompts/图片提示词.md",
"videoStylePrompt": "prompts/视频提示词.md",
"capcut": {
"effects": ["录制边框 III"],
"filter": "电影感:40",
@@ -61,6 +70,9 @@ accounts/ # 项目根目录下
| `imageModel` | string | 默认图片模型 |
| `videoModel` | string | 默认视频模型 |
| `batchSize` | number | 默认批量生成数量 |
| `storyboardPrompt` | string | 分镜提示词模板路径(相对于账号目录) |
| `imageStylePrompt` | string | 图片提示词模板路径(相对于账号目录) |
| `videoStylePrompt` | string | 视频提示词模板路径(相对于账号目录) |
| `capcut.effects` | string[] | CapCut 特效名称列表 |
| `capcut.filter` | string | CapCut 滤镜,格式 "名称:强度" |
| `capcut.subtitleStyle` | object | 字幕样式(字号、颜色、高亮色、加粗) |
@@ -68,66 +80,50 @@ accounts/ # 项目根目录下
---
## 提示词模板prompts/
每个账号在 `prompts/` 目录下维护三个子 Agent 提示词模板:
| 文件 | 用途 | Step |
|------|------|------|
| `分镜.md` | 口播文案 → 分镜表shotDesc/narration/duration/directorRef | Step 1 |
| `图片提示词.md` | shotDesc + directorRef → imagePrompt | Step 2-A |
| `视频提示词.md` | shotDesc + directorRef → videoPrompt | Step 3-A |
这些文件定义了子 Agent 的角色、入参、出参、词库和示例。路径在 account.json 中以相对路径引用Agent 读取 account.json 后自动定位。
### 与 style 文件的关系
- **prompts/** — 子 Agent 的系统提示词(定义 HOW 生成提示词)
- **styles/** — 视觉规则参考(定义 WHAT 风格应该长什么样:颜色、构图、禁止项)
- prompts 模板内部会引用 styles 中定义的色彩体系、构图规则等
---
## 风格文件styles/
每种视觉风格一个文件,文件名即风格名。文件内同时包含图片和视频的提示词策略
每种视觉风格一个文件,文件名即风格名。文件内包含视觉规则参考
### 风格文件结构
```markdown
# 风格名称(英文短横线命名)
# 风格名称
一句话描述风格。
---
## 图片提示词
### 核心视觉要素
<!-- 必选的视觉元素 -->
### 场景/背景规则
<!-- 背景要求 -->
## 核心视觉要素
### 色调方案
<!-- 可选的色彩组合 -->
### 构图模式
<!-- 支持的构图类型 -->
### 图片 Prompt 模板
<!-- 生成 prompt 时的固定结构 -->
### 示例
<!-- 2-3 个完整示例 -->
### MJ/Gemini 参数
<!-- 模型专用后缀参数 -->
### 模型参数(MJ/Gemini/Kling
### 图片禁止项
<!-- 不得出现的元素 -->
---
## 视频提示词
### 运镜规则
<!-- 运镜方式、节奏 -->
### 动态元素要求
<!-- 光影、角色动作、环境氛围 -->
### 视频 Prompt 模板
<!-- VEO/Grok prompt 结构 -->
### 示例
<!-- 2-3 个完整示例 -->
### VEO/Grok 后缀
<!-- 模型专用后缀 -->
### 视频禁止项
<!-- 不得出现的元素 -->
### 禁止项
```
### 风格文件命名
@@ -158,12 +154,13 @@ node scripts/pipeline.js create-account \
### 手动创建
1. 复制 `_template/` 目录,重命名为账号 ID
2. 编辑 `account.json` 填写账号信息
3.`references/` 中放入参考图(所有风格共用
4. 上传参考图到 OSSURL 写入 account.json
2. 编辑 `account.json` 填写账号信息(含 prompts 路径)
3.`prompts/` 中放入提示词模板(从 `工作流程/` 草稿区复制
4. `references/` 中放入参考图(所有风格共用)
5. 上传参考图到 OSSURL 写入 account.json
- `node scripts/oss-upload.js ../../accounts/{id}/references/{图片文件}`
- 将返回的 URL 写入 `styles.{styleName}.references[].url`
5.`styles/` 中创建风格文件(至少一个)
6.`styles/` 中创建风格文件(至少一个)
### 校验账号
@@ -171,7 +168,7 @@ node scripts/pipeline.js create-account \
node scripts/pipeline.js validate-account --account military
```
检查id 匹配、必填字段、参考图完整性、风格文件存在、OSS URL 有效。
检查id 匹配、必填字段、prompts 模板存在、参考图完整性、风格文件存在、OSS URL 有效。
## 添加新风格

View File

@@ -2,19 +2,23 @@
> `pipeline.js init` 创建Pipeline 执行Agent 审查。
>
> **禁止 AI 手写 manifest.json**,必须通过 `pipeline.js init` 初始化。脚本从 account.json 自动继承结构字段AI 只提供创意内容items 的 text/imagePrompt/videoPrompt/keyword)。
> **禁止 AI 手写 manifest.json**,必须通过 `pipeline.js init` 初始化。脚本从 account.json 自动继承结构字段AI 只提供创意内容items 的 shotDesc/narration/imagePrompt 等)。
---
## 创建方式
```bash
# AI 生成创意内容后,通过脚本初始化
node pipeline.js init --account military --mode single \
--items '[{"text":"中文文案","imagePrompt":"English prompt","videoPrompt":"motion prompt","keyword":"关键词","keywordColor":"#FF6B35"}]'
# Step 2-A 生成 imagePrompt 后,通过脚本初始化(不含 videoPrompt
node pipeline.js init --account 军事账号 --mode single \
--items '[{"shotDesc":"英文画面描述","narration":"中文口播旁白","duration":5,"imagePrompt":"English prompt","directorRef":"tarantino"}]'
# 或从文件读取
node pipeline.js init --account military --mode single --items-file ./items.json
node pipeline.js init --account 军事账号 --mode single --items-file ./items.json
# Step 2-C 人工确认
node pipeline.js confirm --manifest <path> --all
node pipeline.js confirm --manifest <path> --items 1,3,5
# 校验已有 manifest
node pipeline.js validate --manifest <path>
@@ -53,11 +57,18 @@ node pipeline.js validate --manifest <path>
| 字段 | 说明 |
|------|------|
| `status` | 固定写 `"pending"` |
| `text` | 中文字幕文案 |
| `imagePrompt` | 英文画面描述(给 Gemini/MJ |
| `videoPrompt` | 英文运动描述(给 Grok/VEO描述镜头运动而非内容 |
| `keyword` | 字幕高亮关键词 |
| `keywordColor` | 高亮颜色 |
| `shotDesc` | 英文分镜描述含隐性动势40-80词 |
| `narration` | 中文口播旁白≤22字 |
| `duration` | 计划视频时长(秒),来自分镜阶段 |
| `imagePrompt` | 英文画面描述(给 Gemini/MJStep 2-A 生成 |
| `directorRef` | 导演构图参考tarantino / kitano / fincher三层透传 |
| `confirmed` | 人工确认状态,默认 `false` |
### Agent 后续回写Step 3-A 视频提示词)
| 字段 | 说明 | 写入时机 |
|------|------|---------|
| `videoPrompt` | 英文运动描述(给 Grok/VEO描述镜头运动而非内容 | Step 3-A 由 Agent 回写 |
### Pipeline 回写(执行后)
@@ -67,17 +78,19 @@ node pipeline.js validate --manifest <path>
| `file` | 生成的图片路径(相对 manifest | images |
| `candidates` | MJ 拆分的 4 张候选图路径Gemini 无此字段) | images |
| `url` | 图片 OSS 公网 URL | upload |
| `confirmed` | 人工确认后设为 `true` | confirm |
| `video` | 生成的视频路径 | videos |
| `videoDuration` | 视频时长Grok=6, VEO=8 | videos |
| `videoUrl` | 视频 OSS 公网 URL | videos |
| `audio` | TTS 音频路径 | tts |
| `duration` | 音频时长(秒) | tts |
| `audioDuration` | 音频时长(秒) | tts |
### Agent 审查时可操作
- MJ 换选:`item.file = item.candidates[2]`
- 删除不合格 item直接从 items 数组移除,重新跑 `--phase images`
- 调整 prompt 重跑:改 `imagePrompt`status 改回 `pending`
- 人工确认:`node pipeline.js confirm --manifest <path> --all`
---
@@ -86,9 +99,9 @@ node pipeline.js validate --manifest <path>
### item 生命周期
```
pending → [images] → done → [upload: url填入] → done → [videos] → done → [tts] → done
↓ ↓
failed failed + error
pending → [images] → done → [confirm] → confirmed=true → [upload: url填入] → [videos] → done → [tts] → done
failed failed + error
```
status 一旦进入 `done` 就不再回退。后续阶段通过检查"有前置字段 + 无后置字段"来识别待处理 item不依赖 status 变化。
@@ -101,8 +114,8 @@ Agent **不需要记住这些条件**pipeline 内部自动匹配。仅供理
|------|------------------|
| images | `status=pending` + 有 `imagePrompt` |
| upload | `status=done` + 有 `file` + 无 `url` |
| videos | `status=done` + 有 `url` + 有 `videoPrompt` + 无 `video` |
| tts | `status=done` + 有 `text` + 无 `audio` |
| videos | `status=done` + `confirmed=true` +`url` + 有 `videoPrompt` + 无 `video` |
| tts | `status=done` + 有 `narration`(回退 `text` + 无 `audio` |
### pipeline.phases 整体状态
@@ -180,7 +193,9 @@ node pipeline.js run --manifest <path> --retry-failed
```
output/{account}_{YYYYMMDD}_{NNN}/
├── manifest.json # 主清单
├── images/ # scene_{NN}_{keyword}.jpeg首尾帧加 _lastMJ 候选加 _cand{1-4}
├── videos/ # scene_{NN}_{keyword}.mp4
├── images/ # scene_{NN}_{slug}.jpeg首尾帧加 _lastMJ 候选加 _cand{1-4}
├── videos/ # scene_{NN}_{slug}.mp4
└── audio/ # seg_001.mp3
```
slug 从 `shotDesc` 派生slugify: 保留中文和字母数字,最多 20 字符)。

View File

@@ -1,54 +0,0 @@
# 提示词生成规则
**前置条件**:账号必须有风格文件。无风格 → 提醒用户创建,不跳过。
**输入**:分镜表 + style.md + account.json
**输出**:每个 shot 生成 imagePrompt / videoPrompt / keyword / keywordColor英文
## 单图模式提示词
每条文案生成:
- `imagePrompt`:画面描述(英文,给 Gemini/MJ/Kling
- `videoPrompt`:运动描述(英文,给 Grok/VEO/Kling
### imagePrompt 模型适配
| 模型 | 约束 |
|------|------|
| Gemini | 无特殊限制 |
| MJ | **禁止写实人像描述**face, body, skin, portrait 等触发审核人物用抽象表达silhouette, figure from behind, shadow或用场景/物体代替 |
| Kling | 无特殊限制,参考图走 style_image |
### videoPrompt 规则
- 描述**运动**而非内容("zoom in" 而非 "a cat"
- 与 imagePrompt 画面内容对应
- 简洁1-2 句,不超过 50 词)
- **收敛原则**:基于图片已有内容,仅描述镜头运动和微动效果
- **禁止**:大幅度环境切换、场景变化、人物位置跳变
- **推荐写法**镜头运动slow zoom/pan/dolly+ 光效微动 + 保持静止氛围
- **画幅继承**manifest.json 顶层 `format` 字段(如 `"9:16"`)会自动传给 VEO/Kling无需在 prompt 中指定
## 首尾帧模式提示词
每条文案生成:
- `imagePrompt`:起始帧画面(英文,与 single 模式复用同一字段)
- `lastFramePrompt`:结束帧画面(英文)
- `videoPrompt`:过渡描述(英文,给 VEO/Kling
### 首尾帧提示词设计原则
| 原则 | 说明 | 示例 |
|------|------|------|
| 同一场景 | 首尾帧是同一地点/主体的不同状态 | 都是工厂,不是两个地方 |
| 视角一致 | 相机角度/高度/距离相同 | 都是 wide shot |
| 状态对比 | imagePrompt"静止/之前"lastFramePrompt"运动/之后" | 空车间 → 生产线运转 |
| 过渡自然 | videoPrompt 描述从首到尾的变化 | "machines start up rhythmically" |
| 光照连贯 | 光源方向一致,可以有渐变 | 冷光 → 暖光可以,不能反转光源 |
### videoPrompt 规则(首尾帧)
- 描述**过渡过程**而非单帧状态
- "from X to Y" 或 "X begins, Y happens" 格式
- 必须同时呼应 imagePrompt起始帧和 lastFramePrompt结束帧中的元素
- 简洁1-2 句,不超过 50 词)

View File

@@ -1,59 +0,0 @@
# 分镜规划规则
**分镜是纯叙事思考,与视觉风格无关。** 拿到文案后、读风格文件之前,先完成分镜。
短视频的画面节奏和文案节奏是脱钩的TTS 配音连续流淌,画面在配音下面切换。分镜规划的是**视觉节拍**,不是文字断句。
## 输入输出
- **输入**:用户文案 + 约束时长、shot 数、特殊要求)
- **输出**结构化分镜表JSON 数组)
## 时长规划
分镜前先算数:
- 短视频目标时长20-60 秒
- 每个 shot 时长6-8 秒(由视频模型决定)
- shot 数量 = 目标时长 / 6~8取整一般 4-8 个 shot
- 配音字数 ≈ shot 数 x 12-15 字(按正常语速)
## 分镜表字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `text` | string | 该 shot 覆盖的配音文案(可能不到一句,也可能跨句) |
| `shotType` | enum | `wide` / `medium` / `close-up` / `extreme-close-up` |
| `cameraMove` | enum | `static` / `zoom-in` / `zoom-out` / `pan-left` / `pan-right` / `dolly-in` / `tracking` |
| `visualDesc` | string | 画面描述(中文),只写三件事:**主体是什么、什么状态/动作、视觉焦点在哪**。氛围和构图交给风格层 |
| `hook` | boolean | 仅 shot 1 为 true标记是否为开场钩子 |
## 景别节奏
```
shot 1 (hook): close-up 或 extreme-close-up强主体抓眼球
shot 2: wide 或 medium展开场景给上下文
shot 3-N交替: close-up→ wide→ close-up→ ...
最后一个 shot: medium 或 wide收束不过度设计
```
不要用 extreme-close-up 收尾(太紧),不要用 tracking 滥用(信息密度低)。
## 镜头运动选择
| cameraMove | 情绪 | 典型场景 |
|------------|------|---------|
| `static` | 稳定、庄严 | 建筑、静物、仪式感 |
| `zoom-in` | 聚焦、压迫 | 悬疑、揭秘、强调细节 |
| `zoom-out` | 揭示、震撼 | 从局部拉出全景,揭示真相 |
| `pan-left/right` | 环顾、流动 | 展示空间、物品陈列 |
| `dolly-in` | 沉浸、紧张 | 人物面部、关键物件 |
| `tracking` | 跟随、活力 | 运动场景、行走少用AI 生成的 tracking 质量不稳定) |
短视频默认转场是硬切不需要单独字段。特殊转场fade/dissolve仅在判断需要情绪转换时标注在 `visualDesc` 里。
## 首尾帧额外规则
首尾帧模式下分镜需要额外注意:
- 每个 shot 必须能拆为两个有状态对比的画面(起始帧 / 结束帧)
- `visualDesc` 需描述状态变化方向:从什么状态到什么状态
- 首尾帧必须在**同一场景**,仅状态不同