---
name: video-gen
description: "帮商家用 AI 生成产品视频（社媒投放 / PDP / 复刻爆款）。触发场景：用户说\"给这个产品做条 TikTok 视频/做条小红书种草视频/复刻这条爆款/做条 PDP 展示视频/这产品配一段视频\"——通常附产品图或参考视频。范围：所有\"画面以产品为主体\"的视频。不含\"画面里有真人讲话\"的场景（例：\"用张医生介绍产品\"是数字人意图，不在范围）。"
version: 1.0.2
owner_repo: Optima-Chat/optima-gen
---

# Video Generation Skill

帮电商商家用 AI 视频生成替代传统实拍。核心价值：**帮用户形成一份满意的 Storyboard，然后按 Storyboard 执行生成。**

## Global Rules

优先级高于任何 pipeline 步骤。违反会导致泄漏、超支或数据丢失。

1. **User-facing 不出现模型名或服务名**
   status / 成本 / 进度 / 错误 / 总结 统一用"视频生成中"。模型名仅用于 skill 内部路由，**代码注释里的也不能抄给用户**。

2. **花钱前必走 COST-GATE**
   任何 `gen video` / `gen image` 调用之前必走一次成本确认（§执行生成）。**Fast-path、迭代、重试均无例外**。成本按秒估算：`Σ(seg.duration_s) × per_second_rate_usd[mode]`，rate 从所选模板的 `production_cost.per_second_rate_usd` 读取。rate 为 TBD 时成本前缀"~"明示粗估。

3. **任何 pipeline 第一步必须 Per-video init**
   分析 / Storyboard / Plan / 生成 / Review 执行前先跑 §Per-video init（建目录 + cd）。否则后续 write 写错位置。迭代场景用 `{旧id}-vN`。

4. **Anti-fabrication**
   未在本 skill 显式列出的命令 / flag / 参数，**不允许凭印象拼**。要么走 §相关工具 里的精确命令，要么 ask user。ffmpeg / gen / scout 子命令同样适用。

5. **git 只前进，不 reset**
   每步完成立刻 commit。迭代用 `-vN` 目录不覆盖。**禁止** `git reset --hard` / `git checkout .` / `git clean -f`。

## 工作目录

所有状态都在 `~/video-gen/`，整个目录是一个 git repo。

```
~/video-gen/
├── preferences.md
├── history.md
└── videos/{video-id}/
    ├── analysis.md
    ├── storyboard.md
    ├── production-plan.md
    ├── quality-report.md
    ├── assets/
    │   ├── product.jpg
    │   ├── reference.mp4
    │   └── keyframes/
    ├── prompts/
    │   └── seg-N.txt
    ├── clips/
    │   ├── seg-N.pending.json
    │   ├── seg-N.meta.json
    │   └── seg-N.mp4
    └── final.mp4
```

## 每次 session 的启动流程

按顺序执行：

1. **检查工作目录**：`ls ~/video-gen/preferences.md`
   - 不存在 → 走「First-time init」
   - 存在 → 继续步骤 2
2. **扫描未完成任务**：找 `~/video-gen/videos/` 下无 `quality-report.md` 且创建 < 7 天的目录
   - 有 → 在回复用户前主动提一次："你有 N 个视频没完成..."
   - 无 → 继续步骤 3
3. **读 preferences.md** 和 **history.md**
4. **按用户意图分流**（**任何路径的第一步都是 Per-video init，见下文专段**）：
   - 有视频 + 有产品图 → Fast-path：直接走「分析 → Storyboard → Production Plan → 生成」全管道
   - 有视频，无产品图 → 问"换成哪个产品？"
   - **只有产品图（社媒目标）** → **爆款驱动默认流程**：
     1. agent 从产品图 + preferences 推断**品类 + 平台 + 关键词**
     2. 走「参考发现」（见下段）：自动跑 scout 取 Top 3 爆款
     3. 展示候选 → 用户选一条 → 进「分析源视频」→ 复刻 storyboard
     4. 用户说**"跳过"/"不要参考"** → 从模板构建 storyboard（opt-out 必须显式）
   - **只有产品图（PDP 目标）** → 从 PDP 模板构建 Storyboard（PDP 场景**不走爆款**，因为 PDP 视频不是社交叙事）
   - **用户意图模糊**（没说社媒 vs PDP）→ 问**一个**关键问题确认 → 再分流
   - "再试 / 更活泼 / 改 X" → 走「迭代」

