更新记录
1.0.9(2026-06-11)
修复安卓端在uniapp项目上云打包报错的问题
1.0.8(2026-06-06)
feat-重要更新:新增matchaIcefall模型,主打快速起播,过程流畅,温柔女生音色
1.0.7(2026-05-27)
修复安卓端云打包错误
平台兼容性
uni-app(5.07)
| Vue2 | Vue2插件版本 | Vue3 | Vue3插件版本 | Chrome | Safari | app-vue | app-nvue | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | 1.0.0 | √ | 1.0.0 | - | - | - | - | 5.0 | 1.0.0 | 13 | 1.0.5 | 19 | 1.0.1 |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(5.07)
| Chrome | Safari | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 | 鸿蒙插件版本 | 微信小程序 |
|---|---|---|---|---|---|---|---|---|
| - | - | 5.0 | 1.0.0 | 13 | 1.0.5 | 19 | 1.0.1 | - |
xwq-sherpa-onnx-tts
xwq-sherpa-onnx-tts 是一个基于 sherpa-onnx 的离线 TTS 播报插件。
推荐优先使用
matchaIcefall模型。当前项目实测它的播报速度非常快,首包响应更积极,适合作为默认首选模型。
matchaIcefall模型初始化需要下载两个模型文件搭配使用:
第一个模型下载:
https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/matcha-icefall-zh-en.tar.bz2
解压后目录如下:
-rw-r--r--@ 1 fangjun staff 58K 4 Dec 14:29 date-zh.fst
drwxr-xr-x@ 122 fangjun staff 3.8K 28 Nov 2023 espeak-ng-data
-rw-r--r--@ 1 fangjun staff 1.3M 4 Dec 14:29 lexicon.txt
-rw-r--r--@ 1 fangjun staff 72M 4 Dec 14:29 model-steps-3.onnx
-rw-r--r--@ 1 fangjun staff 63K 4 Dec 14:29 number-zh.fst
-rw-r--r--@ 1 fangjun staff 87K 4 Dec 14:29 phone-zh.fst
-rw-r--r--@ 1 fangjun staff 2.0K 4 Dec 14:29 README.md
-rw-r--r--@ 1 fangjun staff 21K 4 Dec 14:29 tokens.txt
第二个模型下载:
https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-models/vocos-16khz-univ.onnx
解压后目录如下:
-rw-r--r--@ 1 fangjun staff 51M 4 Dec 14:54 vocos-16khz-univ.onnx
插件能力概览
- 支持基于本地
onnx模型的离线文本转语音播报 - 支持初始化模型、开始播报、暂停、继续、停止
- 支持自定义
sid说话人和speed语速 - 支持传入
number.fst、phone.fst、date.fst文本归一化规则文件 finished回调在当前实现中会尽量等待AudioTrack实际播放完成后再触发
对外暴露的方法
插件推荐通过下面方式引入:
import {
initSherpaOnxxTts,
start,
pause,
resume,
stop
} from "@/uni_modules/xwq-sherpa-onnx-tts"
initSherpaOnxxTts(opt)
初始化 TTS 引擎和模型资源。
- 入参:
initTTsOptions - 返回:无
- 说明:建议页面加载后先调用一次,初始化成功后再调用
start
start(opt)
开始播报文本内容。
- 入参:
PlayParams - 返回:无
- 说明:当前实现会把文本送入离线模型生成语音,并自动写入音频播放器
pause()
暂停当前播报。
- 入参:无
- 返回:无
resume()
继续当前播报。
- 入参:无
- 返回:无
stop()
停止当前播报。
- 入参:无
- 返回:无
回调与类型说明
FailCallBack
type FailCallBack = {
msg: string
code: number
}
字段说明:
msg:错误信息code:错误码,便于业务侧区分初始化失败、播放失败等场景
PlayParams
type PlayParams = {
text: string
fail?: ((val: FailCallBack) => void) | null
finished?: (() => void) | null
}
字段说明:
text:需要播报的文本内容fail:播报失败时触发finished:当前播报完成时触发
initTTsOptions 参数表
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
model |
string |
是 | onnx 模型文件路径,例如 model.onnx |
voices |
string | null |
否 | 音色或附加模型文件路径。vitsMelo 下可传 null;matchaIcefall 下这里需要传 vocoder 路径,例如 vocos-16khz-univ.onnx |
tokens |
string |
是 | 词表文件路径,例如 tokens.txt |
dataDir |
string | null |
否 | 发音引擎数据目录。当前 Android 的 VitsMelo 实现未使用该字段,保留接口兼容 |
numberFst |
string | null |
否 | 数字文本归一化规则文件路径,例如 number.fst |
phoneFst |
string | null |
否 | 电话号码文本归一化规则文件路径,例如 phone.fst |
dateFst |
string | null |
否 | 日期文本归一化规则文件路径,例如 date.fst |
dictDir |
string | null |
否 | 分词字典目录。当前 Android 的 VitsMelo 实现未使用该字段,保留接口兼容 |
lexicon |
string |
是 | 词典文件路径,用于修正特定词汇的发音 |
content |
string | null |
否 | 预留字段,当前初始化流程未使用。实际播报文本请通过 start({ text }) 传入 |
sid |
number | null |
否 | 说话人 ID。未传时默认使用 0 |
speed |
number | null |
否 | 语速。未传时默认使用 1.0 |
fail |
((val: FailCallBack) => void) | null |
否 | 初始化失败回调 |
success |
(() => void) | null |
否 | 初始化成功回调 |
对应类型定义如下:
type initTTsOptions = {
model: string
voices?: string | null
tokens: string
dataDir?: string | null
numberFst?: string | null
phoneFst?: string | null
dateFst?: string | null
dictDir?: string | null
lexicon: string
content?: string | null
sid?: number | null
speed?: number | null
fail?: ((val: FailCallBack) => void) | null
success?: (() => void) | null
}
模型参数对照表
vitsMelo
| 字段 | 是否必填 | 说明 | 当前示例值 |
|---|---|---|---|
modelType |
是 | 固定传 vitsMelo |
vitsMelo |
model |
是 | 声学模型文件 | model.onnx |
voices |
否 | 当前模型未使用,可传 null |
null |
tokens |
是 | 词表文件 | tokens.txt |
lexicon |
是 | 发音词典 | lexicon.txt |
numberFst |
否 | 数字归一化规则 | number.fst |
phoneFst |
否 | 电话归一化规则 | phone.fst |
dateFst |
否 | 日期归一化规则 | date.fst |
dataDir |
否 | 当前 Android 示例未使用,可传 null 或空字符串 |
null |
dictDir |
否 | 当前 Android 示例未使用,可传 null 或空字符串 |
null |
sid |
否 | 说话人 ID | 0 |
speed |
否 | 语速 | 1.0 |
建议目录结构:
static/
vits-melo-tts-zh_en/
model.onnx
tokens.txt
lexicon.txt
number.fst
phone.fst
date.fst
matchaIcefall
| 字段 | 是否必填 | 说明 | 当前示例值 |
|---|---|---|---|
modelType |
是 | 固定传 matchaIcefall |
matchaIcefall |
model |
是 | 声学模型文件 | model-steps-3.onnx |
voices |
是 | 这里不是 voices.bin,而是 vocoder 模型文件 |
vocos-16khz-univ.onnx |
tokens |
是 | 词表文件 | tokens.txt |
lexicon |
是 | 发音词典 | lexicon.txt |
numberFst |
否 | 数字归一化规则 | number-zh.fst |
phoneFst |
否 | 电话归一化规则 | phone-zh.fst |
dateFst |
否 | 日期归一化规则 | date-zh.fst |
dataDir |
建议传 | espeak-ng-data 目录,用于中英混合文本发音支持 |
espeak-ng-data/ |
dictDir |
否 | 当前示例未使用,可传空字符串 | "" |
sid |
否 | 当前模型一般传 0 |
0 |
speed |
否 | 语速 | 1.0 |
建议目录结构:
static/
matcha-icefall-zh-en/
model-steps-3.onnx
vocos-16khz-univ.onnx
tokens.txt
lexicon.txt
number-zh.fst
phone-zh.fst
date-zh.fst
espeak-ng-data/
补充说明:
matchaIcefall至少需要两份onnx:model和voices(vocoder)- iOS 侧接入
matchaIcefall时,voices传入的vocoder文件名应和真实输出采样率保持一致,例如vocos-16khz-univ.onnx对应16kHz - 如果
vocoder资源和真实采样率不匹配,iOS 播放时可能出现“像快放、音调变高”的现象;排查时优先核对model与vocoder是否来自同一套模型资源 - 当前插件会优先根据
vocoder文件名中的16khz、24khz、22050等关键字推断 iOS 播放采样率,重命名模型文件时请保留这类采样率信息 vitsMelo当前只需要一份主模型model.onnx- 如果业务层想做模型切换,最少要同步切换
modelType、model、voices和对应规则文件路径
接入步骤
1. 准备模型资源
建议把模型目录放到项目 static 下。默认推荐先接入 matchaIcefall,例如:
static/
matcha-icefall-zh-en/
model-steps-3.onnx
vocos-16khz-univ.onnx
tokens.txt
lexicon.txt
number-zh.fst
phone-zh.fst
date-zh.fst
espeak-ng-data/
如果你想保留另一套中英双语模型做对比,也可以继续接入 vits-melo-tts-zh_en。
2. 页面中初始化插件
先解析静态资源目录,再调用 initSherpaOnxxTts。
vitsMelo:modelType传vitsMelo,voices可传nullmatchaIcefall:modelType传matchaIcefall,model传声学模型,voices传vocoder模型- Android / iOS 端通常需要先通过
plus.io.convertLocalFileSystemURL('/static/...')把静态资源目录转换成应用内可访问的绝对路径,再把该路径拼接给model、tokens、lexicon等字段 - 鸿蒙端模型资源通常放在插件
resources/rawfile目录下,因此页面层直接传相对目录即可,例如vits-melo-tts-zh_en/model.onnx或matcha-icefall-zh-en/model-steps-3.onnx - 当前鸿蒙实现已经验证可直接把这些
rawfile相对路径传给sherpa-onnx,不再额外复制到应用沙箱 - 如果页面层要做跨平台模型切换,建议把“资源根目录解析”单独封装:Android / iOS 返回本地绝对路径,鸿蒙返回
rawfile相对目录
3. 业务触发播报
通过 start({ text }) 播放文本;如果有播放控制需求,可接入 pause、resume、stop。
模型下载地址
vits模型(支持中英文):https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-melo-tts-zh_en.tar.bz2
推荐模型说明
- 强烈推荐优先使用
matchaIcefall模型,尤其适合对首包速度、整体播报速度和交互响应时间有要求的业务场景 matchaIcefall在当前项目中的实际体验非常快,初始化后播报启动更积极,适合实时播报、消息通知、短文本连续朗读等场景- 如果你的业务重点是“尽快出声”,
matchaIcefall应该作为首选模型 vitsMelo仍然可以继续使用,适合做兼容对比或保留另一套中英双语模型方案,但默认推荐顺序应优先考虑matchaIcefall
TTS说明
模型下载地址:TTS模型下载强烈推荐使用 matchaIcefall 模型,速度非常快,适合作为默认首选模型vits-melo-tts-zh_en 模型同样支持中英双语,可作为备用模型或效果对比模型暂停/恢复功能依赖于底层模型实现,部分模型可能不支持真正的暂停
uni-app x 页面用例
vitsMelo 页面调用示例
<template>
<view class="page">
<button @click="initTTs">初始化TTS</button>
<button @click="playTts">开始播报</button>
<button @click="pauseTts">暂停</button>
<button @click="resumeTts">继续</button>
<button @click="stopTts">停止</button>
</view>
</template>
<script setup>
import {
initSherpaOnxxTts,
start,
pause,
resume,
stop
} from "@/uni_modules/xwq-sherpa-onnx-tts"
const content = ref("清晨推开窗,一股清冽的寒气扑面而来")
const initTTs = () => {
const path = "static/vits-melo-tts-zh_en"
const staticPath = UTSAndroid.getResourcePath(path)
if (staticPath == null || staticPath == "") {
console.log("VITS 静态资源路径解析失败")
return
}
initSherpaOnxxTts({
modelType: "vitsMelo",
model: staticPath + "/model.onnx",
voices: null,
tokens: staticPath + "/tokens.txt",
dataDir: null,
lexicon: staticPath + "/lexicon.txt",
numberFst: staticPath + "/number.fst",
phoneFst: staticPath + "/phone.fst",
dateFst: staticPath + "/date.fst",
sid: 0,
speed: 1.0,
success: () => {
console.log("初始化成功")
},
fail: (result) => {
console.log("初始化失败", result)
}
})
}
const playTts = () => {
start({
text: content.value,
finished: () => {
console.log("播放完成")
},
fail: (result) => {
console.log("播放失败", result)
}
})
}
const pauseTts = () => {
pause()
}
const resumeTts = () => {
resume()
}
const stopTts = () => {
stop()
}
</script>
<style>
.page {
display: flex;
flex-direction: column;
padding: 24px;
gap: 12px;
}
</style>
matchaIcefall 页面调用示例
<template>
<view class="page">
<button @click="initTTs">初始化TTS</button>
<button @click="playTts">开始播报</button>
<button @click="pauseTts">暂停</button>
<button @click="resumeTts">继续</button>
<button @click="stopTts">停止</button>
</view>
</template>
<script setup>
import { ref } from "vue"
import {
initSherpaOnxxTts,
start,
pause,
resume,
stop
} from "@/uni_modules/xwq-sherpa-onnx-tts"
const content = ref("中英文合成测试。Today is a bright day, welcome to try the matcha icefall zh en model.")
const initTTs = () => {
const path = "static/matcha-icefall-zh-en"
const staticPath = UTSAndroid.getResourcePath(path)
if (staticPath == null || staticPath == "") {
console.log("matcha 静态资源路径解析失败")
return
}
initSherpaOnxxTts({
modelType: "matchaIcefall",
model: staticPath + "/model-steps-3.onnx",
voices: staticPath + "/vocos-16khz-univ.onnx",
tokens: staticPath + "/tokens.txt",
dataDir: staticPath + "/espeak-ng-data",
dictDir: "",
lexicon: staticPath + "/lexicon.txt",
numberFst: staticPath + "/number-zh.fst",
phoneFst: staticPath + "/phone-zh.fst",
dateFst: staticPath + "/date-zh.fst",
sid: 0,
speed: 1.0,
success: () => {
console.log("matcha 初始化成功")
},
fail: (result) => {
console.log("matcha 初始化失败", result)
}
})
}
const playTts = () => {
start({
text: content.value,
finished: () => {
console.log("播放完成")
},
fail: (result) => {
console.log("播放失败", result)
}
})
}
const pauseTts = () => {
pause()
}
const resumeTts = () => {
resume()
}
const stopTts = () => {
stop()
}
</script>
<style>
.page {
display: flex;
flex-direction: column;
padding: 24px;
gap: 12px;
}
</style>
uni-app 页面用例
如果是传统 uni-app 页面,静态资源路径通常可以通过 plus.io.convertLocalFileSystemURL 获取。
vitsMelo 页面调用示例
<template>
<view class="page">
<button @click="initTTs">初始化TTS</button>
<button @click="playTts">开始播报</button>
<button @click="pauseTts">暂停</button>
<button @click="resumeTts">继续</button>
<button @click="stopTts">停止</button>
</view>
</template>
<script>
import {
initSherpaOnxxTts,
start,
pause,
resume,
stop
} from "@/uni_modules/xwq-sherpa-onnx-tts"
export default {
data() {
return {
content: "清晨推开窗,一股清冽的寒气扑面而来"
}
},
methods: {
initTTs() {
const path = "/static/vits-melo-tts-zh_en"
const staticPath = plus.io.convertLocalFileSystemURL(path)
if (!staticPath) {
console.log("VITS 静态资源路径解析失败")
return
}
initSherpaOnxxTts({
modelType: "vitsMelo",
model: staticPath + "/model.onnx",
voices: null,
tokens: staticPath + "/tokens.txt",
dataDir: null,
lexicon: staticPath + "/lexicon.txt",
numberFst: staticPath + "/number.fst",
phoneFst: staticPath + "/phone.fst",
dateFst: staticPath + "/date.fst",
sid: 0,
speed: 1.0,
success: () => {
console.log("初始化成功")
},
fail: (result) => {
console.log("初始化失败", result)
}
})
},
playTts() {
start({
text: this.content,
finished: () => {
console.log("播放完成")
},
fail: (result) => {
console.log("播放失败", result)
}
})
},
pauseTts() {
pause()
},
resumeTts() {
resume()
},
stopTts() {
stop()
}
}
}
</script>
<style>
.page {
padding: 24rpx;
}
</style>
matchaIcefall 页面调用示例
<template>
<view class="page">
<button @click="initTTs">初始化TTS</button>
<button @click="playTts">开始播报</button>
<button @click="pauseTts">暂停</button>
<button @click="resumeTts">继续</button>
<button @click="stopTts">停止</button>
</view>
</template>
<script>
import {
initSherpaOnxxTts,
start,
pause,
resume,
stop
} from "@/uni_modules/xwq-sherpa-onnx-tts"
export default {
data() {
return {
content: "中英文合成测试。Today is a bright day, welcome to try the matcha icefall zh en model."
}
},
methods: {
initTTs() {
const path = "/static/matcha-icefall-zh-en"
const staticPath = plus.io.convertLocalFileSystemURL(path)
if (!staticPath) {
console.log("matcha 静态资源路径解析失败")
return
}
initSherpaOnxxTts({
modelType: "matchaIcefall",
model: staticPath + "/model-steps-3.onnx",
voices: staticPath + "/vocos-16khz-univ.onnx",
tokens: staticPath + "/tokens.txt",
dataDir: staticPath + "/espeak-ng-data",
dictDir: "",
lexicon: staticPath + "/lexicon.txt",
numberFst: staticPath + "/number-zh.fst",
phoneFst: staticPath + "/phone-zh.fst",
dateFst: staticPath + "/date-zh.fst",
sid: 0,
speed: 1.0,
success: () => {
console.log("matcha 初始化成功")
},
fail: (result) => {
console.log("matcha 初始化失败", result)
}
})
},
playTts() {
start({
text: this.content,
finished: () => {
console.log("播放完成")
},
fail: (result) => {
console.log("播放失败", result)
}
})
},
pauseTts() {
pause()
},
resumeTts() {
resume()
},
stopTts() {
stop()
}
}
}
</script>
<style>
.page {
padding: 24rpx;
}
</style>
鸿蒙端 页面用例
使用前注意
* 鸿蒙端使用sherpa_onnx语音识别特别说明:
* 将路径:unpackage\dist\dev\app-harmony\entry\build-profile.json5文件拷贝到根目录harmony-configs/entry下(目录没有的需要手动创建)
*
* 在harmony-configs/entry/build-profile.json5中配置参数字段:buildOption下面新增以下内容
* "sourceOption": {
* "workers": [
* '../uni_modules/xwq-sherpa-onnx/utssdk/app-harmony/TtsWorker.ets'
* ]
* }
模型资源需要放在插件目录resources/rawfile目录下面
- 鸿蒙端当前也已支持和 Android / iOS 一致的
modelType分流策略 vitsMelo:modelType传vitsMelo,voices可传nullmatchaIcefall:modelType传matchaIcefall,model传声学模型,voices传vocoder模型,例如vocos-16khz-univ.onnx- 如果要在鸿蒙端做模型切换,至少要同步切换
modelType、model、voices、tokens、lexicon以及对应的fst/dataDir路径 - 当前鸿蒙端资源解析链路为“页面层传
rawfile相对路径 -> worker 直接把路径传给sherpa-onnx”,不再执行额外的资源复制
vitsMelo 页面调用示例
<template>
<view class="page">
<button @click="initTTs">初始化TTS</button>
<button @click="playTts">开始播报</button>
<button @click="pauseTts">暂停</button>
<button @click="resumeTts">继续</button>
<button @click="stopTts">停止</button>
</view>
</template>
<script>
import {
initSherpaOnxxTts,
start,
pause,
resume,
stop
} from "@/uni_modules/xwq-sherpa-onnx-tts"
export default {
data() {
return {
content: "清晨推开窗,一股清冽的寒气扑面而来"
}
},
methods: {
initTTs() {
const path = "vits-melo-tts-zh_en"
initSherpaOnxxTts({
modelType:"vitsMelo",
model:path+"/model.onnx",
voices:null,
dataDir:"",
dictDir:"",
tokens:path+"/tokens.txt",
lexicon:`${path}/lexicon.txt`,
numberFst:`${path}/number.fst`,
phoneFst:`${path}/phone.fst`,
dateFst:`${path}/date.fst`,
// sid:0,
// speed:1.0,
success: () => {
console.log('初始化成功')
// onnxStart()
},
fail: (result) => {
console.log('初始化失败',result)
}
})
},
playTts() {
start({
text: this.content,
finished: () => {
console.log("播放完成")
},
fail: (result) => {
console.log("播放失败", result)
}
})
},
pauseTts() {
pause()
},
resumeTts() {
resume()
},
stopTts() {
stop()
}
}
}
</script>
<style>
.page {
padding: 24rpx;
}
</style>
matchaIcefall 页面调用示例
<template>
<view class="page">
<button @click="initTTs">初始化TTS</button>
<button @click="playTts">开始播报</button>
<button @click="pauseTts">暂停</button>
<button @click="resumeTts">继续</button>
<button @click="stopTts">停止</button>
</view>
</template>
<script>
import {
initSherpaOnxxTts,
start,
pause,
resume,
stop
} from "@/uni_modules/xwq-sherpa-onnx-tts"
export default {
data() {
return {
content: "中英文合成测试。Today is a bright day, welcome to try the matcha icefall zh en model."
}
},
methods: {
initTTs() {
const path = "matcha-icefall-zh-en"
initSherpaOnxxTts({
modelType:"matchaIcefall",
model:path+"/model-steps-3.onnx",
voices:path+"/vocos-16khz-univ.onnx",
tokens:path+"/tokens.txt",
dataDir:path+"/espeak-ng-data",
dictDir:"",
lexicon:`${path}/lexicon.txt`,
numberFst:`${path}/number-zh.fst`,
phoneFst:`${path}/phone-zh.fst`,
dateFst:`${path}/date-zh.fst`,
success: () => {
console.log('matcha 初始化成功')
},
fail: (result) => {
console.log('matcha 初始化失败',result)
}
})
},
playTts() {
start({
text: this.content,
finished: () => {
console.log("播放完成")
},
fail: (result) => {
console.log("播放失败", result)
}
})
},
pauseTts() {
pause()
},
resumeTts() {
resume()
},
stopTts() {
stop()
}
}
}
</script>
<style>
.page {
padding: 24rpx;
}
</style>
使用建议
- 建议在页面进入后先调用一次
initSherpaOnxxTts - 初始化完成前不要直接调用
start - 模型、词表、词典、规则文件建议保持在同一静态目录下,便于维护
- 如果是短文本连续播报,建议在上一次
finished后再发起下一次播报,避免业务层抢占播放状态 - 如果
fail回调收到错误,请先检查模型路径、词表路径和静态资源是否已正确打包到应用内

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 1254
赞赏 6
下载 12262226
赞赏 1922
赞赏
京公网安备:11010802035340号