更新记录

1.0.0(2026-11-04)

  • 首个整理版:UTS 原生层 + 模型管理层 + zl-voice-input 组件合并为自包含插件
  • 组件去第三方依赖:输入框改为原生 textarea(原依赖 uView 的 u--textarea / u-icon)
  • 权限模块内置(common/permission.js),不再依赖宿主工程的权限封装
  • 模型下载地址参数化:新增 configureAsr({ modelUrls, numThreads }),支持自有服务器分发,内置镜像源兜底
  • 下载完成后自动清理 uni.downloadFile 临时文件(此前会残留约 200MB 副本)
  • 下载进度全局事件广播(ASR_PROGRESS_EVENT)+ 快照缓存,页面来回切换进度不丢失
  • 首页即测试页的示例工程:底层识别验证 + 组件演示 + 模型管理页一应俱全
  • v-model 双语法兼容:同时支持 Vue2(value/input)与 Vue3(modelValue/update:modelValue)
  • 明确平台边界:仅支持 uni-app + Android,不支持 uni-app x;移除 engines 中误导性的 uni-app-x 声明

平台兼容性

uni-app(5.0)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
√ √ × × √ √ 5.0 × -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × - × × × - - -

sherpa-asr 离线语音识别(Android)

基于 sherpa-onnx 的 uni-app UTS 插件,提供 Android 端离线流式语音识别(语音转文字):

  • 中英双语流式识别,边说边出字,支持中英混说
  • 全程离线:录音不上传、识别不联网、不消耗调用次数
  • 模型约 200MB,首次使用时自动下载到应用私有目录,不占用安装包体积
  • 开箱即用的 zl-voice-input 语音输入组件:多行输入框右下角语音角标,按住说话松手上屏,识别结果可直接编辑纠错
  • 提供模型管理页参考实现(下载进度、断点续传式跳过、删除重置)

平台支持:仅 uni-app + Android(arm64-v8a,minSdkVersion 21;Vue2 / Vue3 均可)。不支持 uni-app x;iOS / 小程序 / Web 端调用会得到空结果或提示不支持。


一、环境要求

项 要求
HBuilderX 3.6.8+(建议最新版)
uni-app 版本 Vue2 / Vue3 均可
Android minSdkVersion 21,arm64-v8a 设备
调试方式 必须使用自定义调试基座(插件含 Kotlin 混编与 AAR,标准基座不含)

⚠️ 首次运行前请在 HBuilderX 中执行:运行 → 运行到手机 → 制作自定义调试基座。

二、快速开始

  1. 将本插件导入你的项目(HBuilderX 会放入 uni_modules/)
  2. manifest.json 的 Android 权限中添加:
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
  3. 制作自定义调试基座后运行
  4. (可选)在 App.vue 的 onLaunch 中配置自有模型源:
    import { configureAsr } from '@/uni_modules/sherpa-asr/common/asrConfig.js'
    configureAsr({ modelUrls: ['https://your-server.com/asr-models/'] })

    不配置时默认使用内置镜像源(hf-mirror → huggingface 依次尝试)。

三、语音输入组件(easycom 自动注册)

插件内置 zl-voice-input 组件,符合 easycom 规范,页面中直接使用、无需 import:

<zl-voice-input
    v-model="content"
    mode="press"
    placeholder="请填写排查内容"
    :maxlength="500"
    :count="true"
    @done="onVoiceDone"
/>

属性

属性 类型 默认值 说明
v-model / value String '' 输入框内容
placeholder String 请输入内容 占位文案
maxlength Number -1 最大字数,-1 不限制
count Boolean false 是否显示字数统计
autoHeight Boolean true 输入框是否自动增高
disabled Boolean false 是否禁用
mode String 'press' press=按住说话松手结束;toggle=点击开始/再点结束
modelPagePath String '/pages/model/model' 模型未下载时「去下载」跳转的模型管理页路径
hint String '' 自定义底部提示文案

事件

事件 参数 说明
input String 内容变化(v-model)
done String 一次识别结束,参数为完整文本

交互细节(已内置)

  • 无模型时弹窗引导「去下载」,跳转 modelPagePath(页面栈保留,下载完返回后原表单内容不丢;路由不存在时 toast 兜底提示)
  • 麦克风权限:已授权静默通过;未授权自动申请;连续 2 次失败强制引导去系统设置(规避国产 ROM deniedAlways 不准的问题)
  • 首次授权期间用户往往已松手,组件会提示「麦克风已开启,请再按住说话」

四、示例页面(随插件提供)

