---
name: video-from-script
description: 素材生产路由。两类成片：A.幻灯片视频（图文成片）— 生图+配音+字幕；B.AI视频（视频片段成片）— 生图+AI视频化+组装，含单图/首尾帧。触发词：做视频、图文成片、图生视频、首尾帧。
---

# 素材生产路由

**你是主 Agent（导演）。** 子 Agent 执行具体任务，你负责：意图理解 → 编排调度 → 质量卡点 → 用户沟通。

## 两类成片

| 类型 | 成品 | 流程 | 有 AI 视频？ |
|------|------|------|-------------|
| **A. 幻灯片视频** | 图片 + 配音 + 字幕 + BGM + 转场 | 分镜 → 生图 → TTS → 组装 | ❌ 无 |
| **B. AI 视频** | 每张图先生成 AI 视频片段，再组装 | 分镜 → 生图 → 生视频 → TTS → 组装 | ✅ 有 |

B 模式又分两种：**单图模式**（1 图 → 1 段视频）/ **首尾帧模式**（2 图 → 过渡视频）

## 路由规则

| 用户意图 | 对应类型 | 子技能 |
|---------|---------|--------|
| "生图"、"批量图片" | 只生图 | `image-generator` |
| "图文成片"、"幻灯片视频"、"图片轮播" | A. 幻灯片视频 | `image-generator` → `capcut` |
| "图生视频"、"AI视频"、"图片转视频" | B. AI视频（单图） | `image-generator` → `capcut` |
| "首尾帧"、"帧动画"、"关键帧" | B. AI视频（首尾帧） | `image-generator` → `capcut` |
| "创建账号"、"新账号" | — | 见 [account-creation.md](references/account-creation.md) |
| "修改账号"、"改提示词"、"换风格" | — | 直接编辑 prompts/*.md |
| 只说"做视频" | **追问**：幻灯片视频 / AI视频？ | — |

---

## 执行流程

### 核心约束

1. **不可跳步**：
   - A（幻灯片）：分镜 → manifest init → 图片提示词 → 生图 → TTS+成片。无视频阶段
   - B（AI视频）：分镜 → manifest init → 图片提示词 → 生图 → 视频提示词 → 生视频 → TTS+成片
   - 阶段之间必须审查
2. **manifest.json 是唯一状态源**：`pipeline.js init` 在分镜确认后立即执行，创建 `output/{name}/` 目录和初始 manifest。后续所有子 Agent 输出回写此 manifest，不再传裸 JSON
3. **禁止 curl 调 API**：生图/生视频必须通过 `pipeline.js` 或对应 generator 脚本
4. **并行优先**：独立子任务用子 Agent 并行
5. **分镜表是脊骨契约**：用户确认分镜表后，下游子 Agent 只能加字段，禁止改 shot 数量/顺序/字段值。主 Agent 每次接收子 Agent 输出，第一件事数数量是否对得上
6. **prompts/*.md 只被子 Agent 读**：主 Agent 读 account.json，不读子 Agent 提示词模板
7. **中间产物落 output**：所有中间文件（items JSON、urls 缓存、子 Agent 输出）必须写入 `output/{name}/` 目录，禁止散落在项目根目录

### Step -1: 意图确认（逐项确认，缺一不可）

```
1. 成片类型：A.幻灯片视频 / B.AI视频？
   → AI视频继续追问：单图 / 首尾帧？

2. 素材来源：有现成文案/图片/参考图？还是需要 AI 生成？

3. 账号：扫描 accounts/*/account.json → 展示可用账号 → 用户选
   → 未指定让选，不匹配告知并问是否新建