**为什么社媒默认走爆款驱动**：单靠模板 + 产品图生成的视频是"平均水平"——爆款的节奏 / Hook / 卡点来自具体成功案例，不来自抽象模板。agent 主动拉爆款 → 分析 → 复刻，是把 video-gen 从"出得来"升级到"出得好"。用户想要纯模板产出 → 一句"跳过"即可，opt-out 成本为 0。

**Fast-path 触发条件**（必须全部满足才走 fast-path，否则先问）：

| 场景 | 必须有 | 可从 preferences 兜底 |
|---|---|---|
| **复刻（用户自带参考）** | 视频文件/链接 + 产品图 | 调性、平台 |
| **生成（社媒）** | 产品图 + 明确意图动词 + 平台 | 调性；**品类关键词从产品图 + preferences 推**，不够时追问 1 次 |
| **生成（PDP）** | 产品图 + 明确说"详情页"/"PDP" | 调性 |
| **迭代** | 明确的 delta（"更活泼"/"暖一点"）+ history 无歧义匹配 | — |

**社媒 Fast-path 的"爆款发现"不算"问用户"**——agent 自动拉 Top 3 + 展示让用户选 1 条是**必要数据输入**（和"选模板"同级），不是"审批"。用户选条或"跳过"都保持在 Fast-path 内。

**Fast-path 行为**：Storyboard 展示后告知而非审批，但**生成前必须告知预估成本**（见「执行生成」的成本确认）。用户可随时喊停。

## First-time init

首次使用时执行：

```bash
mkdir -p ~/video-gen/videos
cd ~/video-gen
git init -b main
```

创建 `~/video-gen/preferences.md`：

```markdown
# Preferences

## Brand
name:
palette:
tone:
forbidden:

## Defaults
platform:
aspect_ratio:
duration_seconds:

## Learned
```

创建 `~/video-gen/history.md`：

```markdown
# History

| date | video-id | product | purpose | template | storyboard-summary | parent | status | liked |
|---|---|---|---|---|---|---|---|---|
```

创建 `.gitignore`：

```
videos/**/assets/reference.mp4
videos/**/assets/*.mov
videos/**/clips/*.mp4
videos/**/clips/*.mov
videos/**/final.mp4
videos/**/final.mov
```

```bash
git add -A && git commit -m "init: video-gen workspace"
```

**Minimal init**：不要在首次使用时做问卷。只建骨架文件，preferences 留空。

如果用户的首条消息已经包含了足够的信息（产品图 + 意图），**直接进管道**，在过程中自然补充 preferences：
- 用户说了"TikTok" → 默默填 Defaults.platform = TikTok
- 用户说了"warm 风格" → 默默填 Brand.tone = warm
- 都没说 → 从模板默认值兜底，不打断流程去问

只有当管道完全无法推进时（例如连产品图都没有），才问**一个**关键问题。

每次有新信息写入 preferences → `git commit -m "prefs: update <field>"`

## 参考发现（社媒默认触发 · 用户可跳过）

**触发**：按上方「分流」的第 3 条（社媒目标 · 无用户自带参考视频）自动进入。

**不触发**：用户自带参考视频（走"分析源视频"）/ PDP 目标 / 用户明确说"跳过"。

### 步骤

1. **推断品类 + 关键词**（不打断用户）
   - 从产品图（文件名、用户文字、先前 preferences）推断，例："懒人拖把" → 品类=家居清洁 / 关键词="拖把"
   - preferences 有 `default_platform` 用 preferences；无则按"TikTok（海外）/ 抖音（国内）"默认，等用户纠正
   - 关键词低置信（产品图模糊或全新品类）→ 追问 1 次 `"产品属于哪个品类？（如美妆/家居/数码）"`，否则不打断
2. **调 scout**
   - 平台=TikTok → `scout tiktok search-videos "<关键词>" --region <US|...>`
   - 平台=抖音 → `scout douyin search-videos "<关键词>"` 或 `scout douyin hot-search`（按品类筛）
   - 其他平台：按 scout 可用命令对应（见 `storyboard-learning/analyses/2026-04-21-viral-top5-reverse-breakdown.md` 的 SOP 段）
