更新记录
1.0.0(2026-09-13) 下载此版本
初版
平台兼容性
uni-app(3.8.3)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | 4.4 | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | √ | √ |
sl-uniplugin-asr 离线语音识别插件
简介
基于 Vosk 的离线中文语音识别(ASR) UTS 插件,无需网络服务,实时返回识别结果。
| 引擎 | 模型 | 采样率 |
|---|---|---|
| Vosk (Kaldi) | 中文声学模型 + 语言模型 | 16000Hz |
目录结构
sl-uniplugin-asr/
├── package.json
└── utssdk/app-android/
├── index.uts # ASR 实现
├── config.json # 依赖与构建配置
├── AndroidManifest.xml # 权限声明
└── assets/model/ # Vosk 中文模型
├── am/final.mdl # 声学模型
├── conf/ # MFCC 配置
├── graph/ # 语言模型 (Gr.fst, HCLr.fst)
├── ivector/ # ivector 适配器
└── uuid # 模型版本标识
权限
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Android 6.0+ 需运行时动态申请麦克风权限,插件已内置权限检查与申请逻辑。
API
initModel(options, callback)
初始化语音识别模型。通过 Vosk StorageService 从 assets 解压模型到内部存储。
| 参数 | 类型 | 说明 |
|---|---|---|
| options | Object | 无必填参数 |
| callback | Function | 回调函数 |
回调返回值:
{ "code": 0, "success": true, "msg": "Model loaded" }
示例:
import { initModel } from '@/uni_modules/sl-uniplugin-asr'
initModel({}, (res) => {
if (res.code === 0) {
console.log('ASR 模型就绪')
} else {
console.error('初始化失败:', res.msg)
}
})
首次初始化会解压模型到
/data/data/<pkg>/files/model/,之后启动会跳过解压。
startListening(options, callback)
开始离线语音识别。
⚠️ 重要:callback 一次性限制 在 uni-app Vue3(非 uni-app x)项目 + App-Android 真机环境下,UTS callback 只能被 JS 端接收一次。Vosk 的多次识别结果(partial/result/final/timeout)无法通过 callback 传递到 JS 端。
插件已内置
getLastResult()轮询方案绕过此限制,前端需用setInterval轮询获取结果,详见下文。
| 参数 | 类型 | 说明 |
|---|---|---|
| options | Object | 无必填参数 |
| callback | Function | 仅触发一次,返回监听启动状态 |
callback 返回值(仅一次):
// 监听启动成功
{ "code": 0, "msg": "Listening" }
// 监听启动失败
{ "code": 1, "msg": "模型未初始化" }
{ "code": 1, "msg": "正在请求麦克风权限,请授权后重试" }
后续识别结果需通过 getLastResult() 轮询获取:
// partial(说话过程中,实时更新)
{ "code": 0, "type": "partial", "text": "你好", "isFinal": false, "timestamp": 1694000000000 }
// result(检测到一个语音段落后的结果)
{ "code": 0, "type": "result", "text": "你好世界", "isFinal": true, "timestamp": 1694000000500 }
// final(停止监听后的最终结果)
{ "code": 0, "type": "final", "text": "你好世界", "isFinal": true, "timestamp": 1694000001000 }
// timeout(15秒无语音自动超时)
{ "code": 0, "type": "timeout", "text": "", "isFinal": true, "timestamp": 1694000002000 }
// error
{ "code": 1, "type": "error", "text": "", "isFinal": true, "msg": "错误信息", "timestamp": 1694000003000 }
结果类型说明:
| type | 含义 | 是否结束监听 |
|---|---|---|
partial |
说话过程中的部分识别结果 | 否 |
result |
检测到一个语音段落后的结果 | 否 |
final |
调用 stopListening 后的最终结果 | 是 |
timeout |
15秒无语音自动超时 | 是 |
error |
发生错误 | 是 |
完整示例(包含轮询):
import { startListening, getLastResult } from '@/uni_modules/sl-uniplugin-asr'
let listening = false
let lastTimestamp = 0
let pollTimer = null
// 开始聆听
startListening({}, (res) => {
// 这个 callback 只触发一次,用于确认监听是否启动
if (res.code === 0) {
listening = true
console.log('正在聆听,请说话...')
// 启动轮询获取识别结果
lastTimestamp = 0
pollTimer = setInterval(() => {
const result = getLastResult()
if (result == null) return
const ts = result.timestamp || 0
if (ts <= lastTimestamp) return // 不是新结果
lastTimestamp = ts
const type = result.type
const text = result.text
const msg = result.msg
if (result.code === 0) {
// 显示识别结果
if (text && String(text).trim()) {
console.log('识别:' + String(text).trim())
}
// final 或 timeout 表示监听结束
if (type === 'final' || type === 'timeout' || type === 'error') {
listening = false
clearInterval(pollTimer)
pollTimer = null
console.log('识别结束')
}
} else {
console.error('失败:', msg)
listening = false
clearInterval(pollTimer)
pollTimer = null
}
}, 200) // 200ms 轮询
} else {
listening = false
console.error('启动失败:', res.msg)
}
})
// 页面卸载时清除轮询
// onUnload() { if (pollTimer) { clearInterval(pollTimer); pollTimer = null } }
15 秒无语音自动超时停止。
type: 'result'不是结束信号,可以继续说下一句。
getLastResult()
获取最新识别结果。配合 setInterval 轮询使用,绕过 UTS callback 一次性限制。
| 返回值 | 说明 |
|---|---|
UTSJSONObject \| null |
最新识别结果,包含 code/type/text/isFinal/msg/timestamp 字段 |
返回值结构:
{
code: 0, // 0=成功,1=失败
success: true, // 是否成功
type: 'partial', // partial/result/final/timeout/error
text: '你好', // 识别文本(可能为空字符串)
isFinal: false, // 是否为最终结果
msg: '', // 附加消息(错误时包含错误信息)
timestamp: 1694000000000 // 毫秒时间戳,用于判断是否为新结果
}
说明:
- 每次调用返回 UTS 端存储的最新结果(不会消费,重复调用返回同一对象直到有新结果)
- 通过比较
timestamp判断是否有新结果 - 无结果时返回
null - 前端需在
startListening的 callback 触发后启动轮询
轮询示例:
import { getLastResult } from '@/uni_modules/sl-uniplugin-asr'
let lastTimestamp = 0
const pollTimer = setInterval(() => {
const result = getLastResult()
if (result == null) return
const ts = result.timestamp || 0
if (ts <= lastTimestamp) return
lastTimestamp = ts
console.log('新结果:', result.type, result.text)
}, 200)
stopListening(options, callback)
停止语音识别。
示例:
import { stopListening } from '@/uni_modules/sl-uniplugin-asr'
stopListening({}, (res) => {
console.log('已停止识别')
})
destroy(options, callback)
释放 Vosk 模型和 SpeechService 资源。释放后需重新 initModel() 才能使用。
示例:
import { destroy } from '@/uni_modules/sl-uniplugin-asr'
destroy({}, (res) => {
console.log('资源已释放')
})
技术细节
- 轮询机制:UTS callback 在 Weex 引擎下只能被 JS 端接收一次,插件用
lastResult全局变量 +getLastResult()导出函数 + 前端setInterval轮询的方式绕过此限制 - 结果存储:每次 Vosk 回调(partial/result/final/timeout/error)时,结果存入
lastResult全局变量,并附带timestamp时间戳 - 文本解析:Vosk partial 结果用
"partial"键,result/final 用"text"键,插件已统一处理 - 空结果过滤:空 partial 结果不会更新
lastResult,减少无效轮询 - 15秒超时:通过
Handler.postDelayed定时,超时自动停止 SpeechService - 权限检查:
Build.VERSION.SDK_INT >= M时检查RECORD_AUDIO权限,无权限时自动调用requestPermissions - 模型不压缩:
config.json配置noCompress: ["mdl", "fst", "int", "ie", "mat", "dubm", "stats", "conf"]
注意事项
- minSdkVersion 21(Android 5.0+)
- 首次使用需授予麦克风权限
startListening()会自动停止上一次未完成的监听type: 'result'不是结束信号,只有final、timeout和error才表示监听结束- 释放后需重新
initModel()才能再次使用 - 必须用轮询方式获取识别结果:
startListening的 callback 仅触发一次,用于确认监听是否启动;后续识别结果需调用getLastResult()轮询获取 - 轮询间隔建议 200ms:太小会增加 CPU 占用,太大会延迟显示结果
- 页面卸载时需清除轮询定时器,避免内存泄漏
- Vosk 中文模型输出格式:每个词之间用空格分隔(如 "你好 世界"),这是 Vosk 的中文输出特点

收藏人数:
下载插件并导入HBuilderX
赞赏(0)
下载 108
赞赏 1
下载 12592869
赞赏 1949
赞赏
京公网安备:11010802035340号