插件目录内自带两份可直接复制使用的页面源码,无需另行下载示例工程:

文件 说明
example/model-page.vue 模型管理页:状态、已占空间、下载进度、加载到内存、删除模型
example/index-demo.vue 完整功能演示:底层 API 调用、组件两种模式演示、识别日志

接入步骤(以模型管理页为例)

  1. 把 uni_modules/sherpa-asr/example/model-page.vue 复制到你的 pages/model/model.vue
  2. 在 pages.json 注册路由:
    { "path": "pages/model/model", "style": { "navigationBarTitleText": "离线语音模型" } }
  3. 完成。组件默认的 modelPagePath 就是 /pages/model/model,无需额外配置

如果你的路径不同,给组件传 model-page-path 即可:

<zl-voice-input v-model="content" model-page-path="/pages/setting/voice-model" />

两个示例页面里的 import 均使用 @/uni_modules/sherpa-asr/...,复制到任意位置都能直接编译。

五、JS API

配置(common/asrConfig.js)

import { configureAsr } from '@/uni_modules/sherpa-asr/common/asrConfig.js'
configureAsr({ modelUrls: ['https://...'], numThreads: 2 })

业务层(common/asrService.js)

方法 说明
getAsrStatus() 返回 {filesReady, engineReady, missing, paths}
initEngineIfNeeded(paths) 引擎未初始化则初始化
prepareAsrModel(onProgress) 下载 + 初始化一键完成(单例防重入)
getAsrProgress() 下载进度快照(页面返回时恢复显示)
ASR_PROGRESS_EVENT 进度全局事件名,uni.$on 监听

模型管理(common/asrModelManager.js)

方法 说明
getModelPaths() 4 个模型文件绝对路径
checkModelFiles() 检查文件是否齐全(不下载)
ensureAsrModel(onProgress) 缺失则下载(多源重试)
clearAsrModel() 删除模型文件(先释放引擎再调用)

原生识别(插件主入口 @/uni_modules/sherpa-asr)

initAsr / startAsr / stopAsr / getAsrPartial / cancelAsr / releaseAsr / isAsrReady / getAsrError

六、模型分发

模型共 4 个文件(合计约 200MB,字节数必须完全一致,插件按大小校验):

文件 字节数
encoder-epoch-99-avg-1.int8.onnx 181895032
decoder-epoch-99-avg-1.onnx 13876452
joiner-epoch-99-avg-1.int8.onnx 3228404
tokens.txt 56317
  • 默认从 hf-mirror / huggingface 下载,国内速度不稳定,正式商用强烈建议自建分发:把 4 个文件上传到你的静态文件服务(扁平目录、文件名不可改、匿名直链、建议关闭 gzip),然后 configureAsr({ modelUrls: ['https://your-server.com/asr-models/'] })(结尾必须带 /)
  • 自有源放在数组首位会优先使用,内置镜像自动保留兜底
  • 模型存放于 _doc/asr-models/(应用私有目录),卸载 App 自动清除

七、付费授权与加密说明

本插件发布于 DCloud 插件市场,分普通授权版(源码加密,绑定 appid+包名)与源码授权版(全源码可见)。加密规则遵循官方:

  • 除 interface.uts 外的所有 .uts 文件及 utssdk/app-android 下的 Kotlin 混编文件将被加密
  • 加密插件仅支持云端传统打包,不支持离线打包 / 安心打包
  • 每次更换 appid 或包名需重新购买授权

八、常见问题

Q:标准基座能跑吗? 不能。插件含 Kotlin 混编与 AAR(libonnxruntime / libsherpa-onnx-jni),必须自定义调试基座或云打包。

Q:首次初始化耗时? 中端机加载模型约 1~3 秒(2 线程),之后常驻内存直到调用 releaseAsr()。

Q:下载到一半失败? 每个文件多源 × 2 次重试;已完成的文件按字节数校验后自动跳过,直接再点一次即可续传。

Q:低端机识别卡顿? configureAsr({ numThreads: 2 })(默认已是 2);4 线程仅建议中高端机。

Q:识别结果可以修改吗? 可以。组件输出就是普通文本(v-model),用户可直接在输入框里改正错别字。

九、开源许可

本插件基于以下开源项目构建,感谢原作者:

本插件的原始代码部分遵循与发布平台一致的授权协议;使用本插件即表示你同意同时遵守上述开源协议(Apache 2.0 要求的版权与许可声明须予保留)。

十、更新日志

见 changelog.md。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

麦克风

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

录音仅在设备本地识别,不上传任何服务器

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无