3. **过滤 + 排序**：品牌契合（不违反 preferences.forbidden）+ 产品形态匹配 + 按 likes 降序取 Top 3
4. **展示 3 个候选**：平台 / 时间 / 指标（点赞 · 分享 · 评论）/ 风格摘要（hook 类型 · 时长 · BGM 类型）
5. **用户选一条** → 写入 `assets/reference.mp4` 或保留 URL → 继续「分析源视频」
6. **用户说"跳过"/"都不要"/"不要参考"** → 记录到 preferences.Learned（"此类任务偏好无参考"）→ 从模板构建 Storyboard

### 硬规则

- **绝不自动选参考**——Top 3 必须让用户选 1 条（或明说跳过）
- **"跳过"必须是一键**，不问理由（用户说过就记 preferences，未来同类不再默认拉爆款）
- **scout 调用成本算进 COST-GATE**——参考发现本身消耗 Optima credits（scout API 不免费）

## Per-video init

**触发条件**：走任何管道（分析 / Storyboard / Production Plan / 生成）前**必须**先执行此段。否则后续 write 操作会失败或写到错位置。

**每次新 video session 第一步**：

```bash
# <slug> = 由 agent 从产品名 / 用户意图提取的 kebab-case 短语（前 20 字符内）
# 例："懒人拖把" → "lazy-mop"；"免洗洗手液" → "no-rinse-sanitizer"
VIDEO_ID="$(date +%Y%m%d-%H%M)-<slug>"
mkdir -p ~/video-gen/videos/$VIDEO_ID/{assets/keyframes,prompts,clips}
cd ~/video-gen/videos/$VIDEO_ID
echo "Using VIDEO_ID=$VIDEO_ID"
```

**迭代场景**（用户说"再试" / "改 X"）：保留旧版本、写入新目录。用自动递增版本号防覆盖：

```bash
BASE_ID="<旧 video-id>"   # 例如 20260422-1430-product-demo
n=2
while [ -d ~/video-gen/videos/${BASE_ID}-v${n} ]; do n=$((n+1)); done
VIDEO_ID="${BASE_ID}-v${n}"
mkdir -p ~/video-gen/videos/$VIDEO_ID/{assets/keyframes,prompts,clips}
cd ~/video-gen/videos/$VIDEO_ID
echo "Using VIDEO_ID=$VIDEO_ID"
```

**场景路由**：

| 用户输入 | 触发 Per-video init 的路径 |
|---|---|
| 产品图 + 意图（无参考视频） | 进 Storyboard 前先跑 Per-video init |
| 产品图 + 参考视频 | 进「分析源视频」前先跑 Per-video init |
| 迭代（沿用旧 video） | 建 `{旧id}-vN` 目录（N 自动递增）+ cd |

## 分析源视频

**前置**：已完成 Per-video init。

有源视频时执行。产出 `videos/{id}/analysis.md`。

1. 保存素材到 `assets/`

2. ffmpeg 场景检测：

```bash
ffprobe -v quiet -print_format json -show_format -show_streams assets/reference.mp4
ffmpeg -i assets/reference.mp4 -vf "select='gt(scene,0.3)',showinfo" -vsync 0 -f null - 2>&1 | grep showinfo
```

3. 每段抽 3 帧（首/中/尾）：

```bash
ffmpeg -i assets/reference.mp4 -vf "select='eq(n\,<FRAME_NUM>)'" -vsync 0 assets/keyframes/seg-<N>-<pos>.jpg
```

4. 读取关键帧图片，分析每段的 subject / composition / camera / lighting / palette / description

5. 验证 ffmpeg 切段合理性（修正软切/漏切）

6. 以表格写入 `analysis.md`：

```markdown
# Analysis

## 元数据
| 项目 | 值 |
|---|---|
| 总时长 | 7.0s |
| 比例 | 9:16 |
| FPS | 30 |
| 片段数 | 4 |

## 镜头分析

| 段 | 时长 | 主体 | 角色 | 构图 | 运镜 | 光线 | 色调 | 描述 |
|---|---|---|---|---|---|---|---|---|
| 1 | 0-1.5s | ... | ... | ... | ... | ... | ... | ... |
| ... |

## 整体风格
| 项目 | 值 |
|---|---|
| Pacing | slow |
| Mood | aspirational, minimalist |
| Hook | subtle visual intrigue |
| CTA | logo reveal |
```

