更新记录
1.0.0(2026-05-30)
- 首发版本,集成 sherpa-onnx 端侧语音 AI Runtime
- 支持 12 项语音能力:离线 ASR、实时 ASR、VAD、TTS、KWS、Speaker Embedding、Speaker Segmentation、标点恢复、语种识别、音频标签、语音增强、声源分离
- 提供完整测试页面,覆盖所有功能入口和参数配置
- 支持 static 资源目录和绝对路径两种模型加载方式
- 支持 iOS CoreML 推理加速
平台兼容性
uni-app(5.07)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | × | × | × | √ | √ | √ | √ | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(5.07)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | √ | √ | × | × |
em-sherpa-onnx — 端侧离线语音 AI 引擎
概述
em-sherpa-onnx 是基于 sherpa-onnx 的 UniApp X 本地语音 AI Runtime 插件,面向端侧离线语音场景。所有推理在设备本地完成,无需网络连接,数据不出设备。
功能矩阵
| 功能 | 插件 type | 说明 |
|---|---|---|
| 离线语音识别 (ASR / STT) | asr-offline |
识别音频文件中的语音内容,支持多语种 |
| 实时语音识别 | asr-online |
通过麦克风流式获取中间识别结果 |
| 语音活动检测 (VAD) | vad |
检测音频中人声起止时间,用于语音端点检测 |
| 语音合成 (TTS) | tts |
将文本合成为自然语音,支持离线和流式 |
| 关键词唤醒 (KWS) | kws |
监听麦克风,检测预设关键词并触发事件 |
| 说话人嵌入 | speaker-embedding |
提取说话人声纹特征,用于注册/识别/验证 |
| 说话人分段 | speaker-segmentation |
多说话人音频的分段标注(Diarization) |
| 标点恢复 | punctuation |
为无标点文本添加标点符号 |
| 语种识别 | language-id |
识别音频所属语种 |
| 音频标签 | audio-tagging |
识别音频中的环境声音或事件标签 |
| 语音增强 | enhancement |
去除背景噪声,提升语音清晰度 |
| 声源分离 | source-separation |
将混合音频分离为人声和伴奏等独立音轨 |
应用场景
- 语音笔记 & 会议转写:离线 ASR 实时转写本地录音,支持中英粤日韩等多语种
- 语音助手 & 智能家居:KWS 关键词唤醒 + ASR 语音指令理解,完全离线保护隐私
- 语音合成播报:TTS 将通知、新闻、导航播报等文本转为语音播放
- 声纹登录 & 验证:Speaker Embedding 注册用户声纹,实现免密码身份确认
- 多说话人会议标注:Speaker Segmentation 区分不同说话人,生成带标签的转写文本
- 音频内容审核 & 分析:Audio Tagging 识别音频中的枪声、警报、猫叫等事件标签
- 通话降噪 & 录音增强:Enhancement 实时去除环境噪声,改善远端通话质量
引入
import {
getRuntimeInfo,
loadModel,
recognizeFile,
synthesize,
startStreamingAsr,
getStreamEventChannel,
} from "@/uni_modules/em-sherpa-onnx";
模型下载
插件不内置大模型。业务侧应将模型放在 static 目录,或下载到本地绝对路径后传给插件。
官方下载入口
- 预训练模型总表:https://k2-fsa.github.io/sherpa/onnx/pretrained_models/index.html
- GitHub ASR 模型:https://github.com/k2-fsa/sherpa-onnx/releases/tag/asr-models
- GitHub TTS 模型:https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models
- GitHub KWS 模型:https://github.com/k2-fsa/sherpa-onnx/releases/tag/kws-models
- HuggingFace 镜像:https://huggingface.co/k2-fsa/sherpa-onnx-models
推荐测试模型(全功能清单)
为覆盖插件所有 12 项能力,建议按功能分别下载以下模型:
| 功能 | 推荐模型 | 插件 type | 下载地址 |
|---|---|---|---|
| 离线 ASR(中英粤日韩) | SenseVoice int8 | asr-offline |
下载 |
| 实时 ASR(中英) | Streaming Zipformer | asr-online |
下载 |
| VAD | Silero VAD | vad |
下载 |
| TTS(中英) | VITS Melo TTS | tts |
下载 |
| KWS | Zipformer KWS | kws |
下载 |
| Speaker Embedding | 3D Speaker ERES2Net | speaker-embedding |
下载 |
| Speaker Segmentation | PyAnnote Segmentation 3.0 | speaker-segmentation |
下载 |
| 标点恢复 | CT-Transformer | punctuation |
下载 |
| 语种识别 | Whisper Tiny | language-id |
下载 |
| 音频标签 | Zipformer Audio Tagging | audio-tagging |
下载 |
| 语音增强 | GTCRN | enhancement |
下载 |
| 声源分离 | Spleeter 2stems | source-separation |
下载 |
完整模型清单和下载脚本参考
docs/model-downloads.md。
下载 & 放置示例
# 创建模型目录
mkdir -p uni_sherpa/static/assets/models
# 下载 SenseVoice ASR 模型
curl -L -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
mv sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17 sense-voice-zh-en-ja-ko-yue-int8-2024-07-17
rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
# 目录结构
# uni_sherpa/static/assets/models/
# sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/
# model.int8.onnx
# tokens.txt
使用说明
1. 运行时管理
加载模型
模型可放置在 static 资源目录或设备沙盒绝对路径下。
// 从 static 资源加载
await loadModel({
type: "asr-offline",
source: "static",
modelDir: "static/assets/models/sense-voice-zh-en-ja-ko-yue-int8-2024-07-17",
modelId: "asr-main",
numThreads: 2,
provider: "cpu",
});
// 从设备绝对路径加载
await loadModel({
type: "asr-offline",
source: "absolute",
modelDir:
"/storage/emulated/0/models/sense-voice-zh-en-ja-ko-yue-int8-2024-07-17",
modelId: "asr-main",
numThreads: 2,
provider: "cpu",
});
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
string | 是 | 模型类型:asr-offline、asr-online、vad、tts、kws、speaker-embedding、speaker-segmentation、punctuation、language-id、audio-tagging、enhancement、source-separation |
source |
'static' \| 'absolute' |
是 | static 从 App 资源目录读取;absolute 从设备文件系统读取 |
modelDir |
string | 是 | 模型目录路径(静态资源或绝对路径) |
modelId |
string | 否 | 自定义模型标识,后续操作通过此 ID 引用模型;不传则自动生成 |
numThreads |
number | 否 | 推理线程数(默认 2) |
provider |
'cpu' \| 'coreml' |
否 | 推理加速后端,iOS 支持 coreml,Android 仅 cpu |
查看运行时信息
const info = await getRuntimeInfo();
console.log(info.version, info.platform, JSON.stringify(info.models));
查看模型能力
const capabilities = await getModelCapabilities("asr-main");
console.log(JSON.stringify(capabilities));
// 输出示例:
// {
// "type": "asr-offline",
// "engine": "sense-voice",
// "sampleRate": 16000,
// "supportsOffline": true,
// "supportsStreaming": false,
// "preferredLanguage": "auto",
// "languages": ["zh", "yue", "en", "ja", "ko"]
// }
释放资源
// 释放所有模型和实时任务
await releaseAll();
完整示例
参考 pages/runtime/runtime.uvue — 提供模型类型选择、路径输入、provider 切换、加载/释放按钮和输出面板。典型流程:
- 选择模型类型(如
asr-offline) - 填写模型目录路径
- 点击 Load 按钮加载模型
- 查看 capability 输出
- 测试完成后点击 Release 释放
2. 离线语音识别 (ASR / STT)
// 先加载模型
await loadModel({
type: "asr-offline",
source: "static",
modelDir: "static/assets/models/sense-voice-zh-en-ja-ko-yue-int8-2024-07-17",
modelId: "asr-main",
engine: "sense-voice",
numThreads: 2,
provider: "cpu",
});
// 识别文件
const result = await recognizeFile({
modelId: "asr-main",
path: "/path/to/audio.wav",
language: "auto", // auto | zh | yue | en | ja | ko
useItn: true, // 启用标点逆文本正则化
});
console.log(result.text); // 识别结果文字
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
modelId |
string | 是 | 已加载的 ASR 模型 ID |
path |
string | 是 | 音频文件路径(16kHz 单声道 wav 最佳) |
language |
string | 否 | 语种指定:auto 自动检测,或 zh/yue/en/ja/ko |
useItn |
boolean | 否 | 是否启用标点恢复和逆文本正则化(默认 false) |
完整示例
参考 pages/asr/asr.uvue — 支持:
- 加载 ASR 模型:选择路径后点击 Load ASR
- 单文件识别:填入音频路径后点击 ASR File
- 多语言样例:点击 ASR Samples 依次识别中/粤/英/日/韩测试音频
- 快捷语种切换:自动填入对应语言的测试音频路径和 language 参数
3. 实时语音识别 (Streaming ASR)
// 加载实时 ASR 模型
await loadModel({
type: "asr-online",
source: "static",
modelDir: "static/assets/models/asr-streaming-zh-en",
modelId: "asr-stream",
numThreads: 2,
provider: "cpu",
config: {
modelType: "zipformer", // 模型架构
encoder: "encoder-epoch-99.onnx", // 文件名映射
decoder: "decoder-epoch-99.onnx",
joiner: "joiner-epoch-99.onnx",
tokens: "tokens.txt",
},
});
// 订阅实时事件
const channel = getStreamEventChannel();
uni.$on(channel, (event: string) => {
const data = JSON.parse(event);
// data.type: 'asr-online-partial' | 'asr-online-final' | 'asr-online-error' | ...
// data.data: 对应结果
console.log(data.type, data.data);
});
// 启动麦克风流式识别
const taskId = await startStreamingAsr({
modelId: "asr-stream",
language: "zh",
});
// 取消任务
await cancelTask(taskId);
完整示例
参考 pages/stream/stream.uvue — 提供:
- 加载实时 ASR 模型(支持 Zipformer / Paraformer 架构)
- 启动流式识别:打开麦克风并实时返回 partial / final 结果
- 停止 & 取消:结束当前实时任务并拉取已缓存事件
4. 语音活动检测 (VAD)
// 加载 VAD 模型(单文件模型)
await loadModel({
type: "vad",
source: "static",
modelDir: "static/assets/models/silero-vad",
modelId: "vad-main",
numThreads: 1,
provider: "cpu",
});
// 文件级 VAD 检测
const segments = await vadFile({
modelId: "vad-main",
path: "/path/to/audio.wav",
});
// segments: Array<{ start: number, end: number }> 单位秒
// 麦克风实时 VAD(需订阅事件通道)
const taskId = await startVadStream({ modelId: "vad-main" });
VAD + ASR 联动
await loadModel({ type: 'vad', modelId: 'vad-main', ... })
await loadModel({ type: 'asr-offline', modelId: 'asr-main', ... })
const taskId = await startVadAsr({
vadModelId: 'vad-main',
asrModelId: 'asr-main',
language: 'auto'
})
// 事件通道返回 vad-asr 事件,包含语音段起止时间和识别文字
完整示例
参考 pages/vad/vad.uvue — 支持:
- 加载 VAD 模型
- VAD 文件检测:检测音频中的人声时间段
- VAD 实时流:麦克风实时 VAD 事件
- VAD + ASR 联动:VAD 检测到语音段后自动调用离线 ASR 识别
- 取消实时任务
5. 语音合成 (TTS)
// 加载 TTS 模型
await loadModel({
type: "tts",
source: "static",
modelDir: "static/assets/models/vits-melo-tts-zh_en",
modelId: "tts-main",
numThreads: 1,
provider: "cpu",
});
// 查看可用角色 / 音色
const voices = await listTtsVoices("tts-main");
console.log(JSON.stringify(voices));
// 输出示例:[{ id: 'default', name: 'Default', gender: 'female' }, ...]
// 离线合成
const result = await synthesize({
modelId: "tts-main",
text: "你好,欢迎使用语音合成。",
sid: 0, // speaker ID(可选)
speed: 1.0, // 语速倍率(可选)
});
// result.path: 合成音频文件路径
// 可使用 uni.createInnerAudioContext() 播放
// 流式合成
const taskId = await synthesizeStream({
modelId: "tts-main",
text: "这是一段较长的文本,使用流式合成可以边生成边播放。",
sid: 0,
speed: 1.0,
});
完整示例
参考 pages/tts/tts.uvue — 提供:
- 加载 TTS 模型
- 查看 voices:列出模型支持的角色/音色列表
- 离线合成播放:合成后播放音频文件
- 流式合成播放:边合成边返回事件,完成后播放完整 wav
- 重播 & 停止:重播最近合成结果,或停止当前播放
- 取消实时任务
6. 关键词唤醒 (KWS)
// 加载 KWS 模型
await loadModel({
type: "kws",
source: "static",
modelDir: "static/assets/models/kws-zipformer-zh-en",
modelId: "kws-main",
numThreads: 2,
provider: "cpu",
config: {
modelType: "zipformer",
encoder: "encoder-epoch-99.onnx",
decoder: "decoder-epoch-99.onnx",
joiner: "joiner-epoch-99.onnx",
tokens: "tokens.txt",
keywords: "keywords.txt", // 关键词列表文件
},
});
// 启动麦克风唤醒监听
const taskId = await startKws({ modelId: "kws-main" });
// 取消监听
await cancelTask(taskId);
完整示例
参考 pages/kws/kws.uvue — 提供:
- 加载 KWS 模型
- 启动唤醒监听:麦克风持续监听,检测到关键词触发事件
- 取消监听
7. 说话人能力 (Speaker)
// 加载说话人嵌入模型
await loadModel({
type: "speaker-embedding",
source: "static",
modelDir: "static/assets/models/3dspeaker-eres2net",
modelId: "speaker-embed",
numThreads: 2,
provider: "cpu",
});
// 注册声纹
await enrollSpeaker({
modelId: "speaker-embed",
name: "张三",
audioPath: "/path/to/zhangsan.wav",
});
// 识别说话人
const result = await identifySpeaker({
modelId: "speaker-embed",
audioPath: "/path/to/test.wav",
});
console.log(result.name, result.score);
// 验证说话人
const verified = await verifySpeaker({
modelId: "speaker-embed",
name: "张三",
audioPath: "/path/to/test.wav",
threshold: 0.7,
});
console.log(verified.match, verified.score);
// 多人分段标注(需同时加载 speaker-segmentation 模型)
const diarization = await speakerDiarization({
segmentationModelId: "seg-model",
embeddingModelId: "speaker-embed",
audioPath: "/path/to/multi-speaker.wav",
});
// diarization: Array<{ speaker: string, start: number, end: number }>
完整示例
参考 pages/speaker/speaker.uvue — 提供:
- 加载 Speaker Embedding 模型
- 加载 Speaker Segmentation 模型
- 注册(Enroll):录入说话人声纹
- 识别(Identify):从已注册的声纹库中匹配说话人
- 验证(Verify):验证音频是否属于指定说话人
- 分段(Diarize):多说话人音频分段标注
8. 文本与音频后处理
// 标点恢复
const punctuated = await punctuate({
modelId: "punct-model",
text: "今天天气真不错我们出去玩吧",
});
console.log(punctuated.text); // '今天天气真不错,我们出去玩吧。'
// 语种识别
const lang = await detectLanguage({
modelId: "lang-model",
audioPath: "/path/to/audio.wav",
});
console.log(lang.language); // 'zh' | 'en' | 'ja' | ...
// 音频标签
const tags = await audioTagging({
modelId: "tag-model",
audioPath: "/path/to/audio.wav",
});
console.log(JSON.stringify(tags));
// [{ label: 'Speech', score: 0.95 }, ...]
// 语音增强
const enhanced = await enhanceAudio({
modelId: "enhance-model",
audioPath: "/path/to/noisy.wav",
});
// enhanced.path: 增强后的音频文件路径
// 声源分离
const separated = await sourceSeparate({
modelId: "separate-model",
audioPath: "/path/to/mixed.wav",
});
// separated.vocals: 人声音频路径
// separated.accompaniment: 伴奏音频路径
完整示例
参考 pages/post/post.uvue — 集成了所有后处理功能的入口:
- 标点恢复:输入无标点文本,返回带标点文本
- 语种识别:识别音频所属语种
- 音频标签:识别音频事件标签
- 语音增强:去除背景噪声
- 语音增强(流式):麦克风实时降噪
- 声源分离:分离人声和伴奏
事件通道机制
实时功能(Streaming ASR、VAD Stream、TTS Stream、KWS 等)通过 UniApp X 事件通道返回中间结果。
// 获取当前事件通道名称
const channel = getStreamEventChannel();
// 订阅事件
uni.$on(channel, (event: string) => {
const data = JSON.parse(event);
switch (data.type) {
case "asr-online-partial":
// 实时中间结果
console.log("partial:", data.data.text);
break;
case "asr-online-final":
// 最终识别结果
console.log("final:", data.data.text);
break;
case "vad-speech-segment":
// VAD 检测到语音段
console.log("segment:", data.data.start, data.data.end);
break;
case "tts-stream-chunk":
// TTS 流式片段
console.log("tts chunk progress:", data.data.progress);
break;
case "kws-keyword-detected":
// 关键词唤醒
console.log("keyword:", data.data.keyword);
break;
case "task-error":
console.error("task error:", data.data);
break;
}
});
// 取消订阅(释放资源时)
uni.$off(channel);
角色、男女声与方言
- TTS 角色/男女声/音色:由 TTS 模型自身决定,不同模型支持的 speaker 数量不同。加载后通过
listTtsVoices(modelId)查询可用角色。 - ASR 语种和方言:由 ASR 模型决定。SenseVoice 支持普通话、粤语、英语、日语、韩语。多语识别时传
language: 'auto'自动检测。 - 功能扩展性:插件不限制模型的具体能力,只要模型文件符合 sherpa-onnx 格式即可加载。通过
getModelCapabilities()获取模型的能力清单。
常见问题
Q: 模型文件需要放在哪里?
模型可放在 uni_sherpa/static/ 目录下(跟随 App 资源打包),或下载到设备沙盒后使用绝对路径加载。
Q: iOS 和 Android 的路径差异?
- Android:
static/路径自动映射到 assets 资源目录,绝对路径指向/storage/emulated/0/...等设备存储路径。 - iOS:
static/路径自动映射到 App 资源 bundle。绝对路径需手动填写沙盒路径,例如NSHomeDirectory()/Documents/models/...。iOS 推理加速可选 CoreML provider。
Q: 音频格式要求?
推荐 16kHz 采样率、单声道、16-bit 线性 PCM 的 wav 文件。其他格式可能不被支持。
Q: 如何同时加载多个模型?
多次调用 loadModel() 并传入不同的 modelId。例如同时加载 VAD 和 ASR 模型用于 VAD+ASR 联动,或同时加载 Embedding 和 Segmentation 模型用于说话人分段。
Q: 实时任务如何清理?
调用 cancelTask(taskId) 取消指定任务,或调用 releaseAll() 释放所有模型和任务。释放后应调用 uni.$off(channel) 取消事件订阅。
更多细节和完整代码示例请参考
uni_sherpa/pages/下的各功能页面源码。

收藏人数:
购买普通授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 400
赞赏 0
下载 12100114
赞赏 1918
赞赏
京公网安备:11010802035340号