# Manage Avatars & Videos

管理 `~/digital-human/` 工作空间下的分身(`avatars.md`)+ 生成过的视频(`videos/<id>/`)+ 训练素材(`training/<id>/`)。

## "我的分身有哪些"

直接 Read `~/digital-human/avatars.md` 渲染给用户。

文件不存在 → "你还没训过分身,要训一个吗?"(走 [train.md](train.md))

文件存在但只有表头(无数据行)→ 同上。

## "我的视频有哪些" / "列我的视频" / "做过哪些视频"

> ⚠️ **沙箱 bash 须知**(同 [generate.md §0](generate.md)):agent-runtime 的 bash 软拒绝 `for`/`while` 循环、`$( )`、`| grep`/`| sed`/`| awk`/`| wc` 管道、`>` 重定向。所以**别写 `for d in $(ls ...)` 循环**逐目录抓字段——靠 **LLM 自己迭代**:一条 `ls` 列目录,再对每个目录用 **Read tool** 读 meta.md,字段(分身 / 当前版本 / 总文本 / 段数)你读出来自己提取、自己映射 emoji,**不靠 shell**。

**步骤**:

```bash
ls -t ~/digital-human/videos/
```

对列出的每个 `<video-id>`,**用 Read tool** 读 `~/digital-human/videos/<video-id>/meta.md`,从中读出:`avatar`(分身)、`当前版本`、`总文本`前 30 字、segments 表行数(= 段数)。**按"当前版本"值映射 state emoji**:

| "当前版本" 值 | 状态标注 |
|---|---|
| `(audio generating)` | 🚧 音频生成中 (中断,可续接) |
| `(audio-review pending)` | ⏳ 待试听确认 (audio-review pending) |
| `(rendering)` | 🎬 渲染中 |
| `(generating)` / `(review pending)`(旧 v1 字面量) | 📼 旧流程视频 (v1,改动需整条重生) |
| `final-vN.mp4` | ✅ final-vN.mp4 |
| 其它 | ❓ 未知 state |

渲染给用户(markdown 表格更友好):

| video-id | 分身 | 总文本(前 30 字) | 段数 | 状态 |
|---|---|---|---|---|
| 20260515-1430 | 张医生 | "大家好,我是张医生。今天介..." | 4 | ✅ final-v2.mp4 |
| 20260515-1620 | 李老师 | "今天讲..." | 5 | ⏳ 待试听确认 (audio-review pending) |
| 20260516-0915 | 王主任 | "..." | 3 | 🚧 音频生成中 (中断,可续接) |
| 20260514-0945 | 张医生 | "..." | 6 | ✅ final-v1.mp4 |

**用户暗示 + 操作引导**(给 LLM 的内部规则,**对用户**只输出自然语言话术,**不**报 §-编号):
- 看到 ⏳ → user-facing 提示 "想继续把 X 的音频听一下、确认出片吗?"(LLM 内部跳 [generate.md §6.5 重展试听 checkpoint](generate.md))
- 看到 🚧 → user-facing 提示 "想续生剩余音频段吗?"(LLM 内部跳 [generate.md §6.8 续生流程](generate.md))
- 看到 🎬 → user-facing 提示 "X 还在渲染,稍等;若中断了我可以重渲"(LLM 内部跳 [generate.md §6.8 → (rendering) 重渲](generate.md))
- 看到 📼 → 旧流程(v1 逐段视频)视频;用户说"改"时 [edit.md §1.5 Step 0](edit.md) 会拦下、引导整条重新生成(新旧不兼容)
- 看到 ✅ → 视频已完成,用户说"改 seg-N"时由 [edit.md §1.5 state check](edit.md) 路由

文件夹不存在 / 空 → "你还没生成过视频,要做一条吗?"(走 [generate.md](generate.md))

## "把张医生改成张主任"

1. Read `~/digital-human/avatars.md`
2. 在"名字"列找 `张医生`
3. Edit 该行"名字"列的 cell:`张医生` → `张主任`
4. 反馈"已改名,external_id 不变,以后可以用'张主任'引用了"

如果用户给的旧名字找不到 → 反问"没找到叫'张医生'的分身,你现在的分身有:[列出]"

## "删了张医生"