8. `git commit -m "video: analyze $VIDEO_ID — N segments, Xs"`

## 形成 Storyboard

**前置**：已完成 Per-video init。

核心产出。**用户语言写，用户能读能改。**

1. 读输入：preferences + analysis（如有）+ history 匹配 liked 记录 + 匹配模板（**先读 `$CLAUDE_SKILL_DIR/templates/INDEX.md` 路由决定选哪个，再读选中的那一份**，不要把所有模板都读一遍）

2. 有模板则以模板为骨架填入产品/品牌信息；否则从零构建

3. 复刻场景做**物理合理性预检**：原主体和用户产品形态是否兼容
   - 不合理 → 告知原因，降级策略或建议换参考

4. 写 `videos/{id}/storyboard.md`：

```markdown
# Storyboard

## 基本信息
| 项目 | 值 |
|---|---|
| 产品 | <名称> |
| 平台 | <TikTok / IG / PDP> |
| 时长目标 | <Ns> |
| 调性 | <调性> |
| 参考来源 | <来源或"从模板构建"> |

## 镜头表
| 段 | 时长 | 内容 | 运镜 | 替换说明 |
|---|---|---|---|---|
| 1 | 0-1.5s | <内容> | <运镜> | <替换或"原创"> |
| ... |

> **段时长约束**：Storyboard 按叙事节奏自由分段（推荐 2-15s）。Production Plan 阶段会将多个短段合并为 4-15s 的 gen video 调用，再用 ffmpeg trim 切回各段时长。单段 >15s 必须拆段。段时长精度到 0.5s（3.73s 四舍五入到 3.5s）。

## Hook
<第 1 秒如何抓注意力>

## CTA
<末尾留什么>

## 物理合理性预检
<复刻时：替换是否合理。无参考时写 N/A>
```

5. 展示给用户：
   - Fast-path：告知（不等审批），用户可喊停
   - 非 Fast-path：问"OK 吗？想改哪段告诉我。"

6. 确认后 `git commit -m "video: storyboard $VIDEO_ID — <summary>"`

## 产出 Production Plan

**前置**：已完成 Per-video init + Storyboard。

Storyboard 确认后自动推导。用户通常不改。

### 0. 选策略

**默认视频生成路径**支持文生 / 图生视频，**默认输出静音视频**，音频需后期处理（ffmpeg 叠 BGM / `gen tts` 配旁白）。**不要手动指定 `--provider`**，让后端自动路由到当前最优 provider。

| 特征 | 策略 |
|---|---|
| 1 镜头，无参考 | single-shot |
| 多镜头，无参考 | multi-shot-concat |
| 有参考，大致复刻 | clone-loose |
| 有参考，高度还原 | clone-strict |
| PDP 多卖点 | pdp-feature-concat |

> **回退选项**（仅在默认路径不可用或有特殊需求时显式指定）：
> - `--provider dashscope` — 需要自动配音 / 负向提示词，仅支持图生视频，时长 5\|10s
>
> 其他情况一律不传 `--provider`，由后端选默认值。

### 1. 写 `videos/{id}/production-plan.md`

默认 video 路径支持 **4-15 秒**整段生成。Storyboard 的细粒度段需要在 Production Plan 中**合并为 gen video 调用单元**：

- 相邻短段（叙事连贯、同一场景）合并成一个 4-15s 的 gen video 调用
- 每个调用的 prompt 合并覆盖所有子段的内容描述
- 生成后用 ffmpeg trim 切回各子段时长
- 单独一个 ≥4s 的 storyboard 段直接映射为一个 gen video 调用

