Skip to content

Repository files navigation

VoiceLife 声活

语音优先、IM 辅助的本地日程与提醒系统

把安排说出来。本地可靠记住,到点通过语音和消息把你叫回来。

快速开始 · 架构 · 适配器 · 开发工具 · 参与开发

CI ESP-IDF 6.0.2 ESP32-S3 C++ 20

查看图片

VoiceLife 声活设备概念图
产品概念图(非当前交付固件)

Important

当前仓库交付的是可编译、可串联、可验证的架构主干。日程创建链路已经通过内存适配器跑通;真实音频、XRobot、持久化和 IM 平台适配器仍待后续 Issue 填实,不能当作可用产品固件。

SQLite 不是“能跑就算过”

我们在目标 ESP32-S3 上验证了 SQLite 与实际文件系统的事务行为,而不是只跑一条增删改查。结果很明确:SQLite 3.53.4 + FATFS/Wear Levelling 在四轮外部 EN 复位实验中通过;LittleFS + SQLite 的三组配置都在显式回滚后留下表记录、丢失索引记录,因此被否决。

当前合格基线固定为 4 KiB FATFS/WL 扇区、journal_mode=DELETEsynchronous=EXTRApsow=0、单连接和单写者。四轮平均提交耗时的中位数是 1,162,373 us,最慢一次 1,518,898 us,所以数据库提交不会进入音频实时路径。

Note

当前故障注入是串口控制线触发的外部 EN 复位,设备报告 rst:0x1 (POWERON)。它证明了重启恢复,不等于真实电源轨断电;断电、棕断、满容量和长期磨损仍在正式 Adapter 的验收清单中。

这里真正可复用的能力不是“ESP32 能运行 SQLite”,而是一套面向目标板的存储资格测试:显式回滚、跨表原子提交、表/索引一致性、关闭重开、故障点复位、资源水位,以及可恢复的 Flash 备份与回读校验。完整步骤见 SQLite 实板验证与 Flash 恢复手册,去掉 VoiceLife 业务表后的通用版本维护在 esp32-sqlite-durability-lab

快速开始

需要 CMake,以及构建设备固件时所需的 ESP-IDF 6.0.2。Ninja 可选;未安装时主机测试会使用 CMake 默认生成器。

# 提交前完整门禁,不需要 ESP-IDF
./scripts/run_pre_submit_checks.sh

# TDD 内循环:只运行当前模块测试
./scripts/run_host_tests.sh -R schedule_policy_test

# 查看并校验可用适配器 Profile
python3 scripts/firmware.py list
python3 scripts/firmware.py validate

构建 ESP32-S3 架构固件:

source /path/to/esp-idf-v6.0.2/export.sh
python3 scripts/firmware.py build esp32s3-dev

需要合并烧录镜像时:

python3 scripts/firmware.py package esp32s3-dev

架构

VoiceLife 是一个 ESP-IDF 组件化模块单体。业务核心使用纯 C++,外部世界只能通过 Port 进入;XRobot、微信、飞书、Koishi、网络库、存储格式和具体板卡都留在 Adapter 一侧。

架构图

依赖只有一个方向:适配器依赖用例,用例依赖领域,领域不反向认识 ESP-IDF、HTTP 或平台 SDK。scripts/check_architecture.sh 会在 CI 中检查这条规则。

五个刻意做出的设计

设计 解决的问题
日程与定时任务分开建模 Schedule 回答“安排了什么”,TimingTask 回答“何时触发哪一次”;周期、推迟不会污染日程主记录
一次 Port 完成原子写入 创建日程时,Schedule 与 TimingTask 要么一起成功,要么都不出现;底层可以从内存平滑迁移到 SQLite 或其他本地库
IM 只接收语义意图 核心发送 schedule.createdreminder.due,不出现“微信模板 ID”或“飞书卡片 JSON”
能力声明代替平台分支 适配器声明 rich-cardinteractive-actiondelivery-receipt 等能力,配置选择实现,核心不写 if platform == wechat
小智放在防腐层外侧 逐步迁移小智的音频、唤醒和 WebSocket 能力,不把它的全局状态机和板型矩阵带进业务核心

组件

Component 职责 允许依赖
voicelife_contracts 错误、结果和工具调用公共契约
voicelife_schedule 日程实体、命令、结果和服务接口骨架 contracts
voicelife_timing 定时任务、实例和提醒规则 contracts
voicelife_mcp Tool Schema、注册中心与调用路由 contracts
voicelife_voice 会话、音频和工具调用编排 contracts
voicelife_storage_sqlite SQLite 生命周期、命名语句、事务回执与健康指标底座 contracts
voicelife_runtime 唯一组装入口,不承载业务规则 contracts、mcp、voice

文件树

