小程序功能特点
- 文本转语音
- 多平台多发音人可选
- 可调语速
- 可提供音频下载
- 良心产品无广告?
小程序码
已对接在线语音识别服务
小程序截图
服务端主要代码
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似乎无解)。