Commit Graph

154 Commits

Author SHA1 Message Date
7cb8cee70d feat: add device-side subtitle overlay using FreeType for rendering Chinese text
- Updated Cargo.toml to include freetype-rs for font rendering.
- Modified message.rs to introduce a new Message variant for subtitles.
- Enhanced HttpPlugin to send subtitle messages to the live2d plugin.
- Implemented text rendering in the live2d plugin using FreeType for Chinese characters.
- Added OpenGL shaders for rendering text overlays.
- Created a new text.rs module for handling text rasterization and texture rendering.
- Updated renderer.rs to integrate subtitle rendering logic.
2026-07-09 09:15:23 +08:00
9e31aee42d feat(live2d): 添加 Pose 处理模块以管理互斥 Part 的显示状态,优化模型加载和参数更新 2026-07-09 00:29:56 +08:00
514fca6000 feat(renderer): 添加遮罩支持,优化绘制流程和背景渐变 2026-07-09 00:11:48 +08:00
547085c819 feat: 添加 Live2D 渲染插件及相关依赖,优化构建和启动脚本 2026-07-08 17:32:56 +08:00
a8d7c03139 fix(renderer): 修正注释中的中文翻译以提高可读性 2026-07-07 16:59:45 +08:00
8f2ff558eb Refactor Live2D plugin and renderer for improved clarity and performance
- Updated EGL and OpenGL ES integration in gl.rs for better context management.
- Simplified error handling and logging in model.rs and plugin.rs.
- Enhanced texture handling and rendering logic in renderer.rs.
- Added a script to find Cargo configuration files for easier debugging.
- Removed unused imports and dead code to clean up the codebase.
2026-07-07 16:47:28 +08:00
86e36aa677 feat(live2d): 添加 Live2D 渲染插件及相关依赖,替代 Firefox kiosk 方案 2026-07-07 16:13:40 +08:00
2aac62b2bb feat(live2d): implement OpenGL ES 2.0 rendering backend with EGL support
- Add `gl.rs` for OpenGL ES 2.0 and EGL context management.
- Introduce `mod.rs` to organize Live2D plugin modules.
- Create `model.rs` for loading and managing Cubism models, including parameter handling and drawable data extraction.
- Implement shader compilation and rendering context setup for Live2D models.
2026-07-07 16:04:49 +08:00
9637bdd323 fix(Live2D): 用 bash kill -9 \ 替代 pkill(pkill 从 Rust 执行不生效) 2026-07-07 14:50:48 +08:00
00b9200235 fix(service): 去掉 User=showen(user service 不需要,导致 216/GROUP 错误) 2026-07-07 14:33:05 +08:00
e5a311fe3a fix(Live2D): pkill 用绝对路径 + service 加 PATH 环境变量 2026-07-07 14:11:23 +08:00
25508b4c66 fix(Live2D): pkill -9 强制杀 Firefox 进程树(SIGTERM 不够) 2026-07-07 13:59:04 +08:00
d64b393145 fix(Live2D): pkill firefox-esr 杀整个进程树(含 contentproc 子进程) 2026-07-07 13:39:54 +08:00
61256e4acb fix(Live2D): Firefox kiosk 进程清理用 pkill 兜底
Firefox esr 会 fork 子进程,child.kill() 只杀父进程导致残留。
三处清理(ConfigReloaded live2d 分支/切回视频分支/stop)都加
pkill -f live2d-display.html 兜底。
2026-07-07 13:33:59 +08:00
77d788d7a5 feat(Live2D): 设备端 Firefox kiosk 全屏渲染 Live2D 角色
Cubism Core 闭源且无 aarch64 Linux native 库,无法纯 Rust 原生渲染。
设备有 X11+kwin+Firefox 140+OpenGL,用 Firefox kiosk 模式全屏渲染
Live2D 模型(复用 Web 端 Cubism SDK),是 aarch64 上唯一可行路径。

1. src/plugins/http/live2d_display.html — 设备端专用全屏 Live2D 页面
   - 纯 Canvas 渲染,无 UI 控件
   - 轮询 /api/live2d/talking 驱动嘴部动效
   - 自动从 /api/config 读取 live2d_model 路径

2. src/plugins/http/mod.rs — HttpState 加 live2d_talking AtomicBool
   - set_live2d_talking/getter 方法