```markdown
# Production Plan

## 策略
<策略名>
原因: <选择理由>

## 生成调用
| Call | 合并段 | 依赖 | gen_duration | seed | aspect_ratio | Prompt 摘要 |
|---|---|---|---|---|---|---|
| 1 | seg 1-3 (共 8s) | - | 8 | <seed 或 `-`> | <16:9 \| 9:16 \| 1:1> | <合并 prompt> |
| 2 | seg 4 (12s) | - | 12 | $PRODUCT_SEED | <同上> | <prompt> |
| 3 | seg 5 (10s) | Call 2 末帧 | 10 | $PRODUCT_SEED | <同上> | <承接 Call 2 末帧> |
| ... |

**依赖列怎么填**：
- `-`（绝大多数）：跟其它 Call 无依赖，可并行提交
- `Call N`：本 Call 的首帧来自 Call N 的末帧，或本 Call 的输入图来自前面某个 `gen image` 产出，必须等前置完成
- 默认尽量让 Call 之间无依赖（不同 Call 用不同首帧 / 静态产品图），并行收益最大化

## Trim 映射
| seg | 来源 Call | trim 区间 | 输出 |
|---|---|---|---|
| 1 | Call 1 | 0:00-2.5s | clips/seg-1.mp4 |
| 2 | Call 1 | 2.5-5.5s | clips/seg-2.mp4 |
| 3 | Call 1 | 5.5-8.0s | clips/seg-3.mp4 |
| 4 | Call 2 | 0:00-12.0s | clips/seg-4.mp4 |

**seed 规则**：同一产品的镜头（如 template PRODUCT_LOCK 指定的 #4/#5/#6/#9）**共用一个 seed**（任选一个固定整数记录下来）。PAIN / 场景段（如 #1/#2/#3）无产品时可填 `-`。

## 验收标准
- 比例: <从 Storyboard>
- 时长: <从 Storyboard ±20%>
- Hook: <从 Storyboard>
- CTA: <从 Storyboard>
```

### 2. 为每个需 prompt 的步骤生成 `prompts/call-N.txt`

### 3. `git commit -m "video: plan $VIDEO_ID — <strategy>"`

## 执行生成

**前置**：已完成 Per-video init + Storyboard + Production Plan。

<COST-GATE>
**生成前成本确认（必做，包括 Fast-path）**：在执行任何 `gen video` / `gen image` 调用之前，必须向用户展示一次成本摘要：

> 即将生成 N 段视频（策略: <策略名>），预计：
> - 调用次数: N 次 gen video + M 次 gen image（首帧编辑）
> - 总时长: <Σ seg.duration_s>s
> - 预估耗时: ~X 分钟
> - 预估成本: ~$Y（扣 Optima credits）
>
> 继续？

用户说"继续"/"好"/"OK" → 开始执行。
用户说"太贵"/"换个便宜的" → 回到 Production Plan，换策略（如 strict → loose）。
用户不回应超过合理时间 → 不执行，等用户。

**并行波次必须一次性报全波总成本**：并行波在 wait 那一刻把所有 Call 的钱同时扣掉，**不允许逐 Call 单独问**——那样用户被迫连点 N 次"继续"，体验更差且失去把关意义。展示口径：把波内所有 Call 的 `duration_s` 加总、按本波最贵 rate 估总价，一行报"波 #K 总成本 ~$Y"。

**即使是 Fast-path 也必须走这一步。** 这是花钱步骤的唯一确认点。**迭代、重试同样无例外。**
</COST-GATE>

按 production-plan.md 步骤表执行，**默认并行提交，不要写成顺序循环**。

### 并行执行规则

`gen video` 在 bash 层是阻塞调用（内部 submitAndPoll），单条命令耗时主要花在远端排队 + 渲染上。所以：

- **同一波内（依赖列都是 `-` 的 Call）必须用后台 `&` 并行提交，最后 `wait`** — wall time 从 N×T 降到 ~T
- **有依赖的 Call** 放下一波，等前置 `wait` 完再启动
- **每个 Call 的 pending.json 写入 + commit 仍在该 Call 自己的 subshell 里做**，不要等全部完成才一次性写

典型 3 Call 全独立的写法：

