Commit 9116195733e1ab6fbeba66ec8fcc0a2e6d708b01

Authored by xwenliang
1 parent fe1ead00

feat: 使用新语音接口

... ... @@ -95,15 +95,90 @@ App({
95 95 // domain: 'http://localhost:3003',
96 96 domain: 'https://api.xwenliang.cn',
97 97 getTypeList(){
  98 + const globalData = this;
98 99 return [
99 100 {
100   - desc: '女声一',
101   - createUrl(text){
102   - return `https://api.oick.cn/txt/apiz.php?text=${text}&spd=10`;
  101 + desc: 'Chelsie(女)',
  102 + voice: 'Chelsie',
  103 + async createUrl(text){
  104 + return await globalData.requestTTS(text, 'Chelsie');
  105 + }
  106 + },
  107 + {
  108 + desc: 'Cherry(女)',
  109 + voice: 'Cherry',
  110 + async createUrl(text){
  111 + return await globalData.requestTTS(text, 'Cherry');
  112 + }
  113 + },
  114 + {
  115 + desc: 'Ethan(男)',
  116 + voice: 'Ethan',
  117 + async createUrl(text){
  118 + return await globalData.requestTTS(text, 'Ethan');
  119 + }
  120 + },
  121 + {
  122 + desc: 'Serena(女)',
  123 + voice: 'Serena',
  124 + async createUrl(text){
  125 + return await globalData.requestTTS(text, 'Serena');
  126 + }
  127 + },
  128 + {
  129 + desc: 'Dylan(北京话-男)',
  130 + voice: 'Dylan',
  131 + async createUrl(text){
  132 + return await globalData.requestTTS(text, 'Dylan');
  133 + }
  134 + },
  135 + {
  136 + desc: 'Jada(吴语-女)',
  137 + voice: 'Jada',
  138 + async createUrl(text){
  139 + return await globalData.requestTTS(text, 'Jada');
  140 + }
  141 + },
  142 + {
  143 + desc: 'Sunny(四川话-女)',
  144 + voice: 'Sunny',
  145 + async createUrl(text){
  146 + return await globalData.requestTTS(text, 'Sunny');
103 147 }
104 148 }
105 149 ];
106 150 },
  151 + // TTS接口请求方法
  152 + async requestTTS(text, voice) {
  153 + return new Promise((resolve, reject) => {
  154 + const app = getApp();
  155 + app.request({
  156 + url: `${this.domain}/open-api/wx330e54aa6000516d/tts`,
  157 + data: {
  158 + text,
  159 + voice
  160 + },
  161 + success: (resp) => {
  162 + if (resp.data.code === 2000000) {
  163 + resolve(resp.data.data.url);
  164 + } else {
  165 + wx.showToast({
  166 + title: resp.data.msg || '生成失败',
  167 + icon: 'none'
  168 + });
  169 + reject(new Error(resp.data.msg || '生成失败'));
  170 + }
  171 + },
  172 + fail: (error) => {
  173 + wx.showToast({
  174 + title: '网络错误',
  175 + icon: 'none'
  176 + });
  177 + reject(error);
  178 + }
  179 + });
  180 + });
  181 + },
107 182 getSelectedTypeIndex(){
108 183 const storageKey = 'audioTypeselectedIndex';
109 184 return wx.getStorageSync(storageKey);
... ...
pages/index/index.js
... ... @@ -22,36 +22,37 @@ Page({
22 22 async play(){
23 23 const text = this.data.text || this.data.placeholder;
24 24 const selectedType = this.data.typeList[this.data.selectedIndex];
25   - const url = selectedType.createUrl(text);
26 25 const type = selectedType.desc;
27 26  
28 27 this.resetAudio();
29 28 audio = wx.createInnerAudioContext({useWebAudioImplement: true});
30 29 audio.autoplay = true;
  30 +
31 31 // 检查是否播放过
32 32 const audioList = app.globalData.getAudioList();
33   - const played = audioList.find(v => v.url === url);
34   - // 播放失败要移除缓存内容
35   - audio.onError(err => {
36   - app.globalData.setAudioList('delete', played.path);
37   - wx.showModal({
38   - title: '提示',
39   - content: '该语音播放过但缓存失效,点击确定重新播放',
40   - showCancel: false,
41   - success: res => {
42   - this.play();
43   - }
44   - });
45   - });
46   - // 播放过,使用本地文件减少请求,且从播放列表中移到最前
  33 + let played = audioList.find(v => v.text === text && v.type === type);
  34 +
  35 + // 播放过,直接使用本地文件,无需检查合规性
47 36 if(played){
48 37 played.time = Date.now();
49 38 app.globalData.setAudioList('delete', played.path);
50 39 app.globalData.setAudioList('add', played);
  40 + // 播放失败要移除缓存内容
  41 + audio.onError(err => {
  42 + app.globalData.setAudioList('delete', played.path);
  43 + wx.showModal({
  44 + title: '提示',
  45 + content: '该语音播放过但缓存失效,点击确定重新播放',
  46 + showCancel: false,
  47 + success: res => {
  48 + this.play();
  49 + }
  50 + });
  51 + });
51 52 return audio.src = played.path;
52 53 }
53   -
54   - // 检查文本是否合规
  54 +
  55 + // 未播放过,先检查文本是否合规
55 56 wx.showLoading({
56 57 title: '正在合成语音...',
57 58 mask: true
... ... @@ -82,27 +83,41 @@ Page({
82 83 duration: 2000
83 84 });
84 85 }
85   -
86   - // 未播放过,先下载再播放
87   - wx.downloadFile({
88   - url,
89   - success (res) {
90   - wx.hideLoading();
91   - audio.src = res.tempFilePath;
92   - app.globalData.setAudioList('add', {
93   - // 音频文本
94   - text,
95   - // 音频音效
96   - type,
97   - // 音频网络地址
98   - url,
99   - // 音频本地地址
100   - path: res.tempFilePath,
101   - // 音频创建时间
102   - time: Date.now()
103   - });
104   - }
105   - });
  86 + // 未播放过,调用TTS接口生成语音
  87 + try {
  88 + const url = await selectedType.createUrl(text);
  89 + // 下载并播放
  90 + wx.downloadFile({
  91 + url,
  92 + success (res) {
  93 + wx.hideLoading();
  94 + audio.src = res.tempFilePath;
  95 + app.globalData.setAudioList('add', {
  96 + // 音频文本
  97 + text,
  98 + // 音频音效
  99 + type,
  100 + // 音频网络地址
  101 + url,
  102 + // 音频本地地址
  103 + path: res.tempFilePath,
  104 + // 音频创建时间
  105 + time: Date.now()
  106 + });
  107 + },
  108 + fail(err) {
  109 + console.log(err);
  110 + wx.hideLoading();
  111 + wx.showToast({
  112 + title: '下载失败',
  113 + icon: 'none'
  114 + });
  115 + }
  116 + });
  117 + } catch (error) {
  118 + wx.hideLoading();
  119 + // TTS接口调用失败的错误已经在app.js中处理了
  120 + }
106 121 },
107 122 clear(){
108 123 this.resetAudio();
... ...
project.config.json
1   -{
2   - "description": "项目配置文件。",
3   - "setting": {
4   - "urlCheck": true,
5   - "es6": true,
6   - "enhance": true,
7   - "postcss": true,
8   - "preloadBackgroundData": false,
9   - "minified": true,
10   - "newFeature": true,
11   - "coverView": true,
12   - "nodeModules": false,
13   - "autoAudits": false,
14   - "showShadowRootInWxmlPanel": true,
15   - "scopeDataCheck": false,
16   - "uglifyFileName": false,
17   - "checkInvalidKey": true,
18   - "checkSiteMap": true,
19   - "uploadWithSourceMap": true,
20   - "compileHotReLoad": false,
21   - "lazyloadPlaceholderEnable": false,
22   - "useMultiFrameRuntime": true,
23   - "useApiHook": true,
24   - "useApiHostProcess": true,
25   - "babelSetting": {
26   - "ignore": [],
27   - "disablePlugins": [],
28   - "outputPath": ""
29   - },
30   - "useIsolateContext": false,
31   - "userConfirmedBundleSwitch": false,
32   - "packNpmManually": false,
33   - "packNpmRelationList": [],
34   - "minifyWXSS": true,
35   - "disableUseStrict": false,
36   - "minifyWXML": true,
37   - "showES6CompileOption": false,
38   - "useCompilerPlugins": false,
39   - "ignoreUploadUnusedFiles": true
40   - },
41   - "compileType": "miniprogram",
42   - "libVersion": "2.21.3",
43   - "appid": "wx330e54aa6000516d",
44   - "projectname": "text-to-audio",
45   - "packOptions": {
46   - "ignore": [],
47   - "include": []
48   - },
49   - "editorSetting": {
50   - "tabIndent": "insertSpaces",
51   - "tabSize": 2
52   - },
53   - "condition": {}
  1 +{
  2 + "description": "项目配置文件。",
  3 + "setting": {
  4 + "urlCheck": true,
  5 + "es6": true,
  6 + "enhance": true,
  7 + "postcss": true,
  8 + "preloadBackgroundData": false,
  9 + "minified": true,
  10 + "newFeature": true,
  11 + "coverView": true,
  12 + "nodeModules": false,
  13 + "autoAudits": false,
  14 + "showShadowRootInWxmlPanel": true,
  15 + "scopeDataCheck": false,
  16 + "uglifyFileName": false,
  17 + "checkInvalidKey": true,
  18 + "checkSiteMap": true,
  19 + "uploadWithSourceMap": true,
  20 + "compileHotReLoad": false,
  21 + "lazyloadPlaceholderEnable": false,
  22 + "useMultiFrameRuntime": true,
  23 + "useApiHook": true,
  24 + "useApiHostProcess": true,
  25 + "babelSetting": {
  26 + "ignore": [],
  27 + "disablePlugins": [],
  28 + "outputPath": ""
  29 + },
  30 + "useIsolateContext": false,
  31 + "userConfirmedBundleSwitch": false,
  32 + "packNpmManually": false,
  33 + "packNpmRelationList": [],
  34 + "minifyWXSS": true,
  35 + "disableUseStrict": false,
  36 + "minifyWXML": true,
  37 + "showES6CompileOption": false,
  38 + "useCompilerPlugins": false,
  39 + "ignoreUploadUnusedFiles": true
  40 + },
  41 + "compileType": "miniprogram",
  42 + "libVersion": "2.21.3",
  43 + "appid": "wx330e54aa6000516d",
  44 + "projectname": "text-to-audio",
  45 + "packOptions": {
  46 + "ignore": [],
  47 + "include": []
  48 + },
  49 + "editorSetting": {
  50 + "tabIndent": "insertSpaces",
  51 + "tabSize": 2
  52 + },
  53 + "condition": {}
54 54 }
55 55 \ No newline at end of file
... ...
project.private.config.json 0 → 100644
  1 +{
  2 + "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
  3 + "projectname": "text-to-audio",
  4 + "setting": {
  5 + "compileHotReLoad": true,
  6 + "urlCheck": false
  7 + },
  8 + "libVersion": "3.3.5"
  9 +}
0 10 \ No newline at end of file
... ...