@optima-chat/gen-cli 2.6.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/package.json +1 -2
  2. package/.claude/skills/digital-human/SKILL.md +0 -309
  3. package/.claude/skills/digital-human/references/avatar-catalog.md +0 -47
  4. package/.claude/skills/digital-human/references/edit.md +0 -219
  5. package/.claude/skills/digital-human/references/generate.md +0 -378
  6. package/.claude/skills/digital-human/references/manage.md +0 -137
  7. package/.claude/skills/digital-human/references/train.md +0 -276
  8. package/.claude/skills/gen/SKILL.md +0 -366
  9. package/.claude/skills/motion-control/SKILL.md +0 -68
  10. package/.claude/skills/multigrid-poster/SKILL.md +0 -194
  11. package/.claude/skills/multigrid-poster/layouts/2x2.json +0 -34
  12. package/.claude/skills/multigrid-poster/layouts/3x3.json +0 -43
  13. package/.claude/skills/multigrid-poster/scripts/compose.py +0 -116
  14. package/.claude/skills/multigrid-poster/scripts/placeholder.png +0 -0
  15. package/.claude/skills/multigrid-poster/shared/fonts/MaShanZheng-Regular.ttf +0 -0
  16. package/.claude/skills/video-compose/SKILL.md +0 -144
  17. package/.claude/skills/video-compose/scripts/video_compose.py +0 -290
  18. package/.claude/skills/video-edit/SKILL.md +0 -332
  19. package/.claude/skills/video-gen/SKILL.md +0 -642
  20. package/.claude/skills/video-gen/references/cinematic-language.md +0 -158
  21. package/.claude/skills/video-gen/references/confirm-card.md +0 -49
  22. package/.claude/skills/video-gen/references/prompt-craft.md +0 -73
  23. package/.claude/skills/video-gen/templates/INDEX.md +0 -78
  24. package/.claude/skills/video-gen/templates/before-after-beauty.md +0 -183
  25. package/.claude/skills/video-gen/templates/drama-fmcg.md +0 -183
  26. package/.claude/skills/video-gen/templates/kol-reaction-food.md +0 -193
  27. package/.claude/skills/video-gen/templates/multi-point-apparel.md +0 -185
  28. package/.claude/skills/video-gen/templates/pain-solution-home.md +0 -184
  29. package/.claude/skills/video-gen/templates/pdp-360-showcase.md +0 -189
  30. package/.claude/skills/video-gen/templates/pdp-feature-highlight.md +0 -182
  31. package/.claude/skills/video-gen/templates/scene-digital.md +0 -183
  32. package/.claude/skills/video-translate/SKILL.md +0 -547
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/gen-cli",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "AI content generation CLI for LLM agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,7 +37,6 @@
37
37
  },
38
38
  "files": [
39
39
  "dist",
40
- ".claude",
41
40
  "assets"
42
41
  ],
