跳转至

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 准备

  1. 登录 Coze 官网 并注册账号。
  2. 创建个人访问令牌,记录 Access token

    创建 Coze 个人访问令牌

    下图红框中的内容是 Access token

    查看 Coze Access token

  3. 创建智能体,记录 URL 末尾的 bot id

    创建 Coze 智能体并获取 bot id

  4. 在电脑上创建 coze_setting.json

    {
      "token": "替换为个人访问令牌",
      "bots": [
        {
          "name": "默认智能体",
          "botid": "替换为智能体 ID"
        }
      ]
    }
    

当前固件只读取 bots[0]。配置文件需要满足以下限制:

字段 要求
文件大小 不超过 8192 字节
token 1~255 字节;可带Bearer 前缀,正文仅允许字母、数字和 -._~+/=
bots[0].name 1~63 字节,不能包含控制字符
bots[0].botid 1~95 字节,只能包含字母、数字和-._~

不要把真实令牌写入源码或提交到仓库。调试时也不要在截图、日志和问题单中暴露令牌。

编译烧录

编译固件

完成一站式 CLI 环境配置后,在仓库根目录执行:

fbb set-target pack_diting_community
fbb build

固件产物为:

src/output/3322/fwpkg/diting-community.fwpkg

如果不使用一站式 CLI,也可以进入 src 目录执行:

python3 build.py pack_diting_community

准备应用图片转换工具

解压仓库中的 tools/graphic_tools.tar.gz,将 ImageTool 指向同时包含 images_tool.pyconfig.xml 的目录。

Linux 或 macOS:

export ImageTool=/absolute/path/graphic_tools/image_converter_tool
export PYTHON=/usr/bin/python3

Windows PowerShell:

$env:ImageTool = "D:\absolute\path\graphic_tools\image_converter_tool"
$env:PYTHON = "C:\Path\To\python.exe"

当前主题使用的 PNG 需要放在:

samples/js_samples/voice_cloud_LLM/entry/src/main/js/MainAbility/common/theme/assets/

图片文件必须与 common/theme/current_theme.js 中的引用完全一致。构建任务会检查文件并在中间目录完成图片转换,不需要手工生成或提交 .bin 文件。

构建应用

  1. 参考 OpenHarmony JS 应用开发用户指南JS 应用开发与发布 章节完成DevEco Studio 5.0 Release工具准备。
  2. 使用 DevEco Studio 打开 samples/js_samples/voice_cloud_LLM
  3. 选择 Build > Build Hap(s) 构建得到应用包 BIN 文件,文件位于工程 entry/build/default/outputs/default/bin/ 目录下。
  4. 使用 DebugKits 的 System > 上传文件,把应用包 BIN 文件上传为 /user/voice_cloud_llm.bin。进度达到 100% 才表示上传完成(文件较大,需要耐心等待上传完成)。操作方法参见 DebugKits 工具使用指南
  5. 在串口执行 AT+OHOS=OHOSFWK_BM_SET,disable 关闭验签。
  6. 在串口执行 AT+OHOS=OHOSFWK_BM_INSTALL,/user/voice_cloud_llm.bin 完成应用包安装。

只修改 JS、页面样式或主题图片时,重新构建并安装 BIN 即可,不需要重编固件。

上板运行

  1. 烧录 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 模块位于:

src/ohos/foundation/arkui/ace_engine_lite/frameworks/src/core/modules/voice_cloud_llm/

核心函数

位置 函数或配置 作用
voice_page.js createVoicePage() 管理页面生命周期、语音服务调用和动画状态队列
voice_animation.js createAnimationWindow() 每次向组件装载不超过 20 个逻辑时间片
voice_animation_config.js STATE_CLIPSTRANSITION_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()onHideonDestroy 会执行幂等清理。 如果固件没有 @system.voiceCloudLlm,应用仍能打开,但会提示“当前固件缺少语音模块”。


状态机

页面按对话进度显示以下状态:

等待唤醒
   │ 本地唤醒词
请说话 ──► 思考中 ──► 正在回复 ──► 等待说话
   ▲                                   │
   └──────────── 用户继续说话 ──────────┘
                                       │ 空闲约 15 秒
                                    等待唤醒
页面状态 含义 典型触发条件
等待唤醒 本地唤醒引擎正在监听 应用启动、会话结束或异常恢复
请说话 麦克风采集已开始 检测到唤醒词,或连续对话中检测到新一轮语音
思考中 用户说话结束,等待云端生成回复 设备侧检测到用户说话结束
正在回复 正在播放云端返回的 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_RATEVOICE_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/

替换步骤:

  1. voice_cloud_LLM 工程外准备一套主题,保留原始文件作为备份。
  2. 将要使用的 466×466 PNG 放入 assets/。目录内只能放当前主题实际使用的图片。
  3. 修改 current_theme.js,让每个 src 指向 /common/theme/assets/<文件名>.png
  4. 为每张图设置正整数的显示时长参数 hold。1 个单位对应 50 ms。
  5. 删除 assets/ 中未被清单引用的 PNG,并补齐清单引用但缺失的 PNG。
  6. 清理应用构建目录,重新构建并安装 BIN。

构建脚本要求图片平铺在 assets/ 中,文件名使用小写字母、数字和下划线。清单引用与实际 PNG 必须完全一致,否则构建会直接报错。

当前配置使用以下动画片段名:

片段 用途
sleeping_loop 等待唤醒循环
wake_up 从等待唤醒进入请说话
listening_loop 请说话循环
listening_to_thinking 从请说话进入思考中
thinking_loop 思考中循环
thinking_to_speaking 从思考中进入正在回复
speaking_loop 正在回复循环
sit_down 从回复进入等待说话
idle_dazeidle_rub_eye 等待说话时交替播放
idle_to_listening 连续对话重新进入请说话
lie_down 空闲超时后回到等待唤醒

只换图片时保留这些片段名最省事。如果需要增删片段,还要同步修改 voice_animation_config.js 中的 STATE_CLIPSTRANSITION_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/voice_state.js

页面结构和样式位于:

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 中的 tokenbots[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 转换为板端图片格式 ImageToolPYTHON 环境变量

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_llm JS 系统模块。
  • 向 ACE Lite 注册 @system.voiceCloudLlm

如果要关闭 Voice Cloud LLM,需要从 diting-communitydefines 中移除 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,不要提交构建生成的 .binentry/build/
  • 修改 JS 或主题时只需更新 BIN;修改 Native 后端、ACE 系统接口或唤醒能力时必须重新烧录固件。
  • 页面退出会停止语音服务。调试后台行为时不要把正常的生命周期停止误判为服务异常。