- BLE: 修复 BlueZ LocalName 与 Includes 冲突,串行注册与退避 - HTTP: 语音对话补 Live2D talking 标志与 session;Web 补 X-Session-Id - Flutter: 角色/对话/模型页 + API,Gradle/依赖升级,麦克风权限 - 文档: 新增 docs/STATUS.md,校准 CLAUDE/PROGRESS/README - 清理: 移除根目录截图与临时模型,运维脚本迁入 scripts/device
205 lines
6.5 KiB
Markdown
205 lines
6.5 KiB
Markdown
# M2.1 下一阶段实施计划
|
||
|
||
> 创建:2026-07-09
|
||
> 背景:功能不完善;AI 与 Live2D/视频**尚未完整联动**;App/Web 为半成品。
|
||
> 对照:`docs/STATUS.md`(现状)· `docs/M2.1_PRD.md`(产品定义)
|
||
|
||
---
|
||
|
||
## 0. 目标(本阶段完成的定义)
|
||
|
||
**可演示的闭环(P0 验收)**
|
||
|
||
1. 设备开机 → App/Web 可连
|
||
2. 切换角色(至少狗/猫/Live2D 配置)→ 画面与人设同步
|
||
3. 文字对话 → 客户端播 TTS → **画面有“在说话”反馈**
|
||
4. App 按住说话 → 同上
|
||
5. 模型列表可见;切换 LLM 后下一回合生效(失败有明确提示)
|
||
|
||
**不做本阶段(明确边界)**
|
||
|
||
- 设备本机麦克风/扬声器直连(硬件未接)
|
||
- 精细口型同步 / 流式打断
|
||
- 数字人/歌姬全套新视频素材制作
|
||
- 云端 LLM 实装
|
||
|
||
---
|
||
|
||
## 1. 现状结论(计划前提)
|
||
|
||
| 层 | 现状 |
|
||
|----|------|
|
||
| AI 管线 | 本地 ASR/LLM/TTS 可跑;HTTP `/api/chat/*` 可用 |
|
||
| Live2D | 有字幕 `Subtitle`;`live2d_talking` 标志在 HTTP 内,**未驱动嘴部动画** |
|
||
| 视频状态机 | 有 `talk_state` 配置字段;**对话不会 ChangeScene** |
|
||
| App | 角色/对话/模型页已写;真机旅程未系统验 |
|
||
| Web | chat 控制台有入口;HTTP 录音受限 |
|
||
| 仓库 | 2026-07-09 已提交整理与骨架改动(见 git log) |
|
||
|
||
---
|
||
|
||
## 2. 工作包拆分
|
||
|
||
### WP-A · AI ↔ 画面联动(核心缺口)
|
||
|
||
**A1. Live2D 说话态接通(优先)**
|
||
|
||
| 步骤 | 内容 | 验收 |
|
||
|------|------|------|
|
||
| A1.1 | 定义共享通道:消息 `Message::Live2dTalking { on: bool }` **或** 注入 Arc 状态到 Live2D 插件 | 二选一,文档写清 |
|
||
| A1.2 | HTTP chat 成功路径:开始 `talking=true`,结束按**音频时长或字数**回 `false` | 与 TTS 结束大致对齐(误差 ≤1.5s 可接受) |
|
||
| A1.3 | Live2D 渲染循环读 talking → `animation.set_talking` | 说话时嘴部开合,结束后回 idle |
|
||
| A1.4 | 字幕路径保持:`Subtitle` 继续走 | 字+嘴同时有反馈 |
|
||
|
||
**A2. 视频角色 talk 状态(次优先)**
|
||
|
||
| 步骤 | 内容 | 验收 |
|
||
|------|------|------|
|
||
| A2.1 | chat 开始:向 video 发 `ChangeScene(config.character.talk_state)` 或等价 trigger | 有 talk 片段则切过去 |
|
||
| A2.2 | chat 结束:回 `idle`(或配置的默认态) | 不卡在 talk |
|
||
| A2.3 | 无 talk 状态时优雅降级(日志 + 保持当前态,不 500) | 猫狗旧包不炸 |
|
||
|
||
**A3. 时长与互斥**
|
||
|
||
| 步骤 | 内容 |
|
||
|------|------|
|
||
| A3.1 | 优先用回复音频时长驱动 talking 窗口;无音频则字数估算 |
|
||
| A3.2 | 对话进行中拒绝二次对话 / 切角色(或排队策略写死一种) |
|
||
|
||
**负责建议**:内核/HTTP(张明远 or 王浩然)+ Live2D/视频(李思琪)
|
||
**预估**:A1 1~2 天 · A2 1 天 · A3 0.5 天
|
||
|
||
---
|
||
|
||
### WP-B · 设备对齐与回归
|
||
|
||
| 步骤 | 内容 | 验收 |
|
||
|------|------|------|
|
||
| B1 | 本机已提交代码同步到设备 `192.168.31.105` | git 一致或 rsync 可追溯 |
|
||
| B2 | `cargo check --workspace --all-targets` 零 warning | 贴输出 |
|
||
| B3 | `cargo test --workspace` 全绿 | 贴输出 |
|
||
| B4 | `systemctl --user restart showen_v2` + BLE ActiveInstances=1 | 服务稳定 |
|
||
| B5 | `POST /api/chat/text` 冒烟 | 有 reply_text;Live2D 有嘴/字幕 |
|
||
|
||
---
|
||
|
||
### WP-C · App 真机验收与修补
|
||
|
||
| 步骤 | 内容 | 验收 |
|
||
|------|------|------|
|
||
| C1 | 安装 debug APK,配置 `192.168.31.105:5000` | 能连 |
|
||
| C2 | 角色页切换 3 套配置 | 画面+人设变 |
|
||
| C3 | 文字对话 + 自动播 TTS + 重播 | 有声有字 |
|
||
| C4 | 按住说话一轮 | 转写+回复(允许慢) |
|
||
| C5 | 模型页列表/切换 | 失败有文案 |
|
||
| C6 | 按失败项修 Flutter(超时、503、权限) | 不再静默失败 |
|
||
|
||
**依赖**:WP-A 至少完成 A1 后再验“说话联动”。
|
||
|
||
---
|
||
|
||
### WP-D · Web 验收与修补
|
||
|
||
| 步骤 | 内容 |
|
||
|------|------|
|
||
| D1 | 角色/文字对话/模型三页真机点通 |
|
||
| D2 | HTTP 下录音禁用时的固定文案(与 PRD 一致) |
|
||
| D3 | 切角色清空会话上下文 |
|
||
|
||
---
|
||
|
||
### WP-E · 产品化收尾(P1,A~D 之后)
|
||
|
||
| 步骤 | 内容 |
|
||
|------|------|
|
||
| E1 | App 对话历史本地持久化 + 一键清空 |
|
||
| E2 | 模型下载进度轮询/失败重试 UX |
|
||
| E3 | release APK 签名与安装说明 |
|
||
| E4 | M1.2 tag `m1.2`(老板) |
|
||
| E5 | 素材:数字人/歌姬 talk/idle(外部依赖,可并行) |
|
||
|
||
---
|
||
|
||
## 3. 推荐执行顺序
|
||
|
||
```text
|
||
Day 0 本计划评审(老板/CEO)
|
||
Day 1 WP-A1 Live2D talking 接通 + B 设备同步回归
|
||
Day 2 WP-A2 视频 talk 降级策略 + A3 互斥
|
||
Day 3 WP-C App 真机四旅程 + 修洞
|
||
Day 4 WP-D Web 点通 + 文档 STATUS 更新
|
||
Day 5+ WP-E 按优先级穿插
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 技术要点备忘(实现时)
|
||
|
||
### 4.1 Live2D talking 推荐实现
|
||
|
||
```
|
||
HTTP chat 开始
|
||
→ state.set_live2d_talking(true)
|
||
→ tx.send(Message::Live2dTalking { on: true }) // 或等价
|
||
→ tx.send(Message::Subtitle { text })
|
||
|
||
Live2DPlugin::handle_message
|
||
→ renderer.set_talking(on)
|
||
|
||
HTTP chat 结束(spawn 延迟)
|
||
→ set_live2d_talking(false) + Live2dTalking { on: false }
|
||
```
|
||
|
||
避免 Live2D 去轮询 HTTP 内部 AtomicBool(跨插件耦合差)。
|
||
|
||
### 4.2 视频 talk
|
||
|
||
```
|
||
render_type == video 时:
|
||
chat 开始 → PlayerCommand::ChangeScene(talk_state)
|
||
chat 结束 → ChangeScene("idle") // 或配置 default_idle
|
||
无该 scene 时: 忽略并 log,不返回 5xx
|
||
```
|
||
|
||
### 4.3 验证命令(设备)
|
||
|
||
```bash
|
||
ssh -p 2222 showen@192.168.31.105
|
||
systemctl --user status showen_v2
|
||
curl -sS -m 60 -X POST http://127.0.0.1:5000/api/chat/text \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"text":"你好","session_id":"plan_test"}'
|
||
# 同时观察 Live2D 嘴部与字幕
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 风险
|
||
|
||
| 风险 | 应对 |
|
||
|------|------|
|
||
| 对话延迟 5~15s 体感差 | 先保证正确联动;优化单独立项(锁核/更小模型) |
|
||
| 宠物包无 talk 片段 | 强制降级,不阻塞 Live2D 路径 |
|
||
| 设备与 git 漂移 | B1 强制对齐后再验 |
|
||
| 录音权限/机型差异 | App 明确权限引导;失败可走文字 |
|
||
|
||
---
|
||
|
||
## 6. 完成检查清单(勾选)
|
||
|
||
- [ ] Live2D:对话时嘴部动画 + 字幕
|
||
- [ ] 视频:有 talk 则切 talk,无则降级
|
||
- [ ] App:角色 / 文字 / 语音 / 模型 四旅程通过
|
||
- [ ] Web:角色 / 文字对话 / 模型通过
|
||
- [ ] 设备 `cargo test --workspace` 全绿
|
||
- [ ] `docs/STATUS.md` 矩阵更新为与实机一致
|
||
- [ ] (可选)release APK
|
||
|
||
---
|
||
|
||
## 7. 变更记录
|
||
|
||
| 日期 | 说明 |
|
||
|------|------|
|
||
| 2026-07-09 | 初稿:联动缺口 + 分 WP 计划;对应 git 提交含骨架与整理 |
|