接口对接过程中,百度的是最方便的因为有sdk可以直接使用,讯飞的最麻烦需要自己做参数加密,思必驰dui的虽然没提供SDK但是文档写的比较详细对接过程也很方便快速。
目前无法解决的就是,小程序内无法直接下载的问题,只能提供链接,然后用户自己打开浏览器进行下载(iPhone似乎无解)。
1. 文本转语音
2. 多平台多发音人可选
3. 可调语速
4. 可提供音频下载
5. 良心产品无广告
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> <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> 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.4inlove.ink', 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.4inlove.ink/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似乎无解)。
作者:jinggoing
链接:https://juejin.im/post/5c413f48f265da616e4cb1d0