4. 参数：画幅、生图模型、(B 模式)视频模型 — 优先从 account.json 继承
```

→ 5 项确认后，输出执行计划让用户最终确认。用户说"开始"才进入 Step 0。

### Step 0: 前置检查

- 读取 `accounts/{account}/account.json`
- 检查 `prompts/分镜.md`、`prompts/图片提示词.md`、`prompts/视频提示词.md` 是否存在
- 缺失 → 按 [account-creation.md](references/account-creation.md) 创建账号 + 生成模板
- `pipeline.js validate-account --account <id>` 校验通过后进入 Step 1

### Step 1: 分镜脚本（子 Agent 执行）

主 Agent 获取账号专属模板路径 → 将**模板文件绝对路径 + 用户文案**传给子 Agent → 子 Agent **自行 Read 模板文件全文** → 按模板规则输出分镜表 JSON：

**模板路径获取方式**：
```bash
node .claude/skills/video-from-script/scripts/get-template-path.js --account <账号ID> --type storyboard
```
输出示例：`accounts\军事账号\prompts\分镜.md`

**时间线核心规则（固化铁律，必须透传给分镜子 Agent）：**
- 文案是时间轴唯一锚点：总音频时长 = 文案总字数 ÷ 5（语速 5字/秒）
- Kling 可灵视频片段固定 6 秒
- **每个 shot 的 TTS 估算（= script字数÷5）必须 ≤ 6 秒**
- TTS > 6s → 强制在语义断点处拆分，拆分后每段 script = 语义子句（原句切分），**禁止用完整句重复填充多 shot**
- 合并后 script 拼接 = 原句一字不差
- audioDur > videoDur × 2（12s）的 shot 禁止合并，必须拆分

**子 Agent prompt 必须包含**：
1. `模板文件绝对路径：{get-template-path.js 输出的路径，转为绝对路径}`，并指示子 Agent "先 Read 此文件全文，严格按模板规则执行"
2. 用户完整口播文案
3. 成片模式（图文/视频）
4. 输出格式要求（JSON 数组）

**禁止**：主 Agent 不得摘要模板内容传给子 Agent，必须让子 Agent 直接读文件。

```json
[{"id":1,"shotDesc":"英文画面描述","script":"中文口播文案","duration":"TTS估算（=字数÷5）","directorRef":"fincher"}]
```

**主 Agent 审查（时间线合规优先）：**
1. 每个 shot 的 TTS 估算是否 ≤ 6s？→ 超过必须打回
2. TTS > 6s 的 shot 是否已正确拆分？script 是否为语义子句？
3. 时长合理？隐性动势完整（视频模式）？directorRef 已填？
4. 视频模式 script 拼接校验通过（一字不差）？

→ **分镜规划展示（每次必须输出此表）：**
```
文案: [原文]
总字数: N字 | 总音频估算: X.Xs | 视频片段: N个 | 视频模型固定时长: Kling=6s
TTS语速: 1.15x（写死在 qwen-tts.js）| 音频调速: 禁止 | 视频适配: 加速/截断

| # | TTS估算 | script（字数）| ratio估算 | 策略 | 拆分说明 | directorRef |
|---|---------|------------|---------|------|---------|------------|
| 1 | 4.8s  | 你只有看清了...（24字）| 6/17.5=0.34 | ⚠禁止 | TTS>6s需拆 | fincher |
| 2 | 5.2s  | 其实这是...（26字）| 6/27=0.22 | ⚠禁止 | TTS>6s需拆 | fincher |
...
```
ratio = estimatedVideoDuration(6s) / estimatedAudioDuration，字数÷5

→ 展示给用户确认。确认后**分镜表锁定为脊骨契约**，下游禁止增减 shot。

### Step 2-0: Manifest 初始化

```bash
node scripts/pipeline.js init --account <id> --mode <single|framePair> \
  --items '[{"id":1,"shotDesc":"...","script":"...","duration":5,"directorRef":"tarantino","keyword":"权力"}]'
