Diting AI 语音 Demo 入门开发指南
概述
Voice Cloud LLM 是 HiDiting V100 上的云端语音助手。用户打开 OpenHarmony Lite Wearable 应用后,可以用本地唤醒词发起对话。应用显示当前对话状态,固件负责麦克风采集、连接 Coze、接收回复和扬声器播放。
Demo 由 JS 前端和 Native 应用后端组成:
| 部分 | 目录 | 职责 |
|---|---|---|
| JS 前端(OpenHarmony 应用) | samples/js_samples/voice_cloud_LLM/ |
页面入口、状态展示、主题动画,以及语音服务的启动、停止和状态订阅 |
| Native 应用后端(设备侧) | samples/native_samples/voice_cloud_LLM/ |
本地唤醒、音频采集与播放、WebSocket 会话、云端通信和资源回收 |
用户在 JS 页面中操作。前端通过 @system.voiceCloudLlm 调用 Native 后端。后端完成设备侧语音处理和云端通信,再把状态和音频结果返回页面。进入应用时,JS 前端订阅语音状态并启动服务;退出应用时,它停止服务并恢复系统息屏策略。Native 后端属于示例应用的一部分,不能单独启动。
源码说明:
路径中的 LLM 为大写。在 Linux、WSL 和 GitCode 中需要保持大小写一致。
快速跑通AI语音Demo
硬件准备
- HiDiting V100 开发板。
- 466×466 分辨率表盘。
- 扬声器。开发调试可使用 8 Ω/2 W 扬声器。
- 可访问互联网的网络环境。本文使用手机热点和蓝牙 PAN。
构建应用还需要 DevEco Studio 5.0 Release、匹配的 OpenHarmony SDK、Python 3 和仓库内的 ImageTool。
Coze 准备
- 登录 Coze 官网 并注册账号。
-
创建个人访问令牌,记录
Access token。
下图红框中的内容是
Access token。
-
创建智能体,记录 URL 末尾的
bot id。
-
在电脑上创建
coze_setting.json:
当前固件只读取 bots[0]。配置文件需要满足以下限制:
| 字段 | 要求 |
|---|---|
| 文件大小 | 不超过 8192 字节 |
token |
1~255 字节;可带Bearer 前缀,正文仅允许字母、数字和 -._~+/= |
bots[0].name |
1~63 字节,不能包含控制字符 |
bots[0].botid |
1~95 字节,只能包含字母、数字和-._~ |
不要把真实令牌写入源码或提交到仓库。调试时也不要在截图、日志和问题单中暴露令牌。
编译烧录
编译固件
完成一站式 CLI 环境配置后,在仓库根目录执行:
固件产物为:
如果不使用一站式 CLI,也可以进入 src 目录执行:
准备应用图片转换工具
解压仓库中的 tools/graphic_tools.tar.gz,将 ImageTool 指向同时包含 images_tool.py 和 config.xml 的目录。
Linux 或 macOS:
Windows PowerShell:
$env:ImageTool = "D:\absolute\path\graphic_tools\image_converter_tool"
$env:PYTHON = "C:\Path\To\python.exe"
当前主题使用的 PNG 需要放在:
图片文件必须与 common/theme/current_theme.js 中的引用完全一致。构建任务会检查文件并在中间目录完成图片转换,不需要手工生成或提交 .bin 文件。
构建应用
- 参考 OpenHarmony JS 应用开发用户指南 的
JS 应用开发与发布章节完成DevEco Studio 5.0 Release工具准备。 - 使用 DevEco Studio 打开
samples/js_samples/voice_cloud_LLM。 - 选择
Build > Build Hap(s)构建得到应用包 BIN 文件,文件位于工程entry/build/default/outputs/default/bin/目录下。 - 使用 DebugKits 的
System > 上传文件,把应用包 BIN 文件上传为/user/voice_cloud_llm.bin。进度达到 100% 才表示上传完成(文件较大,需要耐心等待上传完成)。操作方法参见 DebugKits 工具使用指南。 - 在串口执行
AT+OHOS=OHOSFWK_BM_SET,disable关闭验签。 - 在串口执行
AT+OHOS=OHOSFWK_BM_INSTALL,/user/voice_cloud_llm.bin完成应用包安装。
只修改 JS、页面样式或主题图片时,重新构建并安装 BIN 即可,不需要重编固件。
上板运行
-
烧录
diting-community.fwpkg,打开 UART2 串口监视器。Windows USB DFU 示例:fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180 fbb monitor --port COM3 --baud 750000将
COM3替换为实际日志串口。其他烧录方式参见 一站式 CLI 开发环境使用指南。 2. 打开手机热点并启用蓝牙共享网络,与开发板建立蓝牙连接。 3. 执行AT+PM=0关闭低功耗。 4. 执行AT+NET=NETSTACK_SWITCH,PAN切换到蓝牙 PAN 配网。串口日志出现pan CONNECTION_CONNECTED即配网成功。 5. 使用 DebugKits 的System > 上传文件,把coze_setting.json上传为/user/coze_setting.json。进度达到 100% 才表示上传完成。操作方法参见 DebugKits 工具使用指南。 6. 安装应用包 BIN 后,启动Voice Cloud LLM应用。 7. 页面显示“等待唤醒”后,说出固件支持的唤醒词,例如“小艺小艺”。页面转变为倾听动画,显示“请说话”后即可开始对话。
启动应用后,页面会自动订阅语音状态并启动语音服务;退出应用时,页面会停止服务、取消状态订阅并恢复系统息屏策略。每次启动语音服务时,应用都会重新读取 /user/coze_setting.json。
当前固件默认映射的唤醒词包括“小艺小艺”“你好悠悠”“小薇小薇”和“嗨,塞莉亚”。
连续对话空闲约 15 秒后,应用会回到等待唤醒状态。
代码走读
代码结构
JS 前端主要文件:
samples/js_samples/voice_cloud_LLM/
├── entry/hvigorfile.ts
│ └── 校验并转换当前主题图片
└── entry/src/main/js/MainAbility/
├── app.js
├── common/theme/
│ ├── current_theme.js
│ └── assets/
└── pages/index/
├── index.hml
├── index.css
├── voice_page.js
├── voice_state.js
├── voice_animation.js
└── voice_animation_config.js
Native 应用后端主要文件:
samples/native_samples/voice_cloud_LLM/
├── voice_cloud_llm.cpp
├── voice_cloud_llm_audio_capture.cpp
├── voice_cloud_llm_audio_player.cpp
├── voice_cloud_llm_ws_client.cpp
├── voice_cloud_llm_protocol.cpp
├── voice_cloud_llm_config.cpp
└── ace_adapter/
ACE Lite 中的 @system.voiceCloudLlm 模块位于:
核心函数
| 位置 | 函数或配置 | 作用 |
|---|---|---|
voice_page.js |
createVoicePage() |
管理页面生命周期、语音服务调用和动画状态队列 |
voice_animation.js |
createAnimationWindow() |
每次向组件装载不超过 20 个逻辑时间片 |
voice_animation_config.js |
STATE_CLIPS、TRANSITION_CLIPS |
把语音状态映射到循环动画和转场动画 |
current_theme.js |
CURRENT_THEME |
配置当前主题图片及每张图的显示时长 |
voice_cloud_llm_module.cpp |
VoiceCloudLlmModule |
向 JS 提供启动、停止、状态查询和状态订阅接口 |
voice_cloud_llm_service.cpp |
StartVoiceCloudLlmService()、StopVoiceCloudLlmService() |
读取/user/coze_setting.json 并调用设备侧语音接口 |
voice_cloud_llm.cpp |
VoiceCloudLlmWorker |
处理唤醒、会话、超时和资源回收 |
ace_adapter/ |
RegisterVoiceCloudLlmNativeApi() |
连接 ACE 模块和设备侧语音组件 |
页面的 onShow 会订阅状态并调用 start();onHide 和 onDestroy 会执行幂等清理。
如果固件没有 @system.voiceCloudLlm,应用仍能打开,但会提示“当前固件缺少语音模块”。
状态机
页面按对话进度显示以下状态:
| 页面状态 | 含义 | 典型触发条件 |
|---|---|---|
| 等待唤醒 | 本地唤醒引擎正在监听 | 应用启动、会话结束或异常恢复 |
| 请说话 | 麦克风采集已开始 | 检测到唤醒词,或连续对话中检测到新一轮语音 |
| 思考中 | 用户说话结束,等待云端生成回复 | 设备侧检测到用户说话结束 |
| 正在回复 | 正在播放云端返回的 PCM 音频 | 收到下行音频数据 |
| 等待说话 | 本轮回复结束,可继续提问 | 云端会话完成 |
设备侧后端还维护 WebSocket 连接、会话创建、配置同步和资源回收等状态。这些状态不会直接显示在页面上,而是映射为上述页面状态或错误提示。修改主题时不需要调整设备侧状态机。
参数配置
先判断参数属于哪一层。不同层的修改方式不同。
| 配置内容 | 位置 | 生效方式 |
|---|---|---|
| Coze token、智能体 ID | /user/coze_setting.json |
重新进入应用,无需重编 BIN 或固件 |
| 主题图片和动画显示时长 | common/theme/ |
重新构建并安装 BIN |
| 页面文案和样式 | pages/index/ |
重新构建并安装 BIN |
| 音频格式、超时和队列 | voice_cloud_llm_config.h |
重新构建并烧录固件 |
音频规格
当前默认值位于 samples/native_samples/voice_cloud_LLM/include/voice_cloud_llm_config.h:
| 参数 | 默认值 | 宏 |
|---|---|---|
| 编码格式 | 上行默认 G.711 A-law;关闭宏后为 PCM | VOICE_CLOUD_LLM_UPLINK_CODEC_G711A |
| 上行采样率 | 采集 16000 Hz;G.711 上行 8000 Hz | VOICE_CLOUD_LLM_INPUT_SAMPLE_RATE、VOICE_CLOUD_LLM_G711_SAMPLE_RATE |
| 下行采样率 | 16000 Hz | VOICE_CLOUD_LLM_OUTPUT_SAMPLE_RATE |
| 声道数 | 单声道 | VOICE_CLOUD_LLM_DEFAULT_CHANNELS |
| 位宽 | 16 bit | VOICE_CLOUD_LLM_DEFAULT_BITS |
| 基础帧长 | 20 ms | VOICE_CLOUD_LLM_UPLINK_FRAME_MS |
| 每批帧数 | 8 | VOICE_CLOUD_LLM_UPLINK_BATCH_FRAMES |
这些参数同时影响音频驱动、云端协议和缓存大小。应用主题开发不需要修改它们。
超时与容量规格
| 参数 | 默认值 | 宏或常量 |
|---|---|---|
| WebSocket 连接超时 | 10 s | VOICE_CLOUD_LLM_CONNECT_TIMEOUT_MS |
| 会话响应超时 | 30 s | VOICE_CLOUD_LLM_RESPONSE_TIMEOUT_MS |
| 连续对话空闲超时 | 15 s | VOICE_CLOUD_LLM_IDLE_TIMEOUT_MS |
| Worker 消息队列 | 64 | VOICE_CLOUD_LLM_QUEUE_DEPTH |
| 预采集缓存 | 20 批次,约 3.2 s | voice_cloud_llm.cpp 中的 VOICE_CLOUD_LLM_PENDING_FRAMES_MAX |
| WebSocket 分片上限 | 64 KiB | voice_cloud_llm_ws_client.cpp 中的 VOICE_CLOUD_LLM_WS_FRAGMENT_MAX_LEN |
这些参数属于设备侧固件。修改后需要重新构建并烧录固件。
应用动画参数
应用动画参数位于 samples/js_samples/voice_cloud_LLM/entry/src/main/js/MainAbility/pages/index/voice_animation_config.js:
| 参数 | 默认值 | 常量 |
|---|---|---|
| 动画逻辑时间片 | 50 ms | FRAME_TICK_MS |
| 单次动画装载窗口 | 20 个时间片 | MAX_ACTIVE_FRAMES |
samples/js_samples/voice_cloud_LLM/entry/src/main/js/MainAbility/common/theme/current_theme.js 中的 hold 是图片显示时长参数,1 个单位对应 50 ms。例如 hold: 6 表示显示约 300 ms。
单次动画装载窗口表示单次装载时间片数量,与主题中物理图片的总数无关。
修改这些参数后只需重新构建并安装 BIN,不需要重编固件。
高阶开发参考指南
主题、文案和页面布局都在 OH 应用里修改,不需要改固件。
替换 OH 应用主题
当前主题目录是:
samples/js_samples/voice_cloud_LLM/entry/src/main/js/MainAbility/common/theme/
├── current_theme.js
└── assets/
替换步骤:
- 在
voice_cloud_LLM工程外准备一套主题,保留原始文件作为备份。 - 将要使用的 466×466 PNG 放入
assets/。目录内只能放当前主题实际使用的图片。 - 修改
current_theme.js,让每个src指向/common/theme/assets/<文件名>.png。 - 为每张图设置正整数的显示时长参数
hold。1 个单位对应 50 ms。 - 删除
assets/中未被清单引用的 PNG,并补齐清单引用但缺失的 PNG。 - 清理应用构建目录,重新构建并安装 BIN。
构建脚本要求图片平铺在 assets/ 中,文件名使用小写字母、数字和下划线。清单引用与实际 PNG 必须完全一致,否则构建会直接报错。
当前配置使用以下动画片段名:
| 片段 | 用途 |
|---|---|
sleeping_loop |
等待唤醒循环 |
wake_up |
从等待唤醒进入请说话 |
listening_loop |
请说话循环 |
listening_to_thinking |
从请说话进入思考中 |
thinking_loop |
思考中循环 |
thinking_to_speaking |
从思考中进入正在回复 |
speaking_loop |
正在回复循环 |
sit_down |
从回复进入等待说话 |
idle_daze、idle_rub_eye |
等待说话时交替播放 |
idle_to_listening |
连续对话重新进入请说话 |
lie_down |
空闲超时后回到等待唤醒 |
只换图片时保留这些片段名最省事。如果需要增删片段,还要同步修改 voice_animation_config.js 中的 STATE_CLIPS 和 TRANSITION_CLIPS。
主题图片数量没有代码上限,但图片越多,BIN 越大,安装和传输时间也越长。优先复用图片并延长显示时长(增大 hold),不要为延长静止画面复制多份相同 PNG。备用、历史和生成失败的主题应放在 voice_cloud_LLM 目录之外,避免被误带入应用工程。
调整动画速度和显示时长
多数节奏调整只需要修改 current_theme.js 中每张图片的显示时长(hold):
sleeping_loop: [
{ src: '/common/theme/assets/sleeping_loop_000.png', hold: 4 },
{ src: '/common/theme/assets/sleeping_loop_001.png', hold: 2 },
],
这里第一张图显示约 200 ms,第二张图显示约 100 ms。增大 hold 会延长显示,减小 hold 则会加快切换。
MAX_ACTIVE_FRAMES = 20 是运行时窗口大小。单张图片的显示时长即使超过 20 个时间片,运行时也会分多个窗口继续使用同一张图片,不需要复制资源。
如果确实需要改变全局时间粒度,可以修改 voice_animation_config.js 中的 FRAME_TICK_MS。这会影响所有片段,修改后应完整检查转场和循环节奏。
修改状态文案和页面布局
状态文案位于:
页面结构和样式位于:
entry/src/main/js/MainAbility/pages/index/index.hml
entry/src/main/js/MainAbility/pages/index/index.css
可以直接修改“等待唤醒”“请说话”“思考中”“正在回复”和“等待说话”等文案,也可以调整文字颜色、字号、背景和状态栏位置。表盘画布为 466×466,修改 CSS 后要检查文字是否超出屏幕,以及错误提示是否遮挡主题主体。
更换云端智能体
只更换 Coze 智能体时,不要修改源码。更新 /user/coze_setting.json 中的 token 和 bots[0],重新进入应用即可。
如果修改了文件但应用仍使用旧配置,先确认上传目标是 /user/coze_setting.json,再检查 DebugKits 进度是否达到 100%。应用在每次启动语音服务时读取该文件。
接入非 Coze WebSocket 服务需要重写鉴权和协议事件映射,不属于应用主题定制范围。这类改动会影响设备侧状态机、超时恢复和音频格式,应配套增加协议测试和板端测试。
判断是否需要重编固件
| 修改内容 | BIN | 固件 |
|---|---|---|
| 主题图片、显示时长、页面文案和 CSS | 重新构建 | 不需要 |
| JS 生命周期或状态动画逻辑 | 重新构建 | 不需要,前提是系统接口未变 |
@system.voiceCloudLlm 接口 |
重新构建 | 重新构建并烧录 |
| 设备侧音频、WebSocket、唤醒或状态机 | 通常不变 | 重新构建并烧录 |
/user/coze_setting.json |
不需要 | 不需要 |
固件和 BIN 应从同一版本源码构建。系统接口有变更时,旧 BIN 与新固件混用可能出现模块不可用、状态值不一致或启动失败。
第三方依赖清单
本应用运行时使用的第三方服务只有 Coze。DevEco Studio、OpenHarmony SDK、ImageTool 和 Python 用于构建应用,不参与板端语音会话。
| 第三方服务 | 用途 | 配置位置 |
|---|---|---|
| Coze WebSocket 语音会话 | 云端 VAD、对话生成和语音合成 | /user/coze_setting.json |
应用构建工具:
| 工具 | 用途 | 配置位置 |
|---|---|---|
| DevEco Studio 与 OpenHarmony SDK | 构建 BIN | JS 应用工程 |
| ImageTool 与 Python 3 | 将主题 PNG 转换为板端图片格式 | ImageTool、PYTHON 环境变量 |
WebSocket、cJSON、音频和本地唤醒能力来自工程或平台 SDK,不需要单独安装。默认云端地址是 wss://ws.coze.cn/v1/chat。
异常排查手册
| 现象 | 检查方法 |
|---|---|
| 页面提示“当前固件缺少语音模块” | 当前固件没有@system.voiceCloudLlm。重新构建并烧录 diting-community.fwpkg |
| 页面提示“语音状态订阅失败” | 检查固件与 BIN 是否来自同一版本,退出应用后重新进入 |
| 页面提示“语音服务启动失败” | 检查/user/coze_setting.json 的路径、JSON 格式、字段长度、token 和 bot ID |
| 蓝牙 PAN 无法联网 | 确认手机已开启蓝牙共享网络,并检查pan CONNECTION_CONNECTED、DNS、系统时间和 TLS |
| 说出唤醒词后无响应 | 确认应用在前台且页面显示“等待唤醒”,再检查麦克风和固件支持的唤醒词 |
| 说话后没有云端回复 | 检查网络、Coze 智能体、token、麦克风和扬声器;查看串口中的 WebSocket 或云端错误 |
| 云端回复较慢 | 在 Coze 智能体配置中选择响应更快的模型,按业务需要关闭深度思考 |
| 动画构建提示资源不一致 | 对照current_theme.js,删除未引用 PNG,补齐缺失 PNG,并检查文件名大小写 |
| 动画黑屏或不切换 | 确认图片是 466×466 PNG,显示时长参数hold 为正整数,片段名与 voice_animation_config.js 一致 |
| BIN 过大或上传较慢 | 减少物理图片,复用图片并增加显示时长(hold);工程内只保留当前主题 |
| 连续对话自动结束 | 默认空闲超时约 15 秒,重新说出唤醒词即可 |
注意事项
固件编译开关
src/build/config/target_config/3322/config.py 中的 diting-community 目标默认定义了 CONFIG_VOICE_CLOUD_LLM_ENABLE 宏。
这个宏同时控制以下内容:
- 编译
voice_cloud_LLM设备侧语音组件。 - 编译
ace_voice_cloud_llmJS 系统模块。 - 向 ACE Lite 注册
@system.voiceCloudLlm。
如果要关闭 Voice Cloud LLM,需要从 diting-community 的 defines 中移除 CONFIG_VOICE_CLOUD_LLM_ENABLE,并从 ram_component_set 中移除 voice_cloud_LLM_set。修改后重新构建固件。
如果只是暂时不用语音助手,不必关闭编译开关;不安装或不启动 BIN 即可。关闭宏后,仍然安装 Voice Cloud LLM BIN,页面会提示“当前固件缺少语音模块”。
配置与资源
- 应用会把麦克风音频发送到第三方云服务。部署前需要确认用户授权、云服务条款和隐私要求。
- 使用单独的最小权限令牌。令牌泄露后立即撤销并轮换。
/user/coze_setting.json是板端运行时配置,不要提交到仓库。- 应用工程内只保留当前主题。备用主题放在
voice_cloud_LLM目录之外。 - 不限制主题图片数量,但需要考虑 BIN 大小、板端存储、安装时间和运行内存。
- 主题目录只放清单引用的 PNG,不要提交构建生成的
.bin或entry/build/。 - 修改 JS 或主题时只需更新 BIN;修改 Native 后端、ACE 系统接口或唤醒能力时必须重新烧录固件。
- 页面退出会停止语音服务。调试后台行为时不要把正常的生命周期停止误判为服务异常。