```bash
# 一波并发：3 个独立 gen video 同时提交
(
  echo '{"task_id":"","submitted_at":"'$(date -Iseconds)'","step":1,"tool":"gen video"}' > clips/seg-1.pending.json
  gen video assets/keyframes/seg-1.jpg --prompt "$(cat prompts/call-1.txt)" --duration 8 --aspect-ratio 9:16 --seed $PRODUCT_SEED -o clips/call-1.mp4 \
    && rm clips/seg-1.pending.json
) &
(
  echo '{"task_id":"","submitted_at":"'$(date -Iseconds)'","step":2,"tool":"gen video"}' > clips/seg-2.pending.json
  gen video assets/keyframes/seg-2.jpg --prompt "$(cat prompts/call-2.txt)" --duration 12 --aspect-ratio 9:16 --seed $PRODUCT_SEED -o clips/call-2.mp4 \
    && rm clips/seg-2.pending.json
) &
(
  echo '{"task_id":"","submitted_at":"'$(date -Iseconds)'","step":3,"tool":"gen video"}' > clips/seg-3.pending.json
  gen video --prompt "$(cat prompts/call-3.txt)" --duration 10 --aspect-ratio 9:16 -o clips/call-3.mp4 \
    && rm clips/seg-3.pending.json
) &
wait

# 波次失败传播 — 没这段 wait 永远返回 0，LLM 会把"并行 + 静默失败"传到 Trim
# 每个 Call 成功才 rm 自己的 pending.json；任何残留 = 该 Call 失败
pending=$(ls clips/seg-*.pending.json 2>/dev/null)
[ -z "$pending" ] || { echo "ERR: 波次有失败: $pending"; exit 1; }
```

依赖关系的写法（Call 3 依赖 Call 2 的末帧）：

```bash
# Wave 1: Call 1 / 2 独立并行（pending.json 写入 + && rm 模板见上面 3-Call 例子）
( ... gen video ... -o clips/call-1.mp4 && rm clips/seg-1.pending.json ) &
( ... gen video ... -o clips/call-2.mp4 && rm clips/seg-2.pending.json ) &
wait

# Wave 1 失败传播（同上）
pending=$(ls clips/seg-*.pending.json 2>/dev/null)
[ -z "$pending" ] || { echo "ERR: Wave 1 有失败: $pending"; exit 1; }

# Wave 1 完了再抽 Call 2 末帧 → Wave 2
# 即使 wait 上方扫过 pending.json，这里仍要 `[ -f ]` 守一道：依赖 Call 输出文件存在性
[ -f clips/call-2.mp4 ] || { echo "ERR: clips/call-2.mp4 不存在，Wave 2 中止"; exit 1; }
ffmpeg -sseof -0.1 -i clips/call-2.mp4 -frames:v 1 assets/keyframes/seg-3.jpg
gen video assets/keyframes/seg-3.jpg --prompt "$(cat prompts/call-3.txt)" -o clips/call-3.mp4
```

**不要把多个 `gen video` 写成 sequential 的 for 循环 / 多条独立命令**——LLM 默认顺序写 bash，要明确按上面的 `( … ) &` + `wait` 结构组装。

**每个 `wait` 之后必须扫 `clips/seg-*.pending.json` 残留**——光 `wait` 不暴露子 shell 失败（无参数 wait 返回 0 或最后 reap 的状态），跟 skill 后面"失败：自动重试 1 次 → 仍失败标记 needs_user_review"机制对齐。残留 = 该 Call 未走完 `&& rm`，必须停下来处理。

**每步执行前**写 `clips/seg-N.pending.json`：

```json
{
  "task_id": "",
  "submitted_at": "<ISO>",
  "step": 1,
  "tool": "<gen video | gen image | ffmpeg>"
}
```

**工具调用**：

```bash
# 图生视频（默认路径，--duration 支持 4-15 秒）
gen video <input_image> \
  --prompt "$(cat prompts/call-N.txt)" \
  --duration <4-15> \
  --aspect-ratio <16:9|9:16|1:1> \
  --seed $PRODUCT_SEED \
  -o clips/call-<N>.mp4

# 纯文生视频（无输入图像）
gen video \
  --prompt "$(cat prompts/call-N.txt)" \
  --duration <4-15> \
  --aspect-ratio <16:9|9:16|1:1> \
  -o clips/call-<N>.mp4

# 注意：不要传 --provider，让后端选默认路径。需要 dashscope / heygen 特殊功能时再显式指定。

# ffmpeg trim — 按 Trim 映射表切回 storyboard 各段
ffmpeg -i clips/call-1.mp4 -ss 0 -t 2.5 -c copy clips/seg-1.mp4
ffmpeg -i clips/call-1.mp4 -ss 2.5 -t 3.0 -c copy clips/seg-2.mp4

# 变量约定（production-plan.md 每个 call 提供）：
#   $PRODUCT_SEED  = 锁定产品一致性的 seed（同一产品的所有镜头共用一个值）

# 注意 --seed 必须 wire：否则每段 gen 产品外观随机变，templates 的 PRODUCT_LOCK
# 规范（same seed across shots）会失效，电商视频产品一致性崩塌。

# 首帧编辑（产品替换）— 双图模式
gen image "<编辑指令>" -i <原始首帧> -i <产品图> -o assets/keyframes/seg-<N>-edited.jpg

# 拼接所有 seg 为最终视频
printf "file '%s'\n" clips/seg-*.mp4 > concat_list.txt
ffmpeg -f concat -safe 0 -i concat_list.txt -c copy final.mp4

# 任务查询 / 取消 / 重试
gen task get <task_id>
gen task cancel <task_id>
gen task retry <task_id>
```

**Duration**：`--duration` 只接受 10 或 15。Production Plan 的 Trim 映射表负责将生成的完整视频切回 Storyboard 各段时长。

**每步完成后**：
- 删 `seg-N.pending.json`
- 写 `seg-N.meta.json`（duration_s / aspect_ratio / status）
- `git commit -m "video: receive $VIDEO_ID seg-N"`

**全部完成**：`git commit -m "video: done $VIDEO_ID"`

**失败**：自动重试 1 次 → 仍失败标记 `needs_user_review`

**生成过程中不问用户。** 并行规则见上方"生成"小节。

## Review

生成完成后对照 storyboard.md 检查：

1. **硬约束**（不过 → 告知用户）：
   - 比例匹配
   - 时长 ±20%
   - 文件可播放（`ffprobe final.mp4`）

2. **软推荐**（不过 → 写入迭代建议）：
   - 产品可见性（抽 5 帧）
   - 主体一致性（5 帧比对）
   - 首帧质量

3. 写 `quality-report.md` → `git commit -m "video: review $VIDEO_ID"`

4. 展示结果 + 质量摘要 + **2-3 个迭代建议**

5. 更新 `~/video-gen/history.md` 追加一行

6. 用户说"好/完美" → 在 preferences.md Learned 追加一条 → `git commit -m "prefs: learn from $VIDEO_ID — <pattern>"`

## 迭代

用户说"再试 / 更 X / 改 Y"：

1. history.md 找匹配项
2. 读该 video 的 storyboard.md
3. 判断：
   - "故事不对" → 改 storyboard → production-plan 重推 → 重新生成
   - "效果不对" → storyboard 不动 → 改 production-plan → 重新生成
4. 新 video-id = `{旧id}-v2`，history 的 parent 指向旧 id

## 核心规则（流程偏好）

> 硬规则见 §Global Rules。以下为流程偏好。

- **信息够就直接做（Fast-path）**——最重要的一条
- **Storyboard 是核心产物**，所有路径汇聚于它
- **Production Plan 由 skill 自动推导**
- **每步完成立刻 git commit**
- **生成过程零打扰**
- **参考视频永远让用户选**
- **生成完给迭代建议**
- **新会话有未完成任务先告知一次**

## 错误处理

| 故障 | 处理 |
|---|---|
| gen 返回 failed | 重试 1 次 → 仍失败告知用户 |
| gen video 返回 "duration out of range" | **不**自动重试/裁剪，告知用户并建议调整该段 storyboard 时长（默认路径支持 4-15 秒；DashScope 5\|10 秒）后重新 Production Plan |
| ffmpeg 失败 | 检查输入完整性，告知用户 |
| 源视频无法下载 | 建议手动下载后重试 |
| scout 无结果 | 告知，转模板构建 |
| 产品替换不合理 | 告知原因，降级策略或换参考 |
| 会话关闭 | 状态在文件系统 + git，下次接续 |
| gen task 超时 | 按 pending.json 重提 |
| git commit 失败 | 说明原因，不 reset |

## 相关工具

- `gen video` — 图/文 → 视频
- `gen image` — 文 → 图
- `gen image` — 文生图，也是图像编辑（`-i` 传入输入图，可多次使用最多 8 张；产品替换首帧用 `-i 源帧 -i 产品图`）
- `gen task get/cancel/retry` — 异步任务控制
- `gen tts` — 文本 → 语音
- `ffmpeg` / `ffprobe` — 视频分析、抽帧、拼接
- `scout` — 爆款视频发现