3. src/plugins/http/routes.rs
   - 新增 GET /live2d-display.html 路由
   - 新增 GET /api/live2d/talking 路由(设备端轮询)
   - chat_text_route 对话开始时 set_live2d_talking(true)
   - 回复后按字数估算时长延迟 set_live2d_talking(false)

4. src/plugins/video/mod.rs — Live2D 模式管理 Firefox kiosk 进程
   - ConfigReloaded render_type=live2d:停止视频,启动 firefox --kiosk
   - ConfigReloaded render_type=video:杀掉 Firefox,恢复视频播放
   - stop() 清理 Firefox 子进程
2026-07-07 13:24:57 +08:00
af5b975375 fix(Web): 角色列表显示所有角色 + 区分视频/Live2D 模式
问题:切到 live2d 配置后角色列表只显示一个角色;角色卡片用当前配置的
character 信息渲染,而非各配置自己的。

1. routes.rs config_available_route 扩展返回结构
   - configs 从字符串数组改为对象数组,每项含 filename + character 元信息
     (name/character_type/render_type/live2d_model)
   - 读取每个配置文件提取 character 块

2. chat.js loadCharacters 用各配置自己的 character 元信息渲染卡片
   - 显示角色名/类型徽章/渲染模式(video/live2d)
   - Live2D 角色额外显示模型路径
   - 策略说明区分"视频播放+状态机"和"Canvas渲染+嘴部动效"

3. chat.js switchCharacter 改为 await loadConfig() 确保配置加载后再刷新
   loadAvailableConfigs 兼容新旧返回结构