1. Read `~/digital-human/avatars.md`
2. 找到"张医生"行,记下该行所有字段(名字 / external_id / 训练时间 / preview URL)
3. **二次确认 + 显式列出恢复锚点**:
   > "确认删除'张医生'? **注意**:这是对你视角的硬删除 —
   > - 你失去所有引用路径(external_id 从你视野消失 + 没有 list 端点)
   > - 后端 DB 行成为 orphan 数据,**找回需要联系运维直接查 DB**
   > - 运维查 DB 需要锚点,以下信息删除后你将看不到,**建议先记下来或截图**:
   >   - 名字:`张医生`
   >   - external_id:`dh-a7f2k9m1`
   >   - 训练时间:`2026-05-14`
   >   - preview:`https://...preview.jpg`
   > 真要删吗?"
4. 用户确认 → 删该行
5. 反馈"已从你的列表删除'张医生'。如需找回请向运维提供上述 4 个锚点(名字 / external_id / 训练时间 / preview URL)。"

如果用户给的名字找不到 → 同上反问。

## 存量分身(用户在前 SPEC 落地之前训过 `dr-wang` 等)

用户说"用 dr-wang 做视频"但 `~/digital-human/avatars.md` "名字"列没有 `dr-wang`:

1. LLM 判断 `dr-wang` 是纯 ASCII + 含 `-` + 不在名字列 → 怀疑是存量 slug
2. LLM 试着 `gen avatar profile dr-wang`(后端单查仍支持任意 external_id)
3. **找到**(返回非 null) → 询问:
   > "我发现你有个分身叫 'dr-wang',要起个友好名字加到你的列表吗?(以后可以用'张医生'这种说法引用,而不是记英文 slug)"
   - 用户给名字 → 追加一行到 `avatars.md`:`| <用户给的名字> | dr-wang | <profile.created_at 或当天> | <preview_image_url> |`
   - 用户说"不用" → 直接走生成流程,但下次还会反问
4. **找不到** → 反问"没训过 dr-wang,要训吗?"

这是**自动迁移路径**,不强制,用户继续用 dr-wang 也行。

## "删了视频 20260515-1430"

视频删除跟分身删除不同 —— 视频 workspace 是用户私有目录,直接删干净,**没有**后端 DB 行残留:

1. 确认 video-id 存在(`ls ~/digital-human/videos/<id>`)
2. 二次确认:
   > "确认删除视频 `<id>`(<段数> 段, 当前 final-vX.mp4)?
   > 这会删除整个目录(segments / final-v* / meta.md / history.md),**不可恢复**。"
3. 用户确认 → `rm -rf ~/digital-human/videos/<id>`
4. 反馈"已删除视频 `<id>`。"

跟分身删除的对比:分身有后端 DB 行,删 markdown 行 = orphan;视频纯客户端,删目录 = 真删干净。

## "改某段视频"

走 [edit.md](edit.md)。

## 磁盘占用查看

用户问"我用了多少磁盘"/"workspace 多大" → 让 ta 自己跑:

```bash
du -sh ~/digital-human/
du -sh ~/digital-human/training/*/
du -sh ~/digital-human/videos/*/
```

每个 training/<id>/ ~ 50-200 MB(主要是 source-video);每个 videos/<id>/ ~ 8-20 MB。

v1 不做自动清理。用户嫌占空间:
- 删旧视频:`rm -rf ~/digital-human/videos/<old-id>`
- 删某分身训练素材:`rm -rf ~/digital-human/training/<external_id>/`(但保留 `avatars.md` 那一行,以后还能用 ID 生成视频,只是不能重训了)

## "我有哪些分身做过 X"(进阶筛选)

v1 不支持。用户问就告诉:"workspace 不索引'分身 → 视频'反向关系。但可以 `grep` workspace:
```bash
grep -l 'external_id: dh-a7f2k9m1' ~/digital-human/videos/*/meta.md
```
找出该分身做过的所有视频。如需要常态化筛选请告诉我们。"

## LLM 读 avatars.md 时的健全性校验

每次 Read 后必须做一遍。**规则详见 [SKILL.md "工作空间" 段](../SKILL.md#工作空间)**,单源真值,本段不复述以免 drift。
