小程序–语音合成tts 对接多平台(讯飞,思必驰,百度)

24次阅读

共计 4347 个字符,预计需要花费 11 分钟才能阅读完成。

小程序功能特点

文本转语音
多平台多发音人可选
可调语速
可提供音频下载
良心产品无广告????

小程序码

已对接在线语音识别服务

思必驰 dui 平台 (超过 40 个免费可选发音人)

讯飞开放平台 (5 个免费可选发音人)

百度语音 (4 个免费发音人可选)

小程序截图

服务端主要代码
class TTSController extends Controller {
async tts () {
let params = this.ctx.query
let result = null
// 根据 plat 参数来调用不同的接口
if (params.plat === ‘xf’) {
result = await this.ctx.service.xftts.getTts(params)
} else if (params.plat === ‘baidu’) {
result = await this.ctx.service.baidutts.getTts(params)
} else {
result = await this.ctx.service.aispeechtts.getTts(params)
}
// 设置 response 的类型,这样客户端接收到的就是一个文件流
this.ctx.response.type = ‘audio/mpeg’
this.ctx.body = result
}
}
小程序客户端 template 代码(使用的 mpvue)
<template>
<div class=”container”>
<div class=”preview”>
<textarea :class=”textAreaFocus? ‘focus’ : ””
auto-height @focus=”bindTextAreaFocus”
@blur=”bindTextAreaBlur” placeholder=” 请输入文本 ”
v-model=”text” maxlength=”256″/>
</div>
<div class=”setting”>
<picker @change=”bindPlatChange” v-model=”platIndex” range-key=”name” :range=”platArr”>
<div class=”item”>
<div class=”label”> 选择平台 </div>
<div class=”value voice”>
{{platArr[platIndex].name}}
</div>
</div>
</picker>
<picker @change=”bindPickerChange” v-model=”index” range-key=”name” :range=”array”>
<div class=”item”>
<div class=”label”> 选择发音人 </div>
<div class=”value voice”>
{{array[index].name}}
</div>
</div>
</picker>
<div class=”item speed”>
<div class=”label”> 调节语速 </div>
<div class=”value”>
<slider @change=”onSpeedChange” :value=”speedObj.default” :step=’speedObj.step’ activeColor=”#6F8FFF” :min=”speedObj.min” :max=”speedObj.max” show-value />
</div>
</div>
</div>
<div style=”height: 140rpx;”>
<div class=”btn-group”>
<div class=”item”><button @click=”audioPlay” type=”main”> 播放合成语音 </button> </div>
<div class=”item”> <button @click=”audioDownload” type=”submain”> 复制链接下载 </button> </div>
</div>
</div>
<div class=”desc”>
说明:tts 是英文 text to speech 的缩写,即文本转语音技术
<contact-button
type=”default-light”
session-from=”weapp”> 联系客服
</contact-button>
</div>
</div>
</template>
script 代码
<script>
import voiceIdArray from ‘./voiceIdArray’

export default {

data () {
return {
array: voiceIdArray.aispeech,
platArr: [{id: ‘xf’, name: ‘ 科大讯飞 ’}, {id: ‘aispeech’, name: ‘ 思必驰 ’}, {id: ‘baidu’, name: ‘ 百度 ’}],
platIndex: 1,
index: 26,
text: ` 改革春风吹满地,吹满地,春风吹满地。\n 中国人民真争气,真争气,人民真争气。\n 这个世界太疯狂,耗子都给猫当伴娘。\n 齐德隆,齐东强。\n 齐德隆的咚得隆咚锵。`,
voiceId: ‘lili1f_diantai’,
speed: 1,
textAreaFocus: false,
audioCtx: null,
ttsServer: ‘https://tts.server.com’,
audioSrc: ”,
downloadUrl: ”,
xfSpeedObj: {
min: 0,
max: 100,
default: 50,
step: 1
},
aispeechSpeedObj: {
min: 0.7,
max: 2,
default: 1,
step: 0.1
},
baiduSpeedObj: {
min: 0,
max: 9,
default: 5,
step: 1
},
speedObj: {}
}
},
watch: {
platIndex (newVal, oldVal) {
if (newVal === 2) {
this.array = voiceIdArray.baidu
this.index = 0
this.speedObj = this.baiduSpeedObj
}
if (newVal === 1) {
this.array = voiceIdArray.aispeech
this.index = 26
this.speedObj = this.aispeechSpeedObj
}
if (newVal === 0) {
this.array = voiceIdArray.xf
this.index = 0
this.speedObj = this.xfSpeedObj
}
}
},
onShareAppMessage () {
return {
title: ‘ 文本转语音服务,多发音人可选 ’
}
},
methods: {
onSpeedChange (e) {
this.speedObj.default = e.target.value
},
bindPlatChange (e) {
this.platIndex = e.target.value * 1
},
bindPickerChange (e) {
this.index = e.target.value
},
getAudioSrc () {
if (this.text === ”) {
return false
}
const speed = this.speedObj.default
const voiceId = this.array[this.index].id
const plat = this.platArr[this.platIndex].id
return encodeURI(`${this.ttsServer}/tts?plat=${plat}&voiceId=${voiceId}&speed=${speed}&text=${this.text}`)
},
getDownloadUrl () {
const plat = this.platArr[this.platIndex].id
const voiceId = this.array[this.index].id
wx.showLoading({
title: ‘ 加载中 ’
})
wx.request({
url: ‘https://tts.server.com/getdownloadurl’,
data: {
plat: plat,
voiceId: voiceId,
speed: this.speedObj.default,
text: this.text
},
header: {
‘content-type’: ‘application/json’ // 默认值
},
success (res) {
wx.hideLoading()
wx.setClipboardData({
data: res.data.short_url,
success (res) {
wx.showToast({
title: ‘ 链接已复制请用浏览器下载 (ios 端无法下载)’,
icon: ‘none’,
duration: 3000
})
}
})
}
})
},
audioPlay () {
this.audioCtx.src = this.getAudioSrc()
if (!this.audioCtx.src) {
wx.showToast({
title: ‘ 请先输入文本 ’,
icon: ‘none’,
duration: 2000
})
return false
}
wx.showLoading({
title: ‘ 加载中 ’
})
this.audioCtx.play()
},
audioDownload () {
this.getDownloadUrl()
},
bindTextAreaBlur (e) {
this.textAreaFocus = false
this.text = e.target.value
},
bindTextAreaFocus () {
this.textAreaFocus = true
}
},

created () {
this.speedObj = this.aispeechSpeedObj
},
mounted () {
this.audioCtx = wx.createInnerAudioContext()
this.audioCtx.onEnded((res) => {
wx.hideLoading()
})
this.audioCtx.onPlay((res) => {
wx.hideLoading()
})
wx.showShareMenu({
withShareTicket: true
})
}
}
</script>
接口对接过程中,百度的是最方便的因为有 sdk 可以直接使用,讯飞的最麻烦需要自己做参数加密,思必驰 dui 的虽然没提供 SDK 但是文档写的比较详细对接过程也很方便快速。
目前无法解决的就是,小程序内无法直接下载的问题,只能提供链接,然后用户自己打开浏览器进行下载(iPhone 似乎无解)。

正文完
 0