43
42
  "publishConfig": {
@@ -1,309 +0,0 @@
1
- ---
2
- name: digital-human
3
- description: "数字人(avatar + voice clone)一站式:训练 + 生成 + 段落编辑 + 管理。触发场景:(a) 训练分身——\"训这个人/克隆这个人/做 AI 老师/做 AI 主播\";(b) 生成口播视频——\"用张医生说欢迎语/用我训的分身介绍产品\";(c) 编辑某段——\"改第 N 段 / 重做第 2 段 / 刚才那条改一句话 / seg-3 重新生成\";(d) 管理——\"我的分身有哪些 / 我的视频有哪些 / 张医生训过没 / 列我的视频\"。范围:所有\"画面里出现真人/数字人讲话\"的视频。"
4
- version: 1.0.3
5
- owner_repo: Optima-Chat/optima-gen
6
- ---
7
-
8
- # Digital Human Skill
9
-
10
- > **CLI 版本要求**:本 SKILL(v2 音频先行)依赖 `@optima-chat/gen-cli ≥ 2.3.0`(含 `gen voice preview` / `gen voice concat` / `gen avatar video --audio`)。LLM 首次调这些命令失败 `command not found` / `unknown command` / `unknown option` → 报错引导用户升级 `@optima-chat/gen-cli`,**不**回退到 inline ffmpeg / 旧的逐段视频拼接流程。
11
- >
12
- > **后端要求**:音频驱动出片(`gen avatar video --audio`)需后端启用 `DOCTOR_VIDEO_AUDIO_DRIVEN`。未启用时命令返回"音频驱动 doctor-video 暂未开放"——这是部署灰度状态,不是用户错误,告知用户稍后可用、不重试。
13
-
14
- 数字分身一站式:训练用户上传的真人视频得到 voice + avatar,后续用名字引用做口播视频。
15
-
16
- > **用户向输出原则**:对话 / status / 报告里**不出现具体上游品牌 / 服务名**,统一用"训练服务" / "数字分身训练" / "上游" 等中性词。skill 内部 reasoning 引用(spec / probe / source code)可保留具体名称用于 LLM 思考。
17
-
18
- ## 路由
19
-
20
- | 用户输入 | 走哪段 |
21
- |---|---|
22
- | 有视频 + 训练意图("训这个人"/"克隆"/"做 AI X") | [references/train.md](references/train.md) |
23
- | 已有分身 + 要做视频("用张医生说..."/"用我训的分身...") | [references/generate.md](references/generate.md) |
24
- | 没指定主体但要"数字人/口播/真人讲解" | [references/generate.md](references/generate.md) → "选公共 avatar" 分支 |
25
- | **要改已有视频的某段**("改第 N 段 / 重做第 2 段 / 刚才那条改一句话") | [references/edit.md](references/edit.md) **§1.5 state check** —— 实际走 generate.md §6.6 还是 edit.md §4 由 video 的 `meta.md` "当前版本" state 决定,**不靠用户措辞猜** |
26
- | **出片确认** / **续接未完成视频**("都 OK 出视频 / 继续 X 视频 / 刚才那条出片") | [references/generate.md §6.5](references/generate.md)(重展音频试听 checkpoint)/ §6.8(跨 session 续接,自动识别 `(audio generating)` / `(audio-review pending)` / `(rendering)` 各 state) |
27
- | "我的分身有哪些"/"我的视频有哪些"/"X 训过吗"/"改名"/"删了 X" | [references/manage.md](references/manage.md) |
28
-
29
- 公共 avatar / voice 清单见 [references/avatar-catalog.md](references/avatar-catalog.md)。
30
-
31
- ## 工作空间
32
-
33
- 所有用户私有状态在 `~/digital-human/`,分 3 部分:
34
-
35
- ```
36
- ~/digital-human/
37
- ├── avatars.md # 分身索引(用户能直接看 + 改)
38
- ├── training/<external_id>/ # 每个分身的训练素材归档
39
- │ ├── source-video.mp4 # 用户上传的原视频副本
40
- │ ├── source-audio.wav # 提取的 90s 单声道
41
- │ ├── train-meta.md # 训练元数据(背景决策 / task ids / specs)
42
- │ └── preview.jpg # 缓存的 preview 图(可选)
43
- └── videos/<YYYYMMDD-HHMM>/ # 每条生成视频的 workspace
44
- ├── meta.md # 这条视频的 avatar / 总文本 / segments 表
45
- ├── segments/
46
- │ ├── seg-NN.txt # 这一段的文本
47
- │ └── seg-NN.wav # 这一段的音频(voice preview 出,逐段试听用)
48
- ├── full-audio.mp3 # 确认后拼接的整条音频(驱动渲染)
49
- ├── final-v1.mp4 # 单条音频驱动渲染的初版
50
- ├── final-vN.mp4 # 改段后重渲的新版(最多 10 个)
51
- └── history.md # 迭代记录
52
- ```
53
-
54
- **首次训练**时 LLM 自动 `mkdir -p ~/digital-human/{training,videos}` + 创建 `avatars.md`,模板:
55
-
56
- ```markdown
57
- # 我的数字分身
58
-
59
- | 名字 | external_id | 训练时间 | preview |
60
- |---|---|---|---|
61
-
62
- <!-- 使用说明:
63
- - "名字"是你叫它的方式,可以改(直接改这一列就行)。
64
- - "external_id"是系统内部 ID,格式为 `dh-` + 8 个小写字母数字,**不要改**;改了 agent 找不到对应分身,你也无法通过运维找回(因为只有这个 ID 能从后端查)。
65
- - 训完一个分身后,这里会自动加一行。
66
- - 删除某一行 = **对你视角的硬删除**:你失去所有引用路径,后端 orphan 数据需要联系运维直接查 DB 才能找回。删除前 agent 会二次确认。
67
- - voice_id / avatar_id 这些底层标识不在这里,需要时 agent 会自动从后端查。
68
- -->
69
- ```
70
-
71
- ### `videos/<id>/meta.md` 模板
72
-
73
- 每次生成视频时创建:
74
-
75
- ```markdown
76
- # Video: <slug from text or topic>
77
-
78
- | 字段 | 值 |
79
- |---|---|
80
- | video-id | 20260515-1430 |
81
- | avatar | 张医生 (external_id: dh-a7f2k9m1) |
82
- | 创建时间 | 2026-05-15 14:30 |
83
- | 当前版本 | final-v1.mp4 | ← 见下方"当前版本" 4 阶段 state machine
84
-
85
- ## 总文本
86
-
87
- > <用户给的完整 text>
88
-
89
- ## Segments
90
-
91
- | seg | text | 音频时长 | 音频文件 | 最后更新 |
92
- |---|---|---|---|---|
93
- | 01 | "..." | ~Xs | segments/seg-01.wav | <时间> |
94
- ```
95
-
96
- **"当前版本"字段 = 4 阶段 state machine**(音频先行,详见 [generate.md §5 / §6.5 / §7](references/generate.md)):
97
-
98
- | state | 何时写入 | 含义 |
99
- |---|---|---|
100
- | `(audio generating)` | generate.md §5(初版 placeholder) | 音频段还在生成,跨 session 续接靠这个 marker |
101
- | `(audio-review pending)` | generate.md §6.5(进音频试听 checkpoint) | 音频段都生成完,等用户逐段试听确认 |
102
- | `(rendering)` | generate.md §7(确认后,拼音频 + 单条渲染中) | 已确认,视频渲染中 |
103
- | `final-vN.mp4` | generate.md §7(渲染成功后) | 已出片,可正常 edit.md 主流程改段 |
104
-
105
- `manage.md` 列视频时按 state 显示 ✅ / ⏳ / 🎬 / 🚧;`edit.md` §1.5 按 state 路由(state 即 routing source-of-truth)。
106
-
107
- **不写 UUID** —— meta.md 是用户视野;voice_id / avatar_id 需要时 LLM `gen avatar profile` 反查。
108
-
109
- ### `training/<external_id>/train-meta.md` 模板
110
-
111
- ```markdown
112
- # Training: 张医生 (external_id: dh-a7f2k9m1)
113
-
114
- | 字段 | 值 |
115
- |---|---|
116
- | display_name | 张医生 |
117
- | external_id | dh-a7f2k9m1 |
118
- | 训练时间 | 2026-05-15 |
119
- | voice_task_id | uuid-xxx |
120
- | avatar_task_id | uuid-yyy |
121
- | 背景决策 | --clean-bg |
122
- | 源视频时长 | 145s |
123
- | 源视频分辨率 | 1080×1920 |
124
- | preview_image_url | https://...preview.jpg |
125
- ```
126
-
127
- 用于:重训(可重用 source-video / source-audio)、debug、运维 orphan 找回。
128
-
129
- **LLM 读 `avatars.md` 时的健全性校验**(防用户手抖改坏):
130
-
131
- | 检查 | 错误处理 |
132
- |---|---|
133
- | external_id 不符 `^dh-[a-z0-9]{8}$` 且不符存量 ASCII slug 模式(`^[a-z0-9_-]+$`) | 警告"第 N 行的 external_id 看起来损坏,可能无法引用:[名字]" |
134
- | 名字列为空 | 警告 + 建议补名字 |
135
- | 名字列重复 | 警告"两个分身都叫 'X',下次引用会有歧义" |
136
-
137
- 校验失败**不阻止**继续操作(用户的文件,LLM 不越界改),只发警告。
138
-
139
- ## LLM 如何区分用户输入是名字还是 external_id
140
-
141
- 当用户说"用 X 做视频"时:
142
-
143
- | X 形态 | 判断 | 走流程 |
144
- |---|---|---|
145
- | 含中文 / 非 ASCII | 必是名字 | 在 `avatars.md` "名字"列模糊匹配 |
146
- | 匹配 `avatars.md` "名字"列任一行 | 名字 | 取该行 external_id |
147
- | 纯 ASCII + 形如 `dh-[a-z0-9]{8}` | external_id(新格式) | 直接走 backend profile 查 |
148
- | 纯 ASCII + 含 `-` + 不在"名字"列 | 大概率存量 external_id(旧 slug,例 `dr-wang`) | 走 [manage.md "存量分身"](references/manage.md) 流程 |
149
- | 纯 ASCII + 不含 `-` + 不在"名字"列 | 歧义 | 反问"是分身名字还是 ID?" |
150
-
151
- ## Global Rules
152
-
153
- 优先级高于任何 pipeline 步骤。违反会导致泄漏、超支或数据错误。
154
-
155
- 1. **触发严格**:必须有视频 + 训练意图二者。**只有视频没意图 → 不触发**(可能用户只想让你看视频)。**只有意图没视频 → 反问**"要训练谁的分身,把视频发我"。
156
- 2. **背景必须显式决策**:训练系统会把视频背景 baked 进 avatar look,**video gen 时无法替换**。`--clean-bg` 或 `--accept-baked-bg` 二选一,不能 silent 默认。
157
- 3. **名字由用户起、external_id 由 LLM 内部生成**:用户只面对一个名字(中英文皆可),UUID(voice_id / avatar_id / external_id)全程不冒泡。
158
- 4. **Anti-fabrication**:命令 / flag / 端点必须用本 skill 列出的精确版本。CLI sub-command / API 端点不允许凭印象拼。**特别注意**:`gen avatar video` 要 `--avatar` + `--voice` 两个 UUID(不支持 `--external-id` 自动反查,必须先 `gen avatar profile` 拿 IDs)。
159
- 5. **用户向不暴露上游品牌**:见上面"用户向输出原则"。
160
- 6. **限制硬约束**(来自 spec §13):
161
- - ~~分身合成视频 text ≤ 50 字 / 输出 ≤ 10 秒~~ **已取消**:那是旧的逐段 text-driven 视频约束;音频先行下成片是**单条音频驱动渲染**,实测能吃长文本(69s+),无 50 字限制。拆段只为逐段试听粒度。
162
- - 视频 ≥ 30 秒(voice 训练用),建议 2-5 分钟(avatar 质量,spec §13.5)
163
- - 单声道音频质量好(噪声 / 多人混杂会 fail)
164
- 7. **沙箱 bash 须知(issue #183)**:agent-runtime 的 bash 是安全沙箱,**软拒绝** `$( )` 命令替换、`for`/`while` 循环、命令内换行、`;`/`&&`/`||` 串多条、`> file`/`>>` 重定向、`| jq`/`| sed`/`| grep`/`| wc` 管道、`nohup &`。所以**取值 / 判断 / 写文件全走 LLM tool_use**:用 **Read tool** 读文件 / 把内容内联进命令,用 **Write/Edit tool** 写文件,从单条 CLI 的 stdout JSON 里**自己读字段**(不 `$()`/`jq` 截),并发靠**一轮发多条单命令**(不写 `for`/`nohup &`)。详见 [generate.md §0](references/generate.md) + [edit.md 顶部沙箱须知](references/edit.md)。**最严重后果**:撞 soft-deny 后回退去手搓 `ffmpeg -f concat` 拼音频 / 拼视频——**绝对禁止**,永远用 `gen voice concat`(这就是 #183 的根因)。
165
-
166
- ## 限制 + 失败模式(来自 spec §13)
167
-
168
- | 限制 | 说明 |
169
- |---|---|
170
- | ~~text ≤ 50 字~~ 已取消 | 音频先行单条渲染能吃长文本(旧约束是逐段 text-driven 才有;spec §13.3 对单条 audio-driven 不成立,已实证) |
171
- | 单视频 4 looks 只用第一个 | 上游服务未暴露 list-looks endpoint(spec §13.5,v1.1 issue #54) |
172
- | trained look "still processing" 短期 race | adapter 自动 retry,30min 失败降级公共 avatar(spec §13.2) |
173
- | 背景 baked | video gen `background` 参数无效,训练时必须干净背景(spec §13.4) |
174
- | consent | API 不强制,产品上自行做合规(医院授权书 / 法律协议)(spec §13.6) |
175
- | 跨设备同步 | workspace `~/digital-human/avatars.md` 本地,换设备看不到(已知妥协,spec [naming-ownership](../../../docs/superpowers/specs/2026-05-14-digital-human-naming-ownership.md) 是 must-have 时的恢复路径) |
176
-
177
- ## 不在范围
178
-
179
- - ❌ Multi-persona 一次训(一个 external_id 对应一次 onboard)
180
- - ❌ Background remove / matting(让用户重拍干净背景或自己 preprocess)
181
- - ❌ License / consent 流程(产品层做,不在 skill 内)
182
- - ❌ 跨设备 workspace 同步
183
- - ❌ 团队共享 / 跨用户分身
184
- - ❌ mix-and-match 主流程支持(见 [generate.md "advanced 参考实现"](references/generate.md))
185
-
186
- ## Contract for business-layer wrappers
187
-
188
- 业务层(例 sibada-doctor / 其他)可以基于 digital-human 包 wrapper SKILL。本节文档化**稳定契约**,wrapper 可以安全 depend on。
189
-
190
- > **⚠️ v2 破坏性变更(skill 2.0.0 / gen-cli 2.3.0)**:音频先行流程把成片从"逐段 mp4 + `gen video stitch` 拼接"换成"逐段音频试听 + `gen voice concat` + `gen avatar video --audio` 单条渲染"。受影响的稳定面:`segments/seg-NN.mp4` → `seg-NN.wav` + `full-audio.mp3`;`gen video stitch`(仍在 CLI,但不再是 digital-human 出片路径);state machine 取值。Mode A wrapper(reference 本 skill reference 文档)自动获得新流程;Mode B wrapper(直接编排 CLI)需迁移到新命令。
191
-
192
- ### 稳定 CLI surface(`@optima-chat/gen-cli ≥ 2.3.0`)
193
-
194
- | 命令 | 用途 | 稳定性承诺 |
195
- |---|---|---|
196
- | `gen avatar train` | 训练 avatar look | flag 名 + 必填项稳定 |
197
- | `gen avatar onboard` | 并发训 voice+avatar | flag 名 + 必填项稳定 |
198
- | `gen avatar profile` | 查分身 profile | 返回 JSON 字段 `heygen_voice_id` / `heygen_avatar_look_ids` 稳定 |
199
- | `gen voice preview` | 逐段出音频试听(纯音频,不烧视频额度) | `--voice / --text / --output` + 可选 `--text-type` 稳定(**无** `--voice-speed`/`--voice-emotion`) |
200
- | `gen voice concat` | 多段音频拼成整条(concat filter 重编码) | `--workspace-dir / --inputs / --out` 稳定;返回 JSON `output_path / duration_sec / input_count` 稳定 |
201
- | `gen avatar video` | 用训练分身合成 | `--avatar` + (音频驱动 `--audio` \| 文本驱动 `--voice / --text`) + `-o, --output / --title` 稳定 |
202
- | `gen video --provider heygen` | 用任意 heygen avatar 合成(含公共 avatar) | `--avatar / --voice / --text / -o, --output` + 可选 `--voice-emotion / --bg-color / --caption / --title / --avatar-style / --voice-speed / --bg-image` 稳定 |
203
- | `gen video stitch` | 多段 mp4 拼接(仍存在,但 digital-human v2 出片**不用**它) | `--workspace-dir / --inputs / --out / --codec` 稳定 |
204
- | `gen voice clone` | 低层 voice 训练 | flag 稳定 |
205
-
206
- 注:`gen doctor *` 是 `gen avatar *` 的兼容性别名,wrapper **应该用 `gen avatar`**,不用 doctor(虽然两者等价)。
207
-
208
- ### 稳定 workspace 布局
209
-
210
- ```
211
- ~/digital-human/
212
- ├── avatars.md # 用户分身索引
213
- ├── training/<external_id>/ # 每分身训练素材
214
- │ ├── source-video.mp4
215
- │ ├── source-audio.wav
216
- │ ├── train-meta.md
217
- │ └── preview.jpg
218
- └── videos/<YYYYMMDD-HHMM>/ # 每条视频 workspace
219
- ├── meta.md
220
- ├── segments/seg-NN.{txt,wav}
221
- ├── full-audio.mp3
222
- ├── final-vN.mp4
223
- └── history.md
224
- ```
225
-
226
- wrapper 可以:
227
- - 在 `videos/<id>/` 下加 wrapper 自己的文件(例 `sibada-meta.md` 存 hospital/department 字段),只要不重名 + 不动 digital-human 自己的文件
228
- - 解析 `meta.md` 取分身、segments、当前版本(state machine);**不**写 meta.md 字段(LLM agent 才写)
229
-
230
- ### 稳定 `meta.md` schema
231
-
232
- "当前版本"字段 = 4 阶段 state machine(音频先行,详见 [audio-first-flow SPEC](docs/2026-05-30-digital-human-audio-first-flow.md)):
233
-
234
- | state | 含义 |
235
- |---|---|
236
- | `(audio generating)` | 音频段还在生 |
237
- | `(audio-review pending)` | 音频段都生完,等用户逐段试听确认 |
238
- | `(rendering)` | 已确认,拼音频 + 单条渲染中 |
239
- | `final-vN.mp4` | 已出片 |
240
-
241
- wrapper depending on this schema:**字段名 / 表结构 / state machine 取值** 都稳定(v2 取值已换,见顶部破坏性变更说明);新增字段会向后兼容(只加不删)。
242
-
243
- ### 两种集成模式
244
-
245
- **Mode A: SKILL composition with pre/post hooks(推荐)**
246
-
247
- wrapper SKILL 在自己 `references/*.md` 流程里 reference digital-human:
248
- - (wrapper) 验证业务前置 → 走 [train.md](references/train.md) 训练 → (wrapper) post-hook 写业务 DB
249
- - (wrapper) 业务上下文 → 走 [generate.md](references/generate.md) 生成 → (wrapper) post-hook 写 video task 到 DB
250
- - (wrapper) 改段触发 → 走 [edit.md](references/edit.md) → (wrapper) post-hook 更新 DB
251
-
252
- LLM 跟 wrapper SKILL 主流程,**穿插**调用 digital-human 各 reference。digital-human 内部不感知 wrapper 存在。复用完整逻辑(不重写),只插 hook;升级 digital-human 自动获益。
253
-
254
- **Mode B: Direct CLI primitives orchestration**
255
-
256
- wrapper 不 reference digital-human SKILL,直接编排 CLI:`gen avatar onboard ... → gen voice preview ...(逐段)→ gen voice concat ... → gen avatar video --audio ...`。wrapper 自己定义文件布局 / state。适用流程跟 digital-human 差异大的场景。
257
-
258
- ### 不稳定项(wrapper 不应 depend on)
259
-
260
- - 内部 bash 步骤编号 / 章节号(`§6.5` 等):随实施迭代会变
261
- - `history.md` 行格式 / `[audio-review]` / `[v1]` 标签:可能演化
262
- - 错误码 `code` 稳定,`message` 文案可能改
263
- - `segments/seg-NN.wav` / `full-audio.mp3` 内部码率 / 编码参数:跟上游返回 + concat 编码有关
264
- - LLM user-facing 话术:产品 UX 调整时会改
265
-
266
- ### Versioning
267
-
268
- - `@optima-chat/gen-cli`:semver,major 破坏性变更才升(删 flag);minor 加 primitive / flag(向后兼容);patch 修 bug
269
- - workspace 布局 + meta.md schema:跟随 optima-agent skill 包版本;major 升才破坏,minor 只加不删
270
-
271
- wrapper SKILL 应在自己 SKILL.md 声明:
272
- ```
273
- 依赖:
274
- - @optima-chat/gen-cli ≥ 2.3.0 (含 voice preview / voice concat / avatar video --audio)
275
- - @optima-chat/optima-agent ≥ <含 digital-human 2.0.0 的包版本> (音频先行 + wrapper contract)
276
- ```
277
-
278
- ## 相关 / 参考
279
-
280
- - **Backend**:`optima-gen/packages/generation`(adapters / routes / db)
281
- - **CLI**:`@optima-chat/gen-cli ≥ 2.3.0`(含 `gen voice preview` / `gen voice concat` / `gen avatar video --audio`),命名空间分层:
282
- - **高层 facade**(本 skill 主用):`gen avatar onboard / profile`(训 + 查) + `gen avatar video --audio`(音频驱动单条出片)
283
- - **音频先行**:`gen voice preview`(逐段试听音频)/ `gen voice concat`(拼整条音频),本 skill `generate.md §6 / §7` 和 `edit.md §5 / §6` 用
284
- - **视频处理**:`gen video --provider heygen`(任意 heygen avatar 单条合成,含公共 avatar 路径)/ `gen video stitch`(多段 mp4 拼接,仍在但 digital-human v2 不用)
285
- - **低层**(单独操作):`gen avatar train`(仅训 avatar 不训 voice) / `gen voice clone`(仅训 voice)
286
- - **辅助**:`gen task get/cancel/list`
287
- - **兼容性别名**:`gen doctor onboard / video / profile` 仍可用,跟 `gen avatar *` 行为等价;本 skill 统一用新名
288
- - **Spec**:[optima-doctor-avatar §13](https://github.com/Optima-Chat/optima-doctor-avatar/blob/main/docs/superpowers/specs/2026-05-07-doctor-avatar-poc-design.md#13-phase-1-probe-findings-2026-05-08)
289
- - **v1.1 follow-up**:[optima-gen issue #54](https://github.com/Optima-Chat/optima-gen/issues/54)
290
- - **设计 SPEC**:
291
- - **[音频先行流程 (v2,当前权威)](docs/2026-05-30-digital-human-audio-first-flow.md)** —— 逐段音频试听 + 单条音频驱动渲染,取代旧的逐段视频 + stitch(在 optima-gen 仓)
292
- - [skill 归并](../../../docs/superpowers/specs/2026-05-14-digital-human-skill-consolidation.md)
293
- - [workspace 命名](../../../docs/superpowers/specs/2026-05-14-digital-human-workspace-naming.md)
294
- - [segment 持久化](../../../docs/superpowers/specs/2026-05-15-digital-human-segment-persistence.md)
295
- - [review checkpoint](../../../docs/superpowers/specs/2026-05-16-digital-human-segment-review-checkpoint.md)
296
- - [gen video stitch primitive + wrapper contract](../../../docs/superpowers/specs/2026-05-16-gen-video-stitch-primitive.md)
297
- - **相关 skill**:`video-gen`(产品视频;与本 skill 互斥 — 见两边 description)
298
-
299
- ## 磁盘提示
300
-
301
- workspace 持久化每条视频的 segments + final + 训练源视频,长期重度用户(年频次 100+ 视频)可能积累几 GB。v1 不自动清理,用户嫌占空间:
302
-
303
- ```bash
304
- du -sh ~/digital-human/ # 总占用
305
- du -sh ~/digital-human/training/*/ # 各分身训练素材占用
306
- du -sh ~/digital-human/videos/*/ # 各视频占用
307
- ```
308
-
309
- 清理:`rm -rf ~/digital-human/videos/<old-id>` 删旧视频目录,`rm -f ~/digital-human/training/<external_id>/source-video.mp4` 单独删源视频文件(保留 train-meta.md 当存根)。
@@ -1,47 +0,0 @@
1
- # 公共 avatar / voice 清单
2
-
3
- 无需训练即可用的公共池。LLM 在用户说"做个口播视频"但没指定主体时,用本表给用户挑选。
4
-
5
- > **维护**:本文件硬编码 v1,长期目标是后端开 `gen avatar list --public` / `gen voice list --public` 端点拉真值。如有更新走 PR 改这里。
6
-
7
- ## 公共 Avatar
8
-
9
- | avatar_id | 名称 |
10
- |---|---|
11
- | `Abigail_expressive_2024112501` | Abigail(上半身,表情丰富) |
12
- | `Abigail_standing_office_front` | Abigail 办公室正面 |
13
- | `Aditya_public_4` | Aditya 棕色西装 |
14
- | `Adrian_public_3_20240312` | Adrian 蓝色衬衫 |
15
-
16
- ## 公共 Voice
17
-
18
- | voice_id | 名称 |
19
- |---|---|
20
- | `f38a635bee7a4d1f9b0a654a31d050d2` | Chill Brian(男) |
21
- | `cef3bc4e0a84424cafcde6f2cf466c97` | Ivy(女) |
22
- | `b966c31caf124c2a99f19ff1479c964f` | Jessica Anne Bogart(女) |
23
- | `42d00d4aac5441279d8536cd6b52c53c` | Hope(女) |
24
-
25
- ## 用法
26
-
27
- 公共 avatar / voice 用 `gen video --provider heygen`,**不是** `gen avatar video`(后者仅用于已 onboard 训练分身):
28
-
29
- ```bash
30
- gen video --provider heygen \
31
- --avatar Abigail_expressive_2024112501 \
32
- --voice f38a635bee7a4d1f9b0a654a31d050d2 \
33
- --text "欢迎来到我们的店铺,今天给大家介绍一款新品" \
34
- -o clips/public-talking.mp4
35
- ```
36
-
37
- 可选参数(见 [generate.md "可选参数"](generate.md)):
38
- - `--avatar-style normal|circle|closeUp`
39
- - `--voice-speed 0.5-1.5`
40
- - `--voice-emotion Excited|Friendly|Serious|Soothing|Broadcaster`
41
- - `--bg-color "#hex"` / `--bg-image <url>`
42
- - `--caption`
43
- - `--title <title>`
44
-
45
- ## 跟训练分身的混搭
46
-
47
- 支持但**不是**主流程,见 [generate.md "Advanced: mix-and-match"](generate.md)。
@@ -1,219 +0,0 @@
1
- # Edit Segment(出片后改某段)
2
-
3
- 改**已出片**视频的某一句:重生那段音频 → 重拼整条 → 整条重渲染。
4
-
5
- > ⚠️ **沙箱 bash 须知**(同 [generate.md §0](generate.md)):agent-runtime 的 bash 是安全沙箱,**软拒绝** `$( )` 命令替换、`for`/`while` 循环、命令内换行、`;`/`&&`/`||` 串多条、`> file` 重定向、`| jq`/`| sed`/`| grep` 管道、`nohup &`。所以本文档的所有"取值 / 判断 / 写文件"都靠 **LLM tool_use**(Read / Write / Edit tool + 单条命令读 JSON 输出),**不靠 shell 拼**。下面 bash 块都是**单条命令**;凡需要变量 / 文件内容,LLM 先用 Read tool 读、把值**内联**进命令,不存 `$VAR`。
6
-
7
- > **音频先行下的成本模型**(跟旧版不同,务必理解):
8
- > - 改音频(重生那段 `seg-NN.wav`)= **免费 / 极廉**(voice preview 不烧视频额度)。
9
- > - 但成片是**单条连续渲染**的整条视频,**没法只换一段画面**——改任意一句都要**整条重渲一次**(烧一次视频额度)。
10
- > - 所以**绝大多数修改应该在出片前的音频试听阶段**([generate.md §6.5](generate.md))就改掉(那时改音频免费、还没渲染)。走到 edit.md 说明**成片后才发现要改**——能做,但要重渲一次,提醒用户。
11
-
12
- ## 触发
13
-
14
- 用户说类似:
15
- - "把刚才那条视频的第 2 段改成 X"
16
- - "重做第 2 段" / "seg-3 重新生成"
17
- - "刚才那条改一句话"
18
-
19
- 不在范围(走别的流程):
20
- - "换 avatar"(换分身)→ 等于新视频,走 [generate.md](generate.md)
21
- - "改总文本"(全部重写)→ 反问"要全新生成还是只改某句?"
22
- - "video 比例 / 时长 / 字幕等元参数"→ trained avatar 不支持,反问
23
-
24
- ## 流程
25
-
26
- ### 1. 找 video-id
27
-
28
- - 用户说"刚才那条" / "刚做的" / 不指定 → `ls -t ~/digital-human/videos/ | head -1` 取最新
29
- - 用户给了 video-id(例 `20260515-1430`)→ 直接定位
30
- - 用户给文本片段或主题 → 遍历 `videos/*/meta.md` "总文本"段模糊匹配
31
- - 0 / 多个匹配 → 反问消歧
32
-
33
- 如果 video 是 SPEC 落地前(无 workspace 目录)生成的 → 反问 "这条视频没有 workspace 记录,只能重新生成整条。要走 [generate.md](generate.md) 全新创建吗?"
34
-
35
- ### 1.5 State check(找到 video-id 后必走)
36
-
37
- **Step 0: 旧流程 / 无分段视频检测(必须在 state 路由之前跑)**
38
-
39
- v2(音频先行)跟 v1(逐段视频 + stitch)**不兼容**。prod 上可能有 v1 时期生成的视频(#118 的卡顿就是 v1 在用)。镜像升到 2.0.0 后,这些旧视频若流进新的音频改段路径会**静默出错**:`gen voice concat` 只扫 `seg-*.{wav,mp3}`,旧的 `seg-*.mp4` 段被排除 → 只剩重生那一段 → 渲出**只含被改段**的残片。所以先挡。
40
-
41
- **两条单命令查 + LLM 判断**(别写 `if`/`grep -q`/`$()`,沙箱拦):
42
-
43
- ```bash
44
- ls ~/digital-human/videos/<VIDEO_ID>/segments/
45
- ```
46
-
47
- 再 Read `~/digital-human/videos/<VIDEO_ID>/meta.md` 看"当前版本"字段。然后 LLM **自己判断**(不靠 shell 条件):
48
-
49
- - **`IS_OLD_FLOW`**(命中任一):`segments/` 里出现 `seg-*.mp4` 段文件,**或** meta.md "当前版本"是旧字面量 `(generating)` / `(review pending)`。
50
- - **`NO_SEGMENTS`**:没有 `segments/` 目录,或目录里没有任何 `seg-*.txt`(公共形象单条渲染不产分段)。
51
-
52
- | 命中 | 行为(user-facing,不报 §-编号) |
53
- |---|---|
54
- | `IS_OLD_FLOW` | 反问:"这条是旧流程(逐段视频)生成的,改某句得整条重新生成——新流程是音频驱动单条渲染,跟旧的逐段视频不兼容。要用 `<meta 里的分身>` + 原文重新生成吗?" 用户同意 → 走 [generate.md](generate.md)(复用 meta.md "总文本",不再问 text)。**绝不**让它流进下面的 `final-vN.mp4` 改段分支。 |
55
- | `NO_SEGMENTS`(且非 old-flow) | 反问:"这条是公共形象单条生成的,没有分段,改内容要整条重新生成,要吗?" 同意 → [generate.md](generate.md) 公共分支。 |
56
-
57
- 两者都不命中 → 继续下面 state 路由。
58
-
59
- Read `meta.md` 取"当前版本"字段,**按 state machine 分支**(state 即路由 source-of-truth,不靠用户 phrasing 猜):
60
-
61
- | "当前版本" 值 | 行为 |
62
- |---|---|
63
- | `final-vN.mp4` | ✅ 已出片,走本文档 §2-§8 主流程(重渲产 final-v<N+1>.mp4) |
64
- | `(audio-review pending)` | ⏳ **跳出 edit.md,跳转 [generate.md §6.5 checkpoint](generate.md)** —— 还没出片,用户说"改 seg-N"是 [§6.6 出片前改音频](generate.md)(免费、不渲染) |
65
- | `(audio generating)` | 🚧 音频段还没生完。**反问**:"这条还在生成音频,要先把剩余段生完吗?(生成中不稳定,没法改)" 用户同意 → 跳 [generate.md §6.8](generate.md) 续生。**话术不出现内部 §-编号** |
66
- | `(rendering)` | 🎬 视频正在渲染。反问"这条正在出片,等渲染完再改好吗?"——渲染中改段没意义 |
67
-
68
- **为什么硬分支**:同一句"改 seg-N",在不同 state 下正确动作完全不同。出片前(audio-review pending)改音频免费、不渲染;出片后(final-vN)改要整条重渲。不 state-aware 会乱花额度或产出不存在的版本引用。
69
-
70
- ### 2. 读现状
71
-
72
- 用 **Read tool** 读 `~/digital-human/videos/<VIDEO_ID>/meta.md` 和 `~/digital-human/videos/<VIDEO_ID>/history.md`(别 `cat`),再单条 `ls` 看分段:
73
-
74
- ```bash
75
- ls ~/digital-human/videos/<VIDEO_ID>/segments/
76
- ```
77
-
78
- LLM 给用户回顾:
79
- > "找到 `<VIDEO_ID>`(分身: 张医生,4 句,当前 final-v2.mp4)。想改哪一句?现有:
80
- > - seg-01: '大家好,我是张医生。'
81
- > - seg-02: '今天介绍一款 ...'
82
- > - seg-03: '它能帮你 ...'
83
- > - seg-04: '谢谢观看。'"
84
-
85
- ### 3. 判断改的是什么
86
-
87
- | 改的是 | 处理 |
88
- |---|---|
89
- | 单段 text | 走 §4(主流程) |
90
- | 多段 text | 逐段确认 + 逐段走 §4 的重生音频,最后**只重渲一次**(§6 合并重渲) |
91
- | 换 avatar / voice | 反问 "这等于新视频,本段流程不支持。要走 [generate.md](generate.md) 用 <新分身> 全新生成吗?" |
92
- | 段间顺序 | 反问 "重排需要重拼音频 + 重渲,本 skill v1 不支持。要手动 mv segments/* 改名后我帮你重拼重渲吗?" |
93
- | 段时长 / 字幕 | trained avatar 不支持调时长 / 字幕参数,reply 不支持 |
94
-
95
- ### 4. text 改动(主流程)
96
-
97
- 获取新 text + **二次确认带阈值**(决策表 #14):
98
-
99
- ```python
100
- # 伪代码
101
- old_text = read("segments/seg-<N>.txt")
102
- new_text = <用户给的新 text>
103
- edit_ratio = levenshtein(old_text, new_text) / max(len(old_text), len(new_text))
104
-
105
- if edit_ratio > 0.3:
106
- # 大改 → 反问确认(注意:这里要重渲整条视频,会烧一次额度)
107
- ask_user(f"确认改 seg-<N>?\n 旧: {old_text}\n 新: {new_text}\n (改音频免费,但成片要整条重渲一次)")
108
- if not confirmed:
109
- return
110
- # else (≤30%): typo/标点微调,静默继续
111
- ```
112
-
113
- 30% 阈值依据:错别字 / 标点 < 5% 静默;半句话 / 换语序 20-40% 触发确认;整段重写 > 50% 肯定确认。无 levenshtein 工具时用粗估 fallback。
114
-
115
- ### 5. 覆盖 segments/seg-NN.txt + 重生 seg-NN.wav(只重生音频,免费)
116
-
117
- 设改的是第 N 段(2 位零填充,例 `02`)。三步,全走 tool_use / 单条命令:
118
-
119
- 1. **覆盖 text**:用 **Write tool** 把新文本写进 `~/digital-human/videos/<VIDEO_ID>/segments/seg-02.txt`(别 `echo >`)。
120
- 2. **反查 voice_id**(meta.md 不存 UUID):Read `meta.md` 自己读出 external_id(形如 `dh-xxxxxxxx`,或老格式 `external_id: ...` 行),**不用 grep/sed**。再单条:
121
- ```bash
122
- gen avatar profile dh-xxxxxxxx
123
- ```
124
- 从它 stdout 的 JSON 里读 `heygen_voice_id`(出片要用的 `heygen_avatar_look_ids[0]` 也一并记下,§6 要),**别 `$()`/`jq` 截**。
125
- 3. **只重生这一段音频**(免费 / 极廉,不烧视频额度;新文本**内联**进 `--text`,你手里就有):
126
- ```bash
127
- gen voice preview --voice <heygen_voice_id> --text "<新 text>" --output ~/digital-human/videos/<VIDEO_ID>/segments/seg-02.wav
128
- ```
129
-
130
- **其他段音频不动**。多段改:对每个改的段各发**一条** `gen voice preview`(LLM 并行多条,不写 `for`/`nohup`),然后 §6 **只重渲一次**。
131
-
132
- > 可选:让用户先**听**新的 seg-N 音频确认,再 §6 重渲(省得渲完又不满意)。强烈推荐多段改 / 大改时先听。
133
-
134
- ### 6. 重拼音频 → 整条重渲 → final-v<下一版本>.mp4
135
-
136
- **版本号计算 + 上限清理**(LLM 看 `ls` 输出自己数,别 `sed`/`sort`/`wc`/`$(())`):
137
-
138
- ```bash
139
- ls ~/digital-human/videos/<VIDEO_ID>/final-v*.mp4
140
- ```
141
-
142
- - LLM 从输出里找最大版本号 `LAST`(例已有 final-v1/v2 → LAST=2),下一版 `NEXT = LAST + 1`(=3)。
143
- - **决策表 #12 上限 10**:输出里 final-v*.mp4 已有 **≥ 10 个** → 删最老的那个(单条命令、路径写全):
144
- ```bash
145
- rm ~/digital-human/videos/<VIDEO_ID>/final-v1.mp4
146
- ```
147
-
148
- **重拼音频 + 单条重渲**(两条单命令,值内联):
149
-
150
- ```bash
151
- gen voice concat --workspace-dir ~/digital-human/videos/<VIDEO_ID>/ --out ~/digital-human/videos/<VIDEO_ID>/full-audio.mp3
152
- ```
153
-
154
- ```bash
155
- gen avatar video --avatar <heygen_avatar_look_ids[0]> --audio ~/digital-human/videos/<VIDEO_ID>/full-audio.mp3 -o ~/digital-human/videos/<VIDEO_ID>/final-v<NEXT>.mp4
156
- ```
157
-
158
- - `gen voice concat` 重拼整条音频(各段已含新的 seg-NN.wav,自动扫 `segments/seg-*` 排序拼接)。**🔴 严禁手搓 `ffmpeg -f concat`**——即使撞 soft-deny 也绝不回退(同 [generate.md §7](generate.md))。
159
- - `<heygen_avatar_look_ids[0]>` 用 §5 第 2 步 `gen avatar profile` 输出里读到的值内联;`<NEXT>` 用上面算出的下一版本号。
160
-
161
- > 没有 `gen video stitch` 那一步了——音频先行下成片是单条渲染,不是拼接多段 mp4。
162
-
163
- **失败处理**:`gen avatar video --audio` 返回 `音频驱动 doctor-video 暂未开放` → 后端音频驱动未启用(灰度状态,不是用户错误)→ 告知"稍后可用",不重试。其他失败看 `error_message`,音频已拼好可直接重跑渲染。
164
-
165
- ### 7. 更新 meta.md + history.md
166
-
167
- 都用 **Edit tool** 改(别 `echo >>` / `cat <<EOF`,沙箱拦;时间用你 LLM 知道的当前时间内联,别 `$(date)`)。
168
-
169
- **meta.md**:表头"当前版本"→ `final-v<NEXT>.mp4`;Segments 表第 N 行"最后更新"→ `<当前时间> (v<NEXT>)`。
170
-
171
- **history.md** 末尾用 Edit 追加一行(保留旧记录):
172
- ```markdown
173
- - **<当前时间>** [v<NEXT>] 改了 seg-<N>: "<旧 text>" → "<新 text>" (<编辑距离比例 X%>,重渲整条)
174
- ```
175
-
176
- ### 8. 报告
177
-
178
- > "✅ 视频更新完成: ~/digital-human/videos/<VIDEO_ID>/final-v<NEXT>.mp4
179
- > 改动:seg-<N> 从 '<旧>' 改成 '<新>',重生了该段音频 + 整条重渲一次。
180
- > 历史版本 final-v1 ~ final-v<LAST> 仍在,想回退直接用旧版本。"
181
-
182
- 如果触发了 final-vN.mp4 删最老逻辑(数量 ≥ 10),加一句"📦 历史版本已满 10,自动清理了最早的 final-v<被删版本>.mp4"。
183
-
184
- ---
185
-
186
- ## Edge cases
187
-
188
- ### 1. 用户说"改第 N 段"但 N 不存在
189
- 例:只有 4 段,用户说"改第 7 段"。反问:"这条只有 4 句(seg-01 ~ seg-04),没有第 7 句。要改哪一句?"
190
-
191
- ### 2. final-v* 数量已达上限 10 + 用户改段
192
- 按 §6 自动删最老 final-v1.mp4,保留 latest + 9 个历史。**不问用户**,在 §8 报告里告知。
193
-
194
- ### 3. 用户改的 text 跟旧 text 完全一样(edit_ratio = 0)
195
- 反问:"新旧 text 一样,确认要重渲吗?(音频会重生,韵律可能有细微差异,但要烧一次重渲额度)" 默认推荐"不改"。
196
-
197
- ### 4. 用户说"改最后一段"/"改第一段"(相对引用)
198
- 单条 `ls ~/digital-human/videos/<VIDEO_ID>/segments/` 看分段,LLM **数** `seg-*.txt` 的个数得到最后一段号(例 4 个 → 最后是 `seg-04`),"第一段"= `seg-01`。别用 `$(ls ... | wc -l)` 拼。
199
-
200
- ### 5. 用户改完后说"算了,用回旧版本"
201
- - final-v<NEXT>.mp4 留着(磁盘占用接受)
202
- - 告诉用户旧版本 `~/digital-human/videos/<VIDEO_ID>/final-v<LAST>.mp4` 还在
203
- - 不做"标记 active 版本"功能(final-vN 并存)
204
-
205
- ---
206
-
207
- ## Common Mistakes
208
-
209
- | ❌ Mistake | ✅ 正确做法 | 为什么 |
210
- |---|---|---|
211
- | 出片后才让用户发现要改 | 引导用户在出片前 [音频试听阶段](generate.md) 改(免费、不渲染) | edit.md 改一句要整条重渲烧额度;音频阶段改免费 |
212
- | 改一句重生所有段音频 | 仅重生改的那段 `seg-NN.wav`,其他不动 | 其他段音频不变,重拼时复用 |
213
- | 多段改时每段都重渲一次 | 逐段重生音频,最后**只重渲一次**整条 | 视频是单条渲染,改 N 段也只渲一次 |
214
- | 用 `gen video stitch` / `gen avatar video --text` 出片 | 用 `gen voice concat` + `gen avatar video --audio` | 音频先行架构下成片是单条音频驱动渲染 |
215
- | 改段时静默不二次确认 | edit_ratio > 30% 反问(且提示要重渲);≤30% 静默 | 重渲烧额度不可逆 |
216
- | final 覆盖旧版本 | final-vN.mp4 并存,最多 10 个 | 用户对比 / 回退 |
217
- | 反查 voice/avatar 从 meta.md 读 | 永远 `gen avatar profile <external_id>` 反查 | meta.md 不存 UUID(UX 原则) |
218
- | 改段时把 video-id 改成新的 | 同一条视频改段复用原 video-id | video-id 是用户对这条视频的锚 |
219
- | `--audio` 报"暂未开放"当 bug 反复重试 | 后端灰度状态,告知稍后可用 | 音频驱动有 feature flag |