```

- 分镜确认后立即执行，创建 `output/{name}/` 目录和初始 `manifest.json`
- 脚本从 account.json 继承：imageModel、videoModel、format、references
- `imagePrompt` 暂为空，Step 2-A 补充；`videoPrompt` 暂为空，Step 3-A 补充
- 输出路径打印到控制台，后续所有操作以此为工作目录

### Step 2-A: 图片提示词（子 Agent 执行）

- 主 Agent 获取账号专属图片模板路径：`node .../get-template-path.js --account <账号ID> --type image`
- 将**模板文件绝对路径 + manifest 绝对路径**传给子 Agent
- 子 Agent **先 Read 模板文件全文**，再 Read manifest.json 的 items，为每个 shot 追加 `imagePrompt` 字段后回写 manifest
- **硬约束：输出 shot 数量 == 输入 shot 数量**

**子 Agent prompt 必须包含**：
1. `模板文件绝对路径：{get-template-path.js 输出的路径，转为绝对路径}`，并指示 "先 Read 此文件全文，严格按模板规则执行"
2. `manifest 绝对路径`，指示 "Read manifest.json 的 items 数组，为每个 item 生成 imagePrompt 后回写"
3. **禁止**：主 Agent 不得摘要模板内容传给子 Agent

**主 Agent 审查**：① 数量对得上？② shotDesc 内容完整保留？③ 光影策略对应 directorRef？

### Step 2-B: 生图

```bash
node scripts/pipeline.js run --manifest <path> --phase images
```

### Step 2-C: 人工确认（可跳过）

告知图片路径给用户自行查看 → 用户可确认全部 / 替换候选图 / 删除不合格项。
用户确认后 `pipeline.js confirm --manifest <path> --all`，跳过则批量设置 `confirmed=true`。

### Step 3-A: 视频提示词（B 模式专属，子 Agent 执行）

- 主 Agent 获取账号专属视频模板路径：`node .../get-template-path.js --account <账号ID> --type video`
- 将**模板文件绝对路径 + manifest 绝对路径**传给子 Agent
- 子 Agent **先 Read 模板文件全文**，再 Read manifest.items（含已确认分镜图路径），为每个 shot 生成 `videoPrompt` 后回写 manifest
- **硬约束：输出数量 == 分镜表 shot 数量**

**子 Agent prompt 必须包含**：
1. `模板文件绝对路径：{get-template-path.js 输出的路径，转为绝对路径}`，并指示 "先 Read 此文件全文，严格按模板规则执行"
2. `manifest 绝对路径`，指示 "Read manifest.json 的 items 数组，为每个 item 生成 videoPrompt 后回写"
3. **禁止**：主 Agent 不得摘要模板内容传给子 Agent

**主 Agent 审查**：① 数量对得上？② 描述运动而非内容？③ 字数 ≤ 50？

### Step 3-B: 生视频（B 模式专属）

```bash
node scripts/pipeline.js run --manifest <path> --phase upload,videos
```

首尾帧模式额外检查过渡连贯性。

### Step 4: TTS + 成片

```bash
node scripts/pipeline.js run --manifest <path> --phase tts,assemble
```

- TTS 使用 script 字段
- 检查字幕准确、BGM 不盖配音

---

## CLI 参考

```bash
# 创建账号
node scripts/pipeline.js create-account --id <id> --name <名称> \
  --desc <描述> --video-model veo3-fast --references ./ref1.png,./ref2.png

# 校验账号
node scripts/pipeline.js validate-account --account <id>

# 初始化 manifest
node scripts/pipeline.js init --account <id> --mode <single|framePair> \
  --items '[{...}]'
node scripts/pipeline.js init --account <id> --mode single --items-file ./items.json

# 校验 manifest
node scripts/pipeline.js validate --manifest <path>

# 跑指定阶段
node scripts/pipeline.js run --manifest <path> --phase images
node scripts/pipeline.js run --manifest <path> --phase upload,videos
node scripts/pipeline.js run --manifest <path> --phase tts,assemble

# 断点续跑
node scripts/pipeline.js run --manifest <path> --resume

# 确认分镜图
node scripts/pipeline.js confirm --manifest <path> --all

# 查看进度
node scripts/pipeline.js status --manifest <path>
```

**阶段顺序**: `tts` → `images` → `upload` → `videos` → `assemble`

> **流程变更**：TTS 提前到图片生成之前，确保音频时长在生图前已知，ratio 可控。

**Item 状态**: `pending` → `generating` → `done` / `failed`

---

## 质量卡点

每阶段完成后主 Agent 自动校验，不通过则修复后继续。

### 分镜规划展示（每次必须输出）

```
文案: [原文]
总字数: N字 | 总音频估算: X.Xs | 视频片段: N个 | 视频模型: Kling=6s