2026-07-07 12:26:45 +08:00
53ed155299 fix(Live2D): 用完整 dog 配置结构生成 live2d_anime.json
之前手写的配置缺少 scenes/triggers/transition 等必需字段导致解析失败。
改为基于 dog_state_machine.json 复制并替换 character 块 + display 块,
保留完整的 playlist/scenes/state_machine 结构,仅修改角色相关字段。
设备验证:--validate 通过,配置切换成功,文字对话正常(小雅人设生效)。
2026-07-07 12:18:23 +08:00
297c2a86fe fix(Live2D): 修正 Haru 模型路径 + gitignore 排除 live2d 模型文件
- live2d_model: haru/index.model3.json → haru/Haru.model3.json(匹配实际文件名)
- .gitignore: 添加 configs/live2d/(模型文件 4.2M 不进 git,部署时单独下载)
- .gitignore: 添加 .commit_msg.txt
2026-07-07 12:00:18 +08:00
39fa2a135a feat(Live2D): 集成 Cubism Web SDK 实现二次元角色渲染
1. routes.rs 新增 GET /live2d/* 静态文件路由
   - 从 source_dir/live2d/ 托管模型文件(.moc3/.model3.json/.png/.physics3.json)
   - 路径穿越防护(禁止 .. 段,canonicalize 校验在 base 内)

2. chat.html 引入 Live2D 渲染依赖
   - PixiJS v6.5.10 + Cubism Core + pixi-live2d-display(CDN)
   - 支持 Cubism 2.1 和 4 全版本模型

3. chat.js 实现 Live2D 模型加载与渲染
   - applyCharStrategy live2d 分支:初始化 PIXI.Application + canvas
   - loadLive2DModel:从 /live2d/<model_path> 加载模型,自动缩放居中
   - 说话动效:对话期间 ParamMouthOpenY 正弦波开合(模拟说话)
   - 呼吸动效:ParamBreath 持续起伏
   - destroyLive2D:切角色时清理 PIXI 资源

4. configs/live2d_anime.json 新建二次元角色"小雅"
   - character_type: live2d, render_type: live2d
   - live2d_model: haru/index.model3.json(Cubism 官方免费样例)
   - persona: 温柔二次元少女人设
   - playlist 复用 dog 的视频作为占位(Live2D 模式下 Web 端显示 canvas)
2026-07-07 11:56:29 +08:00
1ab77df85d refactor(Web): 统一入口 — 合并旧控制台与 AI 对话页为单一 chat.html
- / 和 /index.html 和 /chat 都服务统一页面(原 / 服务旧 WEB_UI_HTML)
- 删除 routes.rs 内嵌的 WEB_UI_HTML 常量(424 行),HTML 拆为 chat.html + chat.js
- 整合 8 个 tab:对话 / 角色 / 模型 / 播放控制 / 视频管理 / 文件管理 / 网络设置 / 系统配置
- 保留全部旧功能:WS 实时状态、播放控制、触发器、视频上传/删除、文件管理器、WiFi 扫描/连接/热点、BLE、配置切换/编辑/显示设置、APK 下载弹窗
- 保留全部新功能:文字对话、语音录音(客户端 WAV 转码)、角色切换、模型管理、Live2D 占位
2026-07-07 11:29:53 +08:00
90860bcf61 delete: 移除端到端测试脚本 (.test_e2e.sh) 2026-07-06 16:51:10 +08:00
5df99ced7b feat(M2.1): Web 端语音录放闭环
1. 新增 GET /api/chat/audio/file?path=<tmp_dir内路径> 路由
   - 路径白名单:canonicalize 后必须位于 config.ai.tmp_dir 内
   - 返回 audio/wav 二进制流(浏览器可直接 <audio> 播放)
   - 60s 后自动清理临时文件
   - 修复:原 /download/:filename 只能读 downloads_dir,TTS 输出在 tmp_dir 无法访问

2. POST /api/chat/audio 支持 X-Audio-Format 头
   - 浏览器 MediaRecorder 产 webm/ogg/m4a,whisper-cli 靠扩展名判断格式
   - 服务端按头指示决定文件扩展名(webm/ogg/m4a/mp3/wav)

3. chat.html 录音 UI + 客户端 WAV 转码
   - 按住🎙按钮录音(MediaRecorder),松开发送
   - 客户端用 Web Audio API 解码 + 重采样到 16k 单声道 PCM16
   - 手写 WAV header,输出标准 16k mono wav(whisper-cli 直接可处理)
   - 非安全上下文(HTTP)下禁用录音并显示 Chrome flag 启用指引
   - 回复音频改用 /api/chat/audio/file 路径播放
   - 显示 ASR 转写文本(🎤 你说: xxx)
2026-07-06 14:18:17 +08:00
8617a0e708 feat(M2.1): Web UI 统一入口+角色类型策略+Live2D 渲染支持+Gemma4 清单
- chat.html: 统一入口, 当前角色信息条, 四种角色类型策略 (pet/human/singer/live2d)
- 对话时根据 render_type 触发不同策略: video 切 talk/idle, live2d 显示动效
- config.rs: 新增 CharacterType::Live2d + RenderType 枚举 + live2d_model/live2d_config 字段
- model_manager.rs: 默认清单加 Gemma 4 E2B Q4_K_M (下载链接, 不含文件)
2026-07-06 12:49:46 +08:00
0c625a0c9a fix: 模型文件不进 git (加 .gitignore, 从索引移除 3.2GB gguf)
模型文件通过 model_manager.rs 清单里的 URL 在线下载,
不随 git 仓库分发。.gitignore 新增 model_download/ model_store/。
2026-07-06 12:41:36 +08:00
0ac4aa31c8 feat(M2.1): Web 对话控制端 (/chat 页面 - 文字对话+角色切换+模型管理) 2026-07-06 10:24:34 +08:00
2f202b82b7 fix: dog 配置 flip_vertical 改为 false (画面上下反了) 2026-07-06 09:51:39 +08:00
b0e201a16f fix: 清理真正的退格符 \u{8} (llama-cli 进度动画) 2026-07-04 17:39:42 +08:00
15ab383603 fix: 编译错误 (\b 转义 + 临时变量生命周期) 2026-07-04 17:35:45 +08:00
9069145de6 fix: 解析 llama-cli 进度动画和回复在同一行的情况 (清理 \b 转义) 2026-07-04 17:28:06 +08:00
1c037db0c2 fix: 解析 llama-cli 输出,只提取生成回复 (去除 banner/进度动画/统计) 2026-07-04 17:18:58 +08:00
a3052ad6db fix: piper 加 ESPEAK_DATA_PATH 环境变量 (espeak-ng-data 目录) 2026-07-04 17:10:23 +08:00
dc20fd3502 fix: piper_lib_dir 修正为 piper/piper 子目录 (库文件实际位置) 2026-07-04 17:04:21 +08:00
4fd7e7997e fix: piper 二进制+依赖库+config 修正 (符号链接指向正确二进制,加 LD_LIBRARY_PATH 和 -c 参数) 2026-07-04 16:58:41 +08:00
706b1375ce fix: llama-cli 加 --single-turn --no-warmup -sys,对齐 spike 调用方式 (修复卡死) 2026-07-04 16:39:33 +08:00
8fc82813d3 fix: ensure_default_models 每次启动重新检查模型文件存在性 2026-07-04 16:02:42 +08:00
6810d1ca13 feat(M2.1): 设备端部署脚本 + whisper LD_LIBRARY_PATH + dog/cat 角色人设配置 2026-07-04 15:44:48 +08:00
4877d54a1c fix: 修复 main.rs config move 后借用错误 (提前提取 ai 配置) 2026-07-04 15:12:16 +08:00
1bb044a3d7 fix: 修复 M2.1 骨架编译错误 (import/match/AppConfig 字段) 2026-07-04 15:09:11 +08:00
a0c4ca2307 feat(M2.1): AI 语音对话插件骨架 + 模型管理 + HTTP API + config schema 扩展
这是 M2.1(语音数字生命 V1)的后端骨架实现,不含 Web UI / Flutter / 设备部署。

新增文件:
- src/plugins/ai/mod.rs: AiPlugin 薄层(持有 ChatPipeline Arc,处理消息系统联动)
- src/plugins/ai/backend.rs: AiBackend trait + LocalCliBackend (whisper-cli/llama-cli/piper 子进程)
  + CloudBackend 占位(V1 返回"暂未支持")
- src/plugins/ai/chat.rs: ChatPipeline 对话管线执行器(HTTP 层 spawn_blocking 直接调用)
- src/plugins/ai/model_manager.rs: ModelManager 模型资产管理
  (清单/下载/切换/删除/配额/档位守门,参照 plugin_repo + version_manager 模式)

修改文件:
- src/core/message.rs: 新增 ChatRequest/ChatResponse/AiModelEvent 消息类型
- src/core/config.rs: AppConfig 新增 character 块(角色元信息+人设)+ ai 块(后端配置)
  均为 #[serde(default)] 向后兼容旧配置
- src/plugins/mod.rs: 注册 ai 模块
- src/plugins/http/mod.rs: HttpState 新增 ai_pipeline + ai_models 字段及注册方法;
  HttpPlugin 新增 set_ai_pipeline/set_ai_models 方法
- src/plugins/http/routes.rs: 新增 6 个 AI 相关路由
  - POST /api/chat/text (文字对话,Web 端主路径)
  - POST /api/chat/audio (语音对话,App 主路径)
  - GET /api/models (模型清单+水位+配额)
  - POST /api/models/download (下载模型,后台线程执行)
  - POST /api/models/switch (切换激活模型)
  - POST /api/models/delete (删除模型,保护当前激活)
- src/main.rs: 注册 AiPlugin,连接 pipeline 到 HttpPlugin

技术决策:
- 对话管线用 spawn_blocking 而非消息系统,满足 HTTP 同步响应需求
- ChatPipeline 用 Arc<Mutex> 共享,HTTP 和 AiPlugin 共用同一实例
- 互斥用 try_lock,忙时返回 409 而非阻塞
- Spike 结论固化: LLM t=2 锁大核、ctx=1024 限死、Qwen2.5-0.5B 默认档

待完成 (后续提交):
- Web 控制端 UI (文字对话 + 角色切换 + 模型管理界面)
- Flutter App (角色页/语音页/模型管理页)
- 设备端部署 llama.cpp/whisper.cpp/piper 二进制 + 模型下载
- 画面联动 (talk/idle 状态切换)
- 测试

注: Windows 开发环境缺 dbus,无法本地 cargo check;待目标机验证。
2026-07-04 15:01:00 +08:00
b066dd187b docs: CLAUDE.md 标记 P1/P2 修复目标机复验通过 (147/147 零 warning, SIGINT 234ms 退出) 2026-07-04 14:29:16 +08:00
a64d9907c3 docs: 更新 CLAUDE.md 待处理清单 - P1 Shutdown 修复标记完成, P2 部分完成, 新增待复验项 2026-07-04 12:35:27 +08:00
38dcd21352 refactor: P2 清理 - 闭环 check_updates 结果回传 + SDK 文档修正 + DeviceResponse 错误留痕
1. service_manager.rs check_plugin_updates: 返回 Vec<(id, cur, new)>,
   调用处通过 Custom { kind: "plugin_updates" } 广播结果,闭环 HTTP
   调用方获取检查结果的链路 (CLAUDE.md:163 第3项, 王浩然风险3 建议)

2. plugin-sdk/src/lib.rs broadcast 文档: 替换误导性的 WifiProvisioned
   示例为 StateChanged (当前真正闭环的消息),并新增 Phase 2 占位消息
   说明,列出 WifiProvisioned/DeviceEvent/CursorVisibility 三个当前无
   生产者的变体,提醒开发者不要为其编写业务逻辑 (CLAUDE.md:163 第1项)

3. src/plugins/device/mod.rs handle_message: DeviceResponse::Error
   转换时补 eprintln 留痕,避免设备层故障完全静默 (CLAUDE.md:163 第4项,
   王浩然风险3 建议: 至少在一处记录 Error 响应)

未处理项:
- 单实例保护 (锁文件/socket 互斥): 需目标机实测锁行为,留给设备端工程师
- unclutter 僵尸 reap: 核查发现 shutdown() 已做 kill+wait+pkill 兜底,
  仅 SIGKILL 极端场景残留,不值得加 SIGCHLD handler (过度工程)
- CursorVisibility 变体: 删除会破坏示例插件和测试,倾向 Phase 2 统一清理

注: Windows 开发环境缺 dbus/pkg-config, 无法本地 cargo check;
改动经 rust-analyzer 类型检查零诊断, 待目标机验证.
2026-07-04 12:27:35 +08:00
ab1dd9160c fix: 修复 Ctrl+C 无法及时退出主循环的 P1 bug
问题: main.rs Ctrl+C handler 只置 AtomicBool, 但 manager.run() 阻塞在
rx.recv() 永久等待下一条消息, 导致 Ctrl+C 后需等任意消息到达才能退出.
CLAUDE.md:162 记录的已知 P1 隐患 (王浩然发现).

修复 (3 处):
1. service_manager.rs run(): recv() -> recv_timeout(200ms), 超时则
   continue 重新检查 self.running, 确保信号能被及时响应
2. service_manager.rs handle_manager_message(): Shutdown 分支广播后
   置 self.running=false, 让主循环正常退出 (原本只广播不停机)
3. main.rs Ctrl+C handler: 除置 AtomicBool 外, 向 channel 注入
   Message::Shutdown envelope, 唤醒 recv_timeout 并触发优雅停机

效果: Ctrl+C 后最多 200ms 退出, 而非等待下一条任意消息.

注: Windows 开发环境缺 pkg-config/libdbus, 无法本地 cargo check;
改动经 rust-analyzer 类型检查零诊断, 待目标机 (Linux ARM64) 验证.
2026-07-04 12:22:51 +08:00
4d830c0e56 docs: 修正 README 与代码不一致 (edition 2021 + 补 device 插件) 2026-07-04 12:17:57 +08:00
9c290e19ab docs: M2.1 PRD 立项 + 团队沟通记录与状态同步
- 新增 docs/M2.1_PRD.md:语音数字生命 V1 产品需求文档(角色切换 + 语音回合 + 模型管理 + 双端交付)
- 更新 CLAUDE.md:M2.1 立项状态、spike 结论、待处理项
- 更新 .showen/TEAM_CHAT.md:团队最新沟通记录
- 更新 souls/zhang-mingyuan.md、souls/zhang-wanlin.md:成员状态
2026-07-04 12:04:01 +08:00
417dabb127 refactor: 更新团队成员状态和设备清理经验,优化文档内容 2026-07-03 15:17:59 +08:00
2a6e14b976 feat: Update project documentation and workflow to reflect changes in task dispatching and testing processes
- Changed references from "kilo" to "Agent 子代理" in various documentation files to align with the new task dispatching method.
- Updated CLAUDE.md to reflect the new agent-based execution model and modified task dispatch template.
- Revised PROGRESS.md to indicate successful testing and acceptance of M1.2 with detailed results.
- Enhanced communication and workflow documentation to clarify the use of Agent 子代理 for real-time collaboration and task management.
- Updated team member soul files with lessons learned from recent testing and integration experiences.
- Refactored test files to remove unused code and improve clarity, ensuring compliance with zero warning standards.
- Documented specific experiences and lessons learned during M1.2 testing, including handling of edge cases and configuration validation.
2026-07-03 14:14:50 +08:00
5770b7007c chore: remove unused Config type alias, add deny_unknown_fields to remaining config structs 2026-03-31 23:45:00 +08:00
1ded747a0c refactor: deduplicate HSV validation with loop over channel ranges 2026-03-31 23:43:44 +08:00
0cdea53f8d refactor: derive PartialEq + Eq for core message types (Destination, PlayerCommand, WifiCommand, etc.) 2026-03-31 23:43:06 +08:00