diff --git a/app.js b/app.js index bc9337d..6b14f0f 100644 --- a/app.js +++ b/app.js @@ -95,15 +95,90 @@ App({ // domain: 'http://localhost:3003', domain: 'https://api.xwenliang.cn', getTypeList(){ + const globalData = this; return [ { - desc: '女声一', - createUrl(text){ - return `https://api.oick.cn/txt/apiz.php?text=${text}&spd=10`; + desc: 'Chelsie(女)', + voice: 'Chelsie', + async createUrl(text){ + return await globalData.requestTTS(text, 'Chelsie'); + } + }, + { + desc: 'Cherry(女)', + voice: 'Cherry', + async createUrl(text){ + return await globalData.requestTTS(text, 'Cherry'); + } + }, + { + desc: 'Ethan(男)', + voice: 'Ethan', + async createUrl(text){ + return await globalData.requestTTS(text, 'Ethan'); + } + }, + { + desc: 'Serena(女)', + voice: 'Serena', + async createUrl(text){ + return await globalData.requestTTS(text, 'Serena'); + } + }, + { + desc: 'Dylan(北京话-男)', + voice: 'Dylan', + async createUrl(text){ + return await globalData.requestTTS(text, 'Dylan'); + } + }, + { + desc: 'Jada(吴语-女)', + voice: 'Jada', + async createUrl(text){ + return await globalData.requestTTS(text, 'Jada'); + } + }, + { + desc: 'Sunny(四川话-女)', + voice: 'Sunny', + async createUrl(text){ + return await globalData.requestTTS(text, 'Sunny'); } } ]; }, + // TTS接口请求方法 + async requestTTS(text, voice) { + return new Promise((resolve, reject) => { + const app = getApp(); + app.request({ + url: `${this.domain}/open-api/wx330e54aa6000516d/tts`, + data: { + text, + voice + }, + success: (resp) => { + if (resp.data.code === 2000000) { + resolve(resp.data.data.url); + } else { + wx.showToast({ + title: resp.data.msg || '生成失败', + icon: 'none' + }); + reject(new Error(resp.data.msg || '生成失败')); + } + }, + fail: (error) => { + wx.showToast({ + title: '网络错误', + icon: 'none' + }); + reject(error); + } + }); + }); + }, getSelectedTypeIndex(){ const storageKey = 'audioTypeselectedIndex'; return wx.getStorageSync(storageKey); diff --git a/pages/index/index.js b/pages/index/index.js index 262ec1e..2b34fd8 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -22,36 +22,37 @@ Page({ async play(){ const text = this.data.text || this.data.placeholder; const selectedType = this.data.typeList[this.data.selectedIndex]; - const url = selectedType.createUrl(text); const type = selectedType.desc; this.resetAudio(); audio = wx.createInnerAudioContext({useWebAudioImplement: true}); audio.autoplay = true; + // 检查是否播放过 const audioList = app.globalData.getAudioList(); - const played = audioList.find(v => v.url === url); - // 播放失败要移除缓存内容 - audio.onError(err => { - app.globalData.setAudioList('delete', played.path); - wx.showModal({ - title: '提示', - content: '该语音播放过但缓存失效,点击确定重新播放', - showCancel: false, - success: res => { - this.play(); - } - }); - }); - // 播放过,使用本地文件减少请求,且从播放列表中移到最前 + let played = audioList.find(v => v.text === text && v.type === type); + + // 播放过,直接使用本地文件,无需检查合规性 if(played){ played.time = Date.now(); app.globalData.setAudioList('delete', played.path); app.globalData.setAudioList('add', played); + // 播放失败要移除缓存内容 + audio.onError(err => { + app.globalData.setAudioList('delete', played.path); + wx.showModal({ + title: '提示', + content: '该语音播放过但缓存失效,点击确定重新播放', + showCancel: false, + success: res => { + this.play(); + } + }); + }); return audio.src = played.path; } - - // 检查文本是否合规 + + // 未播放过,先检查文本是否合规 wx.showLoading({ title: '正在合成语音...', mask: true @@ -82,27 +83,41 @@ Page({ duration: 2000 }); } - - // 未播放过,先下载再播放 - wx.downloadFile({ - url, - success (res) { - wx.hideLoading(); - audio.src = res.tempFilePath; - app.globalData.setAudioList('add', { - // 音频文本 - text, - // 音频音效 - type, - // 音频网络地址 - url, - // 音频本地地址 - path: res.tempFilePath, - // 音频创建时间 - time: Date.now() - }); - } - }); + // 未播放过,调用TTS接口生成语音 + try { + const url = await selectedType.createUrl(text); + // 下载并播放 + wx.downloadFile({ + url, + success (res) { + wx.hideLoading(); + audio.src = res.tempFilePath; + app.globalData.setAudioList('add', { + // 音频文本 + text, + // 音频音效 + type, + // 音频网络地址 + url, + // 音频本地地址 + path: res.tempFilePath, + // 音频创建时间 + time: Date.now() + }); + }, + fail(err) { + console.log(err); + wx.hideLoading(); + wx.showToast({ + title: '下载失败', + icon: 'none' + }); + } + }); + } catch (error) { + wx.hideLoading(); + // TTS接口调用失败的错误已经在app.js中处理了 + } }, clear(){ this.resetAudio(); diff --git a/project.config.json b/project.config.json index 2fb6a00..fd9623e 100644 --- a/project.config.json +++ b/project.config.json @@ -1,54 +1,54 @@ -{ - "description": "项目配置文件。", - "setting": { - "urlCheck": true, - "es6": true, - "enhance": true, - "postcss": true, - "preloadBackgroundData": false, - "minified": true, - "newFeature": true, - "coverView": true, - "nodeModules": false, - "autoAudits": false, - "showShadowRootInWxmlPanel": true, - "scopeDataCheck": false, - "uglifyFileName": false, - "checkInvalidKey": true, - "checkSiteMap": true, - "uploadWithSourceMap": true, - "compileHotReLoad": false, - "lazyloadPlaceholderEnable": false, - "useMultiFrameRuntime": true, - "useApiHook": true, - "useApiHostProcess": true, - "babelSetting": { - "ignore": [], - "disablePlugins": [], - "outputPath": "" - }, - "useIsolateContext": false, - "userConfirmedBundleSwitch": false, - "packNpmManually": false, - "packNpmRelationList": [], - "minifyWXSS": true, - "disableUseStrict": false, - "minifyWXML": true, - "showES6CompileOption": false, - "useCompilerPlugins": false, - "ignoreUploadUnusedFiles": true - }, - "compileType": "miniprogram", - "libVersion": "2.21.3", - "appid": "wx330e54aa6000516d", - "projectname": "text-to-audio", - "packOptions": { - "ignore": [], - "include": [] - }, - "editorSetting": { - "tabIndent": "insertSpaces", - "tabSize": 2 - }, - "condition": {} +{ + "description": "项目配置文件。", + "setting": { + "urlCheck": true, + "es6": true, + "enhance": true, + "postcss": true, + "preloadBackgroundData": false, + "minified": true, + "newFeature": true, + "coverView": true, + "nodeModules": false, + "autoAudits": false, + "showShadowRootInWxmlPanel": true, + "scopeDataCheck": false, + "uglifyFileName": false, + "checkInvalidKey": true, + "checkSiteMap": true, + "uploadWithSourceMap": true, + "compileHotReLoad": false, + "lazyloadPlaceholderEnable": false, + "useMultiFrameRuntime": true, + "useApiHook": true, + "useApiHostProcess": true, + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + }, + "useIsolateContext": false, + "userConfirmedBundleSwitch": false, + "packNpmManually": false, + "packNpmRelationList": [], + "minifyWXSS": true, + "disableUseStrict": false, + "minifyWXML": true, + "showES6CompileOption": false, + "useCompilerPlugins": false, + "ignoreUploadUnusedFiles": true + }, + "compileType": "miniprogram", + "libVersion": "2.21.3", + "appid": "wx330e54aa6000516d", + "projectname": "text-to-audio", + "packOptions": { + "ignore": [], + "include": [] + }, + "editorSetting": { + "tabIndent": "insertSpaces", + "tabSize": 2 + }, + "condition": {} } \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json new file mode 100644 index 0000000..2a4018a --- /dev/null +++ b/project.private.config.json @@ -0,0 +1,9 @@ +{ + "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", + "projectname": "text-to-audio", + "setting": { + "compileHotReLoad": true, + "urlCheck": false + }, + "libVersion": "3.3.5" +} \ No newline at end of file