| # | TTS估算 | script内容（字数）| 拆分说明 | audioDur估算→真实 | ratio |
|---|---------|----------------|---------|------------------|------|
| 1 | 4.8s  | 你只有看清了...（24字）| ✅未超6s | 4.8→17.5s | 0.34⚠ |
| 2 | 5.2s  | 其实这是...（26字）| ✅未超6s | 5.2→27.0s | 0.22⚠ |
...
```
ratio = estimatedVideoDuration / realAudioDuration，⚠=需拆分

### 分镜质量卡点（固化）

| 检查项 | 标准 | 不通过则 |
|--------|------|---------|
| 单 shot TTS 估算 | duration ≤ estimatedVideoDuration（Kling=6s） | **强制打回分镜阶段拆分** |
| 长句处理 | TTS>6s → 语义子句拆分，script 不重复完整句 | 打回重写 |
| script 内容 | 每个 shot 的 script 是独立语义子句 | 打回重写 |
| 合并校验 | 所有 script 拼接 = 原文一字不差 | 打回重写 |
| ratio 预判 | estimatedVideoDuration / estimatedAudioDuration < 0.9 → 禁止 | 打回分镜重切 |
| 视频模型时长 | estimatedVideoDuration 已填入 manifest | 检查 pipeline init |

**assemble 阶段铁律：**
- 音频以 1.15x 原速导入 CapCut，无 speed 字段
- 视频只允许加速（speed_up）或截断（trim）
- **禁止慢放（slow_down）/ 冻结帧（freeze）/ 音频调速**

### 生图

| 检查项 | 标准 | 不通过 |
|--------|------|--------|
| 数量 | 与 items 数量匹配 | 补生成失败项 |

### 配音

| 检查项 | 标准 | 不通过 |
|--------|------|--------|
| 音频数量 | 与 items 数量匹配 | 补充或裁剪 |

### AI视频

| 检查项 | 标准 | 不通过 |
|--------|------|--------|
| 视频数量 | 与 items 数量匹配 | 补生成失败项 |

### 成片输出

| 检查项 | 标准 |
|--------|------|
| 字幕准确 | 与原始文案一一对应 |

---

## 目录规范

```
output/{name}_{YYYYMMDD}_{NNN}/
├── manifest.json
├── images/          # scene_{NN}_{slug}.jpeg（首尾帧加 _last 后缀）
├── videos/          # scene_{NN}_{slug}.mp4
└── audio/           # seg_001.mp3（多句时 seg_{id}_{j}.mp3）
```

命名对应：`scene_01_觉醒.jpeg` → `scene_01_觉醒.mp4`；MJ 候选 `scene_01_觉醒_cand1.jpeg`

完整规范见 [batch-mode.md](../image-generator/references/batch-mode.md)。

---

## manifest.json

完整字段规范见 [manifest-schema.md](references/manifest-schema.md)。

核心规则：
- 脚本检测 `lastFrameUrl` → 首尾帧模式；否则 → 单图模式
- 顶层 `format` 自动传给视频模型作为画幅
- `account` 字段驱动 capcut_assemble 读取字幕风格配置

---

## 参考：视频模式

### 单图模式

每条文案生成 1 张图 + 1 个 videoPrompt。Grok、VEO、Kling 都支持。提示词描述运动如 "slow zoom in on subject"。

### 首尾帧模式

每条文案生成 **2 张图**（firstFrame + lastFrame）+ 1 个 videoPrompt。仅 VEO、Kling 支持。两帧必须是同一场景的不同状态，提示词描述过渡如 "transition from A to B"。

| 对比 | 单图模式 | 首尾帧模式 |
|------|---------|-----------|
| 图片数量 | N 张 | 2N 张 |
| 生图耗时 | 标准 | ~2 倍（可并行） |
| 视频连贯性 | 仅运动 | 场景变化（更强） |
| 可用模型 | Grok + VEO + Kling | VEO + Kling |
| 适用场景 | 风景、人物展示 | 状态变化、叙事过渡 |

---

## 参考：视频模型与降级

| 模型 | 时长 | 画幅 | 单图 | 首尾帧 | 特点 | API |
|------|------|------|------|--------|------|-----|
| Grok | 6s | 任意 | ✅ | ❌ | 快、稳定 | yunwu.ai |
| Veo3-fast | ~8s | 16:9, 9:16 | ✅ | ✅ | 超分、中文增强 | jimmyai.cn |
| Veo3-fast-frames | ~8s | 16:9, 9:16 | ✅ | ✅ | 多帧、质量最高 | jimmyai.cn |
| Kling | 6s | 任意 | ✅ | ✅ | 快、首尾帧支持 | yunwu.ai |

**注意事项**：
- 并行提交（并发 3），再并行轮询。单视频 60-300 秒，脚本内置 3 次重试
- VEO 独有：`enhance_prompt=true` 中文增强，`enable_upsample=true` 超分
- 同批次同模型，画幅统一跟随 manifest.format
- 个别 item 降级时在 manifest 标记 `videoModel` 以便追踪

**降级链**: `Grok ↔ VEO ↔ Kling`。同一 item 重试 5 次仍失败 → 备用模型补生成 → 上传 OSS → 回写 `videoUrl` → 继续 tts+assemble

---

## 共享资源

- `scripts/` — 生图、生视频、TTS、成片组装、OSS 上传等
- `accounts/` — 账号配置（项目根目录）
- `references/account-system.md` — 账号系统说明
- `skills/config.json` — API 密钥、路径配置

---

## 子技能

| 技能 | 触发词 | 职责 |
|------|--------|------|
| `image-generator` | 生图、批量出图、MJ、Gemini | 图片生成（双模型、单图/帧对） |
| `capcut` | 成片、组装、剪映、图片轮播 | CapCut 成片组装 |
