@optima-chat/gen-cli 2.3.0 → 2.5.0
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.
- package/.claude/skills/digital-human/SKILL.md +131 -17
- package/.claude/skills/digital-human/references/edit.md +121 -100
- package/.claude/skills/digital-human/references/generate.md +256 -124
- package/.claude/skills/digital-human/references/manage.md +28 -17
- package/.claude/skills/digital-human/references/train.md +47 -62
- package/.claude/skills/gen/SKILL.md +13 -0
- package/.claude/skills/motion-control/SKILL.md +68 -0
- package/.claude/skills/video-compose/SKILL.md +144 -0
- package/.claude/skills/video-compose/scripts/video_compose.py +290 -0
- package/.claude/skills/video-edit/SKILL.md +62 -1
- package/.claude/skills/video-gen/SKILL.md +165 -57
- package/.claude/skills/video-gen/references/cinematic-language.md +158 -0
- package/.claude/skills/video-gen/references/confirm-card.md +49 -0
- package/.claude/skills/video-gen/references/prompt-craft.md +72 -0
- package/.claude/skills/video-translate/SKILL.md +205 -69
- package/assets/video-compose/bgm-library/SOURCES.md +25 -0
- package/assets/video-compose/bgm-library/calm/calm-01.mp3 +0 -0
- package/assets/video-compose/bgm-library/calm/calm-02.mp3 +0 -0
- package/assets/video-compose/bgm-library/dramatic/dramatic-01.mp3 +0 -0
- package/assets/video-compose/bgm-library/dramatic/dramatic-02.mp3 +0 -0
- package/assets/video-compose/bgm-library/energetic/energetic-01.mp3 +0 -0
- package/assets/video-compose/bgm-library/energetic/energetic-02.mp3 +0 -0
- package/assets/video-compose/bgm-library/sad/sad-01.mp3 +0 -0
- package/assets/video-compose/bgm-library/sad/sad-02.mp3 +0 -0
- package/assets/video-compose/bgm-library/upbeat/upbeat-01.mp3 +0 -0
- package/assets/video-compose/bgm-library/upbeat/upbeat-02.mp3 +0 -0
- package/assets/video-compose/bgm-library/warm/warm-01.mp3 +0 -0
- package/assets/video-compose/bgm-library/warm/warm-02.mp3 +0 -0
- package/assets/video-compose/voice-samples/01-/346/270/251/346/232/226/345/260/221/345/245/263.mp3 +0 -0
- package/assets/video-compose/voice-samples/02-/347/224/234/347/276/216/345/245/263/345/243/260.mp3 +0 -0
- package/assets/video-compose/voice-samples/03-/347/224/234/347/276/216/345/205/203/346/260/224.mp3 +0 -0
- package/assets/video-compose/voice-samples/04-/346/270/205/347/224/234/345/260/221/345/245/263.mp3 +0 -0
- package/assets/video-compose/voice-samples/05-/345/276/241/345/247/220.mp3 +0 -0
- package/assets/video-compose/voice-samples/06-/346/210/220/347/206/237/347/237/245/346/200/247.mp3 +0 -0
- package/assets/video-compose/voice-samples/07-/345/245/263/344/270/273/346/222/255.mp3 +0 -0
- package/assets/video-compose/voice-samples/CATALOG.md +9 -0
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +19 -2
- package/dist/services/auth.js.map +1 -1
- package/package.json +3 -2
|
@@ -7,6 +7,10 @@ owner_repo: Optima-Chat/optima-gen
|
|
|
7
7
|
|
|
8
8
|
# Digital Human Skill
|
|
9
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
|
+
|
|
10
14
|
数字分身一站式:训练用户上传的真人视频得到 voice + avatar,后续用名字引用做口播视频。
|
|
11
15
|
|
|
12
16
|
> **用户向输出原则**:对话 / status / 报告里**不出现具体上游品牌 / 服务名**,统一用"训练服务" / "数字分身训练" / "上游" 等中性词。skill 内部 reasoning 引用(spec / probe / source code)可保留具体名称用于 LLM 思考。
|
|
@@ -18,7 +22,8 @@ owner_repo: Optima-Chat/optima-gen
|
|
|
18
22
|
| 有视频 + 训练意图("训这个人"/"克隆"/"做 AI X") | [references/train.md](references/train.md) |
|
|
19
23
|
| 已有分身 + 要做视频("用张医生说..."/"用我训的分身...") | [references/generate.md](references/generate.md) |
|
|
20
24
|
| 没指定主体但要"数字人/口播/真人讲解" | [references/generate.md](references/generate.md) → "选公共 avatar" 分支 |
|
|
21
|
-
| **要改已有视频的某段**("改第 N 段 / 重做第 2 段 / 刚才那条改一句话") | [references/edit.md](references/edit.md) |
|
|
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) |
|
|
22
27
|
| "我的分身有哪些"/"我的视频有哪些"/"X 训过吗"/"改名"/"删了 X" | [references/manage.md](references/manage.md) |
|
|
23
28
|
|
|
24
29
|
公共 avatar / voice 清单见 [references/avatar-catalog.md](references/avatar-catalog.md)。
|
|
@@ -39,9 +44,10 @@ owner_repo: Optima-Chat/optima-gen
|
|
|
39
44
|
├── meta.md # 这条视频的 avatar / 总文本 / segments 表
|
|
40
45
|
├── segments/
|
|
41
46
|
│ ├── seg-NN.txt # 这一段的文本
|
|
42
|
-
│ └── seg-NN.
|
|
43
|
-
├──
|
|
44
|
-
├── final-
|
|
47
|
+
│ └── seg-NN.wav # 这一段的音频(voice preview 出,逐段试听用)
|
|
48
|
+
├── full-audio.mp3 # 确认后拼接的整条音频(驱动渲染)
|
|
49
|
+
├── final-v1.mp4 # 单条音频驱动渲染的初版
|
|
50
|
+
├── final-vN.mp4 # 改段后重渲的新版(最多 10 个)
|
|
45
51
|
└── history.md # 迭代记录
|
|
46
52
|
```
|
|
47
53
|
|
|
@@ -74,7 +80,7 @@ owner_repo: Optima-Chat/optima-gen
|
|
|
74
80
|
| video-id | 20260515-1430 |
|
|
75
81
|
| avatar | 张医生 (external_id: dh-a7f2k9m1) |
|
|
76
82
|
| 创建时间 | 2026-05-15 14:30 |
|
|
77
|
-
| 当前版本 | final-v1.mp4 |
|
|
83
|
+
| 当前版本 | final-v1.mp4 | ← 见下方"当前版本" 4 阶段 state machine
|
|
78
84
|
|
|
79
85
|
## 总文本
|
|
80
86
|
|
|
@@ -82,11 +88,22 @@ owner_repo: Optima-Chat/optima-gen
|
|
|
82
88
|
|
|
83
89
|
## Segments
|
|
84
90
|
|
|
85
|
-
| seg | text |
|
|
91
|
+
| seg | text | 音频时长 | 音频文件 | 最后更新 |
|
|
86
92
|
|---|---|---|---|---|
|
|
87
|
-
| 01 | "..." | ~Xs | segments/seg-01.
|
|
93
|
+
| 01 | "..." | ~Xs | segments/seg-01.wav | <时间> |
|
|
88
94
|
```
|
|
89
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
|
+
|
|
90
107
|
**不写 UUID** —— meta.md 是用户视野;voice_id / avatar_id 需要时 LLM `gen avatar profile` 反查。
|
|
91
108
|
|
|
92
109
|
### `training/<external_id>/train-meta.md` 模板
|
|
@@ -141,46 +158,143 @@ owner_repo: Optima-Chat/optima-gen
|
|
|
141
158
|
4. **Anti-fabrication**:命令 / flag / 端点必须用本 skill 列出的精确版本。CLI sub-command / API 端点不允许凭印象拼。**特别注意**:`gen avatar video` 要 `--avatar` + `--voice` 两个 UUID(不支持 `--external-id` 自动反查,必须先 `gen avatar profile` 拿 IDs)。
|
|
142
159
|
5. **用户向不暴露上游品牌**:见上面"用户向输出原则"。
|
|
143
160
|
6. **限制硬约束**(来自 spec §13):
|
|
144
|
-
-
|
|
161
|
+
- ~~分身合成视频 text ≤ 50 字 / 输出 ≤ 10 秒~~ **已取消**:那是旧的逐段 text-driven 视频约束;音频先行下成片是**单条音频驱动渲染**,实测能吃长文本(69s+),无 50 字限制。拆段只为逐段试听粒度。
|
|
145
162
|
- 视频 ≥ 30 秒(voice 训练用),建议 2-5 分钟(avatar 质量,spec §13.5)
|
|
146
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 的根因)。
|
|
147
165
|
|
|
148
166
|
## 限制 + 失败模式(来自 spec §13)
|
|
149
167
|
|
|
150
168
|
| 限制 | 说明 |
|
|
151
169
|
|---|---|
|
|
152
|
-
| text ≤ 50
|
|
170
|
+
| ~~text ≤ 50 字~~ 已取消 | 音频先行单条渲染能吃长文本(旧约束是逐段 text-driven 才有;spec §13.3 对单条 audio-driven 不成立,已实证) |
|
|
153
171
|
| 单视频 4 looks 只用第一个 | 上游服务未暴露 list-looks endpoint(spec §13.5,v1.1 issue #54) |
|
|
154
172
|
| trained look "still processing" 短期 race | adapter 自动 retry,30min 失败降级公共 avatar(spec §13.2) |
|
|
155
173
|
| 背景 baked | video gen `background` 参数无效,训练时必须干净背景(spec §13.4) |
|
|
156
174
|
| consent | API 不强制,产品上自行做合规(医院授权书 / 法律协议)(spec §13.6) |
|
|
157
|
-
| 跨设备同步 | workspace `~/digital-human/avatars.md` 本地,换设备看不到(已知妥协,spec [naming-ownership](
|
|
175
|
+
| 跨设备同步 | workspace `~/digital-human/avatars.md` 本地,换设备看不到(已知妥协,spec [naming-ownership](../../../docs/superpowers/specs/2026-05-14-digital-human-naming-ownership.md) 是 must-have 时的恢复路径) |
|
|
158
176
|
|
|
159
177
|
## 不在范围
|
|
160
178
|
|
|
161
179
|
- ❌ Multi-persona 一次训(一个 external_id 对应一次 onboard)
|
|
162
180
|
- ❌ Background remove / matting(让用户重拍干净背景或自己 preprocess)
|
|
163
|
-
- ❌ Long video gen(text > 50 字让用户拆段)
|
|
164
181
|
- ❌ License / consent 流程(产品层做,不在 skill 内)
|
|
165
182
|
- ❌ 跨设备 workspace 同步
|
|
166
183
|
- ❌ 团队共享 / 跨用户分身
|
|
167
184
|
- ❌ mix-and-match 主流程支持(见 [generate.md "advanced 参考实现"](references/generate.md))
|
|
168
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
|
+
|
|
169
278
|
## 相关 / 参考
|
|
170
279
|
|
|
171
280
|
- **Backend**:`optima-gen/packages/generation`(adapters / routes / db)
|
|
172
|
-
- **CLI
|
|
173
|
-
- **高层 facade**(本 skill 主用):`gen avatar onboard /
|
|
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 不用)
|
|
174
285
|
- **低层**(单独操作):`gen avatar train`(仅训 avatar 不训 voice) / `gen voice clone`(仅训 voice)
|
|
175
286
|
- **辅助**:`gen task get/cancel/list`
|
|
176
287
|
- **兼容性别名**:`gen doctor onboard / video / profile` 仍可用,跟 `gen avatar *` 行为等价;本 skill 统一用新名
|
|
177
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)
|
|
178
289
|
- **v1.1 follow-up**:[optima-gen issue #54](https://github.com/Optima-Chat/optima-gen/issues/54)
|
|
179
290
|
- **设计 SPEC**:
|
|
180
|
-
- [
|
|
181
|
-
- [
|
|
182
|
-
- [
|
|
183
|
-
-
|
|
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)
|
|
184
298
|
|
|
185
299
|
## 磁盘提示
|
|
186
300
|
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
# Edit Segment(
|
|
1
|
+
# Edit Segment(出片后改某段)
|
|
2
2
|
|
|
3
|
-
|
|
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 说明**成片后才发现要改**——能做,但要重渲一次,提醒用户。
|
|
4
11
|
|
|
5
12
|
## 触发
|
|
6
13
|
|
|
7
14
|
用户说类似:
|
|
8
15
|
- "把刚才那条视频的第 2 段改成 X"
|
|
9
|
-
- "重做第 2 段"
|
|
16
|
+
- "重做第 2 段" / "seg-3 重新生成"
|
|
10
17
|
- "刚才那条改一句话"
|
|
11
|
-
- "seg-3 重新生成"
|
|
12
|
-
- "第 N 段不对,改成 ..."
|
|
13
18
|
|
|
14
19
|
不在范围(走别的流程):
|
|
15
|
-
- "换 avatar"(换分身)→
|
|
16
|
-
- "改总文本"(全部重写)→ 反问"
|
|
20
|
+
- "换 avatar"(换分身)→ 等于新视频,走 [generate.md](generate.md)
|
|
21
|
+
- "改总文本"(全部重写)→ 反问"要全新生成还是只改某句?"
|
|
17
22
|
- "video 比例 / 时长 / 字幕等元参数"→ trained avatar 不支持,反问
|
|
18
23
|
|
|
19
24
|
## 流程
|
|
@@ -23,23 +28,55 @@
|
|
|
23
28
|
- 用户说"刚才那条" / "刚做的" / 不指定 → `ls -t ~/digital-human/videos/ | head -1` 取最新
|
|
24
29
|
- 用户给了 video-id(例 `20260515-1430`)→ 直接定位
|
|
25
30
|
- 用户给文本片段或主题 → 遍历 `videos/*/meta.md` "总文本"段模糊匹配
|
|
26
|
-
- 0
|
|
27
|
-
- 多个匹配 → 反问消歧
|
|
31
|
+
- 0 / 多个匹配 → 反问消歧
|
|
28
32
|
|
|
29
33
|
如果 video 是 SPEC 落地前(无 workspace 目录)生成的 → 反问 "这条视频没有 workspace 记录,只能重新生成整条。要走 [generate.md](generate.md) 全新创建吗?"
|
|
30
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
|
+
|
|
31
70
|
### 2. 读现状
|
|
32
71
|
|
|
72
|
+
用 **Read tool** 读 `~/digital-human/videos/<VIDEO_ID>/meta.md` 和 `~/digital-human/videos/<VIDEO_ID>/history.md`(别 `cat`),再单条 `ls` 看分段:
|
|
73
|
+
|
|
33
74
|
```bash
|
|
34
|
-
|
|
35
|
-
cat meta.md
|
|
36
|
-
cat history.md
|
|
37
|
-
ls segments/
|
|
75
|
+
ls ~/digital-human/videos/<VIDEO_ID>/segments/
|
|
38
76
|
```
|
|
39
77
|
|
|
40
78
|
LLM 给用户回顾:
|
|
41
|
-
> "找到 `<VIDEO_ID>`(分身: 张医生,4
|
|
42
|
-
> 想改哪一段?现有:
|
|
79
|
+
> "找到 `<VIDEO_ID>`(分身: 张医生,4 句,当前 final-v2.mp4)。想改哪一句?现有:
|
|
43
80
|
> - seg-01: '大家好,我是张医生。'
|
|
44
81
|
> - seg-02: '今天介绍一款 ...'
|
|
45
82
|
> - seg-03: '它能帮你 ...'
|
|
@@ -47,14 +84,12 @@ LLM 给用户回顾:
|
|
|
47
84
|
|
|
48
85
|
### 3. 判断改的是什么
|
|
49
86
|
|
|
50
|
-
用户给意图后,分支:
|
|
51
|
-
|
|
52
87
|
| 改的是 | 处理 |
|
|
53
88
|
|---|---|
|
|
54
|
-
| 单段 text | 走 §4
|
|
55
|
-
| 多段 text | 逐段确认 + 逐段走 §4 |
|
|
89
|
+
| 单段 text | 走 §4(主流程) |
|
|
90
|
+
| 多段 text | 逐段确认 + 逐段走 §4 的重生音频,最后**只重渲一次**(§6 合并重渲) |
|
|
56
91
|
| 换 avatar / voice | 反问 "这等于新视频,本段流程不支持。要走 [generate.md](generate.md) 用 <新分身> 全新生成吗?" |
|
|
57
|
-
| 段间顺序 | 反问 "
|
|
92
|
+
| 段间顺序 | 反问 "重排需要重拼音频 + 重渲,本 skill v1 不支持。要手动 mv segments/* 改名后我帮你重拼重渲吗?" |
|
|
58
93
|
| 段时长 / 字幕 | trained avatar 不支持调时长 / 字幕参数,reply 不支持 |
|
|
59
94
|
|
|
60
95
|
### 4. text 改动(主流程)
|
|
@@ -65,123 +100,107 @@ LLM 给用户回顾:
|
|
|
65
100
|
# 伪代码
|
|
66
101
|
old_text = read("segments/seg-<N>.txt")
|
|
67
102
|
new_text = <用户给的新 text>
|
|
68
|
-
|
|
69
103
|
edit_ratio = levenshtein(old_text, new_text) / max(len(old_text), len(new_text))
|
|
70
104
|
|
|
71
105
|
if edit_ratio > 0.3:
|
|
72
|
-
# 大改 → 反问确认
|
|
73
|
-
ask_user(f"确认改 seg-<N>?\n 旧: {old_text}\n 新: {new_text}\n (
|
|
106
|
+
# 大改 → 反问确认(注意:这里要重渲整条视频,会烧一次额度)
|
|
107
|
+
ask_user(f"确认改 seg-<N>?\n 旧: {old_text}\n 新: {new_text}\n (改音频免费,但成片要整条重渲一次)")
|
|
74
108
|
if not confirmed:
|
|
75
109
|
return
|
|
76
|
-
# else (≤30%): typo
|
|
110
|
+
# else (≤30%): typo/标点微调,静默继续
|
|
77
111
|
```
|
|
78
112
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
|
|
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
|
+
```
|
|
83
129
|
|
|
84
|
-
|
|
130
|
+
**其他段音频不动**。多段改:对每个改的段各发**一条** `gen voice preview`(LLM 并行多条,不写 `for`/`nohup`),然后 §6 **只重渲一次**。
|
|
85
131
|
|
|
86
|
-
|
|
132
|
+
> 可选:让用户先**听**新的 seg-N 音频确认,再 §6 重渲(省得渲完又不满意)。强烈推荐多段改 / 大改时先听。
|
|
133
|
+
|
|
134
|
+
### 6. 重拼音频 → 整条重渲 → final-v<下一版本>.mp4
|
|
135
|
+
|
|
136
|
+
**版本号计算 + 上限清理**(LLM 看 `ls` 输出自己数,别 `sed`/`sort`/`wc`/`$(())`):
|
|
87
137
|
|
|
88
138
|
```bash
|
|
89
|
-
|
|
90
|
-
echo "<新 text>" > segments/seg-$N.txt
|
|
91
|
-
|
|
92
|
-
# 从 meta.md 提取 external_id (avatar 字段含 "external_id: dh-XXXXXXXX")
|
|
93
|
-
EXTERNAL_ID=$(grep -oE 'dh-[a-z0-9]{8}' meta.md | head -1)
|
|
94
|
-
if [ -z "$EXTERNAL_ID" ]; then
|
|
95
|
-
# 存量 slug 兜底 (例 dr-wang),从 meta.md 表里抽
|
|
96
|
-
EXTERNAL_ID=$(grep -oE 'external_id: [a-z0-9_-]+' meta.md | sed 's/external_id: //' | head -1)
|
|
97
|
-
fi
|
|
98
|
-
|
|
99
|
-
# 反查 voice_id + avatar_id (meta.md 不存 UUID,profile 反查)
|
|
100
|
-
PROFILE=$(gen avatar profile "$EXTERNAL_ID")
|
|
101
|
-
VOICE_ID=$(echo "$PROFILE" | jq -r '.heygen_voice_id')
|
|
102
|
-
AVATAR_ID=$(echo "$PROFILE" | jq -r '.heygen_avatar_look_ids[0]')
|
|
103
|
-
|
|
104
|
-
# 只重生这一段
|
|
105
|
-
gen avatar video --avatar "$AVATAR_ID" --voice "$VOICE_ID" \
|
|
106
|
-
--text "$(cat segments/seg-$N.txt)" \
|
|
107
|
-
-o "segments/seg-$N.mp4"
|
|
139
|
+
ls ~/digital-human/videos/<VIDEO_ID>/final-v*.mp4
|
|
108
140
|
```
|
|
109
141
|
|
|
110
|
-
|
|
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
|
+
```
|
|
111
147
|
|
|
112
|
-
|
|
148
|
+
**重拼音频 + 单条重渲**(两条单命令,值内联):
|
|
113
149
|
|
|
114
|
-
|
|
150
|
+
```bash
|
|
151
|
+
gen voice concat --workspace-dir ~/digital-human/videos/<VIDEO_ID>/ --out ~/digital-human/videos/<VIDEO_ID>/full-audio.mp3
|
|
152
|
+
```
|
|
115
153
|
|
|
116
154
|
```bash
|
|
117
|
-
|
|
118
|
-
LAST_V=$(ls final-v*.mp4 2>/dev/null | sed 's/final-v\(.*\).mp4/\1/' | sort -n | tail -1)
|
|
119
|
-
NEXT_V=$((LAST_V + 1))
|
|
120
|
-
|
|
121
|
-
# 决策表 #12: 上限 10,第 11 次写 → 静默删 final-v1.mp4
|
|
122
|
-
COUNT=$(ls final-v*.mp4 2>/dev/null | wc -l)
|
|
123
|
-
if [ "$COUNT" -ge 10 ]; then
|
|
124
|
-
OLDEST=$(ls final-v*.mp4 | sort -V | head -1)
|
|
125
|
-
rm "$OLDEST"
|
|
126
|
-
fi
|
|
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
|
|
127
156
|
```
|
|
128
157
|
|
|
129
|
-
|
|
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>` 用上面算出的下一版本号。
|
|
130
160
|
|
|
131
|
-
|
|
161
|
+
> 没有 `gen video stitch` 那一步了——音频先行下成片是单条渲染,不是拼接多段 mp4。
|
|
162
|
+
|
|
163
|
+
**失败处理**:`gen avatar video --audio` 返回 `音频驱动 doctor-video 暂未开放` → 后端音频驱动未启用(灰度状态,不是用户错误)→ 告知"稍后可用",不重试。其他失败看 `error_message`,音频已拼好可直接重跑渲染。
|
|
132
164
|
|
|
133
165
|
### 7. 更新 meta.md + history.md
|
|
134
166
|
|
|
135
|
-
**
|
|
136
|
-
|
|
137
|
-
-
|
|
167
|
+
都用 **Edit tool** 改(别 `echo >>` / `cat <<EOF`,沙箱拦;时间用你 LLM 知道的当前时间内联,别 `$(date)`)。
|
|
168
|
+
|
|
169
|
+
**meta.md**:表头"当前版本"→ `final-v<NEXT>.mp4`;Segments 表第 N 行"最后更新"→ `<当前时间> (v<NEXT>)`。
|
|
138
170
|
|
|
139
|
-
**history.md**
|
|
171
|
+
**history.md** 末尾用 Edit 追加一行(保留旧记录):
|
|
140
172
|
```markdown
|
|
141
|
-
- **<当前时间>** [v
|
|
173
|
+
- **<当前时间>** [v<NEXT>] 改了 seg-<N>: "<旧 text>" → "<新 text>" (<编辑距离比例 X%>,重渲整条)
|
|
142
174
|
```
|
|
143
175
|
|
|
144
176
|
### 8. 报告
|
|
145
177
|
|
|
146
|
-
> "✅ 视频更新完成:
|
|
147
|
-
> 改动:seg
|
|
148
|
-
>
|
|
149
|
-
> 历史版本 final-v1 ~ final-v$LAST_V 仍在,想回退直接用旧版本。"
|
|
178
|
+
> "✅ 视频更新完成: ~/digital-human/videos/<VIDEO_ID>/final-v<NEXT>.mp4
|
|
179
|
+
> 改动:seg-<N> 从 '<旧>' 改成 '<新>',重生了该段音频 + 整条重渲一次。
|
|
180
|
+
> 历史版本 final-v1 ~ final-v<LAST> 仍在,想回退直接用旧版本。"
|
|
150
181
|
|
|
151
|
-
|
|
152
|
-
如果触发了 final-vN.mp4 删最老的逻辑(数量 ≥ 10),加一句"📦 历史版本已满 10,自动清理了最早的 final-v$DELETED.mp4"。
|
|
182
|
+
如果触发了 final-vN.mp4 删最老逻辑(数量 ≥ 10),加一句"📦 历史版本已满 10,自动清理了最早的 final-v<被删版本>.mp4"。
|
|
153
183
|
|
|
154
184
|
---
|
|
155
185
|
|
|
156
186
|
## Edge cases
|
|
157
187
|
|
|
158
188
|
### 1. 用户说"改第 N 段"但 N 不存在
|
|
159
|
-
|
|
160
|
-
例:视频只有 4 段,用户说"改第 7 段"。
|
|
161
|
-
|
|
162
|
-
反问:"这条视频只有 4 段(seg-01 ~ seg-04),没有第 7 段。要改哪一段?"
|
|
189
|
+
例:只有 4 段,用户说"改第 7 段"。反问:"这条只有 4 句(seg-01 ~ seg-04),没有第 7 句。要改哪一句?"
|
|
163
190
|
|
|
164
191
|
### 2. final-v* 数量已达上限 10 + 用户改段
|
|
165
|
-
|
|
166
|
-
按 §6 自动删 final-v1.mp4(最老),保留 latest + 9 个历史。**不问用户**,在 §8 报告里告知"自动清理了 final-vX.mp4"。
|
|
192
|
+
按 §6 自动删最老 final-v1.mp4,保留 latest + 9 个历史。**不问用户**,在 §8 报告里告知。
|
|
167
193
|
|
|
168
194
|
### 3. 用户改的 text 跟旧 text 完全一样(edit_ratio = 0)
|
|
169
|
-
|
|
170
|
-
反问:"新旧 text 一样,确认要重生 seg-N 吗?(会花一次 credits,但 mp4 结果可能跟旧版有细微 heygen 随机差异)"
|
|
171
|
-
默认推荐"不重生"。
|
|
195
|
+
反问:"新旧 text 一样,确认要重渲吗?(音频会重生,韵律可能有细微差异,但要烧一次重渲额度)" 默认推荐"不改"。
|
|
172
196
|
|
|
173
197
|
### 4. 用户说"改最后一段"/"改第一段"(相对引用)
|
|
174
|
-
|
|
175
|
-
LLM 解析:"最后一段"= `seg-$(ls segments/seg-*.txt | wc -l | xargs printf "%02d")`,"第一段"= seg-01。
|
|
198
|
+
单条 `ls ~/digital-human/videos/<VIDEO_ID>/segments/` 看分段,LLM **数** `seg-*.txt` 的个数得到最后一段号(例 4 个 → 最后是 `seg-04`),"第一段"= `seg-01`。别用 `$(ls ... | wc -l)` 拼。
|
|
176
199
|
|
|
177
200
|
### 5. 用户改完后说"算了,用回旧版本"
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
- final-
|
|
181
|
-
- 用户用旧版本:直接告诉 ta `~/digital-human/videos/$VIDEO_ID/final-v$LAST_V.mp4` 还在
|
|
182
|
-
- 不做"标记 active 版本"功能(SPEC §决策表 #3:final-vN 并存)
|
|
183
|
-
|
|
184
|
-
如果用户问"怎么撤销刚才的改动" → 告诉文件路径 + 提示"meta.md 当前版本字段可以手改回旧 v 号,或者再让我改回去"。
|
|
201
|
+
- final-v<NEXT>.mp4 留着(磁盘占用接受)
|
|
202
|
+
- 告诉用户旧版本 `~/digital-human/videos/<VIDEO_ID>/final-v<LAST>.mp4` 还在
|
|
203
|
+
- 不做"标记 active 版本"功能(final-vN 并存)
|
|
185
204
|
|
|
186
205
|
---
|
|
187
206
|
|
|
@@ -189,10 +208,12 @@ LLM 解析:"最后一段"= `seg-$(ls segments/seg-*.txt | wc -l | xargs printf "
|
|
|
189
208
|
|
|
190
209
|
| ❌ Mistake | ✅ 正确做法 | 为什么 |
|
|
191
210
|
|---|---|---|
|
|
192
|
-
|
|
|
193
|
-
|
|
|
194
|
-
|
|
|
195
|
-
|
|
|
196
|
-
|
|
|
197
|
-
|
|
|
198
|
-
|
|
|
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 |
|