VoiceLife/
├── .github/
│   ├── ISSUE_TEMPLATE/          # Bug、功能、设计和工程任务入口
│   ├── workflows/ci.yml         # 提交、主机测试、架构和 ESP-IDF 构建检查
│   └── pull_request_template.md # PR 结论、验证、风险和 Review 清单
├── components/
│   ├── voicelife_contracts/     # 最小公共契约,不放业务工具箱
│   ├── voicelife_schedule/      # 日程领域结构与服务接口骨架
│   ├── voicelife_timing/        # 定时任务与触发规则
│   ├── voicelife_mcp/           # MCP 工具注册中心
│   ├── voicelife_voice/         # 语音会话协调器与 Port
│   ├── voicelife_storage_sqlite/ # SQLite 单连接、事务协议与健康指标底座
│   └── voicelife_runtime/       # Composition Root
├── config/
│   ├── adapter-profile.schema.json
│   └── profiles/                # 板卡与 Adapter 选择,不保存凭据
├── docs/
│   ├── adr/                     # 一次只记录一个重大架构决定
│   ├── architecture/            # 架构规范与小智迁移方案
│   ├── engineering/             # 协作、Review 和提交规范
│   └── assets/                  # README 素材
├── main/                        # ESP-IDF app_main,仅启动 Runtime
├── scripts/                     # 构建、诊断、边界检查与实板恢复工具
├── tests/
│   ├── board/                   # SQLite 等必须上板验证的故障探针
│   ├── host/                    # 按组件拆分的纯 C++ 单元与串联测试
│   └── python/                  # 构建工具与错误输入测试
├── third_party/licenses/        # 迁移代码与工具的第三方许可原文
├── CMakeLists.txt               # ESP-IDF 工程入口
└── sdkconfig.defaults           # 受版本控制的公共默认配置

适配器

Profile 把“这次固件使用哪些实现”写成可审查配置:

{
  "id": "esp32s3-dev",
  "target": "esp32s3",
  "adapters": {
    "audio": { "driver": "scaffold", "capabilities": [] },
    "speech": { "driver": "scaffold", "capabilities": [] },
    "storage": { "driver": "memory", "capabilities": ["atomic-calendar-write"] },
    "im": { "driver": "disabled", "capabilities": [] }
  }
}

当前已经实现 Profile Schema 校验、sdkconfig 选择和按 Profile 构建;Runtime 仍使用 scaffold、内存存储和禁用 IM 的固定装配。编译期工厂注册、能力核对和凭据引用解析尚未实现,真实 Adapter 接入前必须补齐,不能把 Profile 文件存在等同于运行时已经支持热切换。

例如接入飞书时,日程和提醒代码不需要修改。新增适配器实现、声明能力、补契约测试,再在部署配置中把 driverkoishi-wechat 换成 koishi-feishu。凭据只使用 secret://nvs://env:// 引用,不进入 Profile 和 Git。

完整规则见 架构与适配器设计规范

开发工具

78/xiaozhi-esp32 迁移并收敛了两项工具能力:

  • scripts/firmware.py:Profile 校验、ESP-IDF 构建、合并镜像和可追溯打包。
  • scripts/audio_debug_server.py:抓取设备通过 UDP 发出的原始 PCM,保存为 WAV,供音频链路诊断。
  • scripts/sqlite_board_probe.py:按分区表备份、写入非活动槽、注入 EN 复位、逐段回读校验并恢复原始数据。

上游来源和改造范围记录在 THIRD_PARTY.md,后续源码迁移策略见 小智能力迁移方案

当前进度

能力 状态 说明
组件边界与依赖检查 已完成 主机与 CI 可验证
分组件 TDD 主机测试 已完成 6 个单元测试与 1 个串联测试,可按名称筛选
MCP → 日程 → 定时任务串联 已完成 使用内存适配器,仅证明架构
ESP32-S3 固件构建 已完成 ESP-IDF 6.0.2 已验证
SQLite 存储资格测试 已完成基线验证 FATFS/WL 四轮通过;LittleFS 路线已否决;真实断电与寿命测试待补
Profile 驱动 Runtime 装配 待开发 当前只完成 Schema、构建选择和设计契约
小智音频与 XRobot Adapter 待开发 从上游能力逐段迁移
持久化 Adapter 待开发 只允许基于已验证底座实现,并复用单连接、迁移和事务生命周期
微信 / 飞书 IM Adapter 待开发 先稳定平台无关语义契约
真机闭环与用户试用 待开发 属于 MS3 功能 Issue

文档

致谢

VoiceLife 的设备侧语音能力建立在小智项目的工程经验之上。感谢 78/xiaozhi-esp32 及其贡献者开放音频、唤醒、协议和构建工具实现。

About

语音优先、IM 辅助的日程提醒工具。

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages