1
- const apiConfig = {
2
- "voice-api" : {
3
- url : "https://ttsapi.zwei.de.eu.org/tts" ,
4
- speakers : {
5
- "zh-CN-XiaoxiaoNeural" : "晓晓" ,
6
- "zh-CN-YunxiNeural" : "云希" ,
7
- "zh-CN-YunjianNeural" : "云健" ,
8
- "zh-CN-XiaoyiNeural" : "晓伊" ,
9
- "zh-CN-YunyangNeural" : "云扬" ,
10
- "zh-CN-XiaochenNeural" : "晓辰" ,
11
- "zh-CN-XiaochenMultilingualNeural" : "晓辰 多语言" ,
12
- "zh-CN-XiaohanNeural" : "晓涵" ,
13
- "zh-CN-XiaomengNeural" : "晓梦" ,
14
- "zh-CN-XiaomoNeural" : "晓墨" ,
15
- "zh-CN-XiaoqiuNeural" : "晓秋" ,
16
- "zh-CN-XiaorouNeural" : "晓柔" ,
17
- "zh-CN-XiaoruiNeural" : "晓睿" ,
18
- "zh-CN-XiaoshuangNeural" : "晓双" ,
19
- "zh-CN-XiaoxiaoDialectsNeural" : "晓晓 方言" ,
20
- "zh-CN-XiaoxiaoMultilingualNeural" : "晓晓 多语言" ,
21
- "zh-CN-XiaoyanNeural" : "晓颜" ,
22
- "zh-CN-XiaoyouNeural" : "晓悠" ,
23
- "zh-CN-XiaoyuMultilingualNeural" : "晓宇 多语言" ,
24
- "zh-CN-XiaozhenNeural" : "晓甄" ,
25
- "zh-CN-YunfengNeural" : "云枫" ,
26
- "zh-CN-YunhaoNeural" : "云皓" ,
27
- "zh-CN-YunjieNeural" : "云杰" ,
28
- "zh-CN-YunxiaNeural" : "云夏" ,
29
- "zh-CN-YunyeNeural" : "云野" ,
30
- "zh-CN-YunyiMultilingualNeural" : "云逸 多语言" ,
31
- "zh-CN-YunzeNeural" : "云泽" ,
32
- "zh-CN-YunfanMultilingualNeural" : "云帆 多语言" ,
33
- "zh-CN-YunxiaoMultilingualNeural" : "云萧 多语言" ,
34
- "zh-CN-guangxi-YunqiNeural" : "云奇 广西" ,
35
- "zh-CN-henan-YundengNeural" : "云登" ,
36
- "zh-CN-liaoning-XiaobeiNeural" : "晓北 辽宁" ,
37
- "zh-CN-liaoning-YunbiaoNeural" : "云彪 辽宁" ,
38
- "zh-CN-shaanxi-XiaoniNeural" : "晓妮" ,
39
- "zh-CN-shandong-YunxiangNeural" : "云翔" ,
40
- "zh-CN-sichuan-YunxiNeural" : "云希 四川" ,
41
- "zh-HK-HiuMaanNeural" : "曉曼" ,
42
- "zh-HK-WanLungNeural" : "雲龍" ,
43
- "zh-HK-HiuGaaiNeural" : "曉佳" ,
44
- "zh-TW-HsiaoChenNeural" : "曉臻" ,
45
- "zh-TW-YunJheNeural" : "雲哲" ,
46
- "zh-TW-HsiaoYuNeural" : "曉雨"
47
- }
48
- }
49
- } ;
50
-
51
- function updateSpeakerOptions ( apiName ) {
52
- const speakers = apiConfig [ apiName ] . speakers ;
53
- const speakerSelect = $ ( '#speaker' ) ;
54
- speakerSelect . empty ( ) ;
55
- Object . entries ( speakers ) . forEach ( ( [ key , value ] ) => {
56
- speakerSelect . append ( new Option ( value , key ) ) ;
57
- } ) ;
1
+ const apiConfig = {
2
+ "voice-api" : {
3
+ url : "https://ttsapi.zwei.de.eu.org/tts" ,
4
+ speakers : {
5
+ "zh-CN-XiaoxiaoNeural" : "晓晓" ,
6
+ "zh-CN-YunxiNeural" : "云希" ,
7
+ "zh-CN-YunjianNeural" : "云健" ,
8
+ "zh-CN-XiaoyiNeural" : "晓伊" ,
9
+ "zh-CN-YunyangNeural" : "云扬" ,
10
+ "zh-CN-XiaochenNeural" : "晓辰" ,
11
+ "zh-CN-XiaochenMultilingualNeural" : "晓辰 多语言" ,
12
+ "zh-CN-XiaohanNeural" : "晓涵" ,
13
+ "zh-CN-XiaomengNeural" : "晓梦" ,
14
+ "zh-CN-XiaomoNeural" : "晓墨" ,
15
+ "zh-CN-XiaoqiuNeural" : "晓秋" ,
16
+ "zh-CN-XiaorouNeural" : "晓柔" ,
17
+ "zh-CN-XiaoruiNeural" : "晓睿" ,
18
+ "zh-CN-XiaoshuangNeural" : "晓双" ,
19
+ "zh-CN-XiaoxiaoDialectsNeural" : "晓晓 方言" ,
20
+ "zh-CN-XiaoxiaoMultilingualNeural" : "晓晓 多语言" ,
21
+ "zh-CN-XiaoyanNeural" : "晓颜" ,
22
+ "zh-CN-XiaoyouNeural" : "晓悠" ,
23
+ "zh-CN-XiaoyuMultilingualNeural" : "晓宇 多语言" ,
24
+ "zh-CN-XiaozhenNeural" : "晓甄" ,
25
+ "zh-CN-YunfengNeural" : "云枫" ,
26
+ "zh-CN-YunhaoNeural" : "云皓" ,
27
+ "zh-CN-YunjieNeural" : "云杰" ,
28
+ "zh-CN-YunxiaNeural" : "云夏" ,
29
+ "zh-CN-YunyeNeural" : "云野" ,
30
+ "zh-CN-YunyiMultilingualNeural" : "云逸 多语言" ,
31
+ "zh-CN-YunzeNeural" : "云泽" ,
32
+ "zh-CN-YunfanMultilingualNeural" : "云帆 多语言" ,
33
+ "zh-CN-YunxiaoMultilingualNeural" : "云萧 多语言" ,
34
+ "zh-CN-guangxi-YunqiNeural" : "云奇 广西" ,
35
+ "zh-CN-henan-YundengNeural" : "云登" ,
36
+ "zh-CN-liaoning-XiaobeiNeural" : "晓北 辽宁" ,
37
+ "zh-CN-liaoning-YunbiaoNeural" : "云彪 辽宁" ,
38
+ "zh-CN-shaanxi-XiaoniNeural" : "晓妮" ,
39
+ "zh-CN-shandong-YunxiangNeural" : "云翔" ,
40
+ "zh-CN-sichuan-YunxiNeural" : "云希 四川" ,
41
+ "zh-HK-HiuMaanNeural" : "曉曼" ,
42
+ "zh-HK-WanLungNeural" : "雲龍" ,
43
+ "zh-HK-HiuGaaiNeural" : "曉佳" ,
44
+ "zh-TW-HsiaoChenNeural" : "曉臻" ,
45
+ "zh-TW-YunJheNeural" : "雲哲" ,
46
+ "zh-TW-HsiaoYuNeural" : "曉雨"
47
+ }
48
+ }
49
+ } ;
50
+
51
+ function updateSpeakerOptions ( apiName ) {
52
+ const speakers = apiConfig [ apiName ] . speakers ;
53
+ const speakerSelect = $ ( '#speaker' ) ;
54
+ speakerSelect . empty ( ) ;
55
+ Object . entries ( speakers ) . forEach ( ( [ key , value ] ) => {
56
+ speakerSelect . append ( new Option ( value , key ) ) ;
57
+ } ) ;
58
+ }
59
+
60
+ function updateSliderLabel ( sliderId , labelId ) {
61
+ const slider = $ ( `#${ sliderId } ` ) ;
62
+ const label = $ ( `#${ labelId } ` ) ;
63
+ label . text ( slider . val ( ) ) ;
64
+ slider . on ( 'input' , function ( ) {
65
+ label . text ( this . value ) ;
66
+ } ) ;
67
+ }
68
+
69
+ $ ( document ) . ready ( function ( ) {
70
+ // 启用工具提示
71
+ $ ( '[data-toggle="tooltip"]' ) . tooltip ( ) ;
72
+
73
+ // 设置初始API为voice-api
74
+ updateSpeakerOptions ( 'voice-api' ) ;
75
+
76
+ // 更新所选 API 的讲述人选项
77
+ $ ( '#api' ) . on ( 'change' , function ( ) {
78
+ updateSpeakerOptions ( this . value ) ;
79
+ } ) ;
80
+
81
+ // 初始化语速和语调滑块
82
+ updateSliderLabel ( 'rate' , 'rateValue' ) ;
83
+ updateSliderLabel ( 'pitch' , 'pitchValue' ) ;
84
+
85
+ $ ( '#text2voice-form' ) . on ( 'submit' , function ( event ) {
86
+ event . preventDefault ( ) ;
87
+ generateVoice ( false ) ;
88
+ } ) ;
89
+
90
+ $ ( '#previewButton' ) . on ( 'click' , function ( ) {
91
+ generateVoice ( true ) ;
92
+ } ) ;
93
+ } ) ;
94
+
95
+ function generateVoice ( isPreview ) {
96
+ const apiName = $ ( '#api' ) . val ( ) ;
97
+ const apiUrl = apiConfig [ apiName ] . url ;
98
+ const speaker = $ ( '#speaker' ) . val ( ) ;
99
+ const text = $ ( '#text' ) . val ( ) ;
100
+ const previewText = isPreview ? text . substring ( 0 , 20 ) : text ; // 预览时获取前20个字
101
+ let url = `${ apiUrl } ?t=${ encodeURIComponent ( previewText ) } &v=${ encodeURIComponent ( speaker ) } ` ;
102
+
103
+ const rate = $ ( '#rate' ) . val ( ) ;
104
+ const pitch = $ ( '#pitch' ) . val ( ) ;
105
+ url += `&r=${ encodeURIComponent ( rate ) } &p=${ encodeURIComponent ( pitch ) } &o=audio-24khz-48kbitrate-mono-mp3` ;
106
+
107
+ $ ( '#loading' ) . show ( ) ;
108
+ $ ( '#result' ) . hide ( ) ;
109
+ $ ( '#generateButton' ) . prop ( 'disabled' , true ) ;
110
+ $ ( '#previewButton' ) . prop ( 'disabled' , true ) ;
111
+
112
+ $ . ajax ( {
113
+ url : url ,
114
+ method : 'GET' ,
115
+ headers : {
116
+ 'x-api-key' : '@ak47' // 添加 API 密钥
117
+ } ,
118
+ xhrFields : {
119
+ responseType : 'blob' // 确保返回的是一个Blob对象
120
+ } ,
121
+ success : function ( blob ) {
122
+ const voiceUrl = URL . createObjectURL ( blob ) ;
123
+ $ ( '#audio' ) . attr ( 'src' , voiceUrl ) ;
124
+ $ ( '#audio' ) [ 0 ] . load ( ) ; // 确保加载音频文件
125
+ if ( ! isPreview ) {
126
+ $ ( '#download' ) . attr ( 'href' , voiceUrl ) ;
127
+ const timestamp = new Date ( ) . toLocaleTimeString ( ) ; // 获取当前时间
128
+ const shortenedText = text . length > 5 ? text . substring ( 0 , 5 ) + '...' : text ; // 截取前5个字
129
+ addHistoryItem ( timestamp , shortenedText , voiceUrl ) ;
58
130
}
59
-
60
- function updateSliderLabel ( sliderId , labelId ) {
61
- const slider = $ ( `#${ sliderId } ` ) ;
62
- const label = $ ( `#${ labelId } ` ) ;
63
- label . text ( slider . val ( ) ) ;
64
- slider . on ( 'input' , function ( ) {
65
- label . text ( this . value ) ;
66
- } ) ;
131
+ $ ( '#result' ) . show ( ) ;
132
+ $ ( '#loading' ) . hide ( ) ;
133
+ $ ( '#generateButton' ) . prop ( 'disabled' , false ) ;
134
+ $ ( '#previewButton' ) . prop ( 'disabled' , false ) ;
135
+ } ,
136
+ error : function ( ) {
137
+ alert ( '请求失败,请检查网络连接' ) ;
138
+ $ ( '#loading' ) . hide ( ) ;
139
+ $ ( '#generateButton' ) . prop ( 'disabled' , false ) ;
140
+ $ ( '#previewButton' ) . prop ( 'disabled' , false ) ;
67
141
}
68
-
69
- $ ( document ) . ready ( function ( ) {
70
- // 启用工具提示
71
- $ ( '[data-toggle="tooltip"]' ) . tooltip ( ) ;
72
-
73
- // 设置初始API为voice-api
74
- updateSpeakerOptions ( 'voice-api' ) ;
75
-
76
- // 更新所选 API 的讲述人选项
77
- $ ( '#api' ) . on ( 'change' , function ( ) {
78
- updateSpeakerOptions ( this . value ) ;
79
- } ) ;
80
-
81
- // 初始化语速和语调滑块
82
- updateSliderLabel ( 'rate' , 'rateValue' ) ;
83
- updateSliderLabel ( 'pitch' , 'pitchValue' ) ;
84
-
85
- $ ( '#text2voice-form' ) . on ( 'submit' , function ( event ) {
86
- event . preventDefault ( ) ;
87
- generateVoice ( false ) ;
88
- } ) ;
89
-
90
- $ ( '#previewButton' ) . on ( 'click' , function ( ) {
91
- generateVoice ( true ) ;
92
- } ) ;
93
- } ) ;
94
-
95
- function generateVoice ( isPreview ) {
96
- const apiName = $ ( '#api' ) . val ( ) ;
97
- const apiUrl = apiConfig [ apiName ] . url ;
98
- const speaker = $ ( '#speaker' ) . val ( ) ;
99
- const text = $ ( '#text' ) . val ( ) ;
100
- const previewText = isPreview ? text . substring ( 0 , 20 ) : text ; // 预览时获取前20个字
101
- let url = `${ apiUrl } ?t=${ encodeURIComponent ( previewText ) } &v=${ encodeURIComponent ( speaker ) } ` ;
102
-
103
- const rate = $ ( '#rate' ) . val ( ) ;
104
- const pitch = $ ( '#pitch' ) . val ( ) ;
105
- url += `&r=${ encodeURIComponent ( rate ) } &p=${ encodeURIComponent ( pitch ) } &o=audio-24khz-48kbitrate-mono-mp3` ;
106
-
107
- $ ( '#loading' ) . show ( ) ;
108
- $ ( '#result' ) . hide ( ) ;
109
- $ ( '#generateButton' ) . prop ( 'disabled' , true ) ;
110
- $ ( '#previewButton' ) . prop ( 'disabled' , true ) ;
111
-
112
- $ . ajax ( {
113
- url : url ,
114
- method : 'GET' ,
115
- headers : {
116
- 'x-api-key' : window . ENV . API_KEY // 动态插入 API 密钥
117
- } ,
118
- xhrFields : {
119
- responseType : 'blob' // 确保返回的是一个Blob对象
120
- } ,
121
- success : function ( blob ) {
122
- const voiceUrl = URL . createObjectURL ( blob ) ;
123
- $ ( '#audio' ) . attr ( 'src' , voiceUrl ) ;
124
- $ ( '#audio' ) [ 0 ] . load ( ) ; // 确保加载音频文件
125
- if ( ! isPreview ) {
126
- $ ( '#download' ) . attr ( 'href' , voiceUrl ) ;
127
- const timestamp = new Date ( ) . toLocaleTimeString ( ) ; // 获取当前时间
128
- const shortenedText = text . length > 5 ? text . substring ( 0 , 5 ) + '...' : text ; // 截取前5个字
129
- addHistoryItem ( timestamp , shortenedText , voiceUrl ) ;
130
- }
131
- $ ( '#result' ) . show ( ) ;
132
- $ ( '#loading' ) . hide ( ) ;
133
- $ ( '#generateButton' ) . prop ( 'disabled' , false ) ;
134
- $ ( '#previewButton' ) . prop ( 'disabled' , false ) ;
135
- } ,
136
- error : function ( ) {
137
- alert ( '请求失败,请检查网络连接' ) ;
138
- $ ( '#loading' ) . hide ( ) ;
139
- $ ( '#generateButton' ) . prop ( 'disabled' , false ) ;
140
- $ ( '#previewButton' ) . prop ( 'disabled' , false ) ;
141
- }
142
- } ) ;
143
- }
144
-
145
- function addHistoryItem ( timestamp , text , audioURL ) {
146
- const historyItems = $ ( '#historyItems' ) ;
147
- const historyItem = $ ( `
148
- <div class="history-item">
149
- <span>${ timestamp } - ${ text } </span>
150
- <div>
151
- <button class="btn btn-secondary" onclick="playAudio('${ audioURL } ')">播放</button>
152
- <button class="btn btn-info" onclick="downloadAudio('${ audioURL } ')">下载</button>
153
- </div>
154
- </div>
155
- ` ) ;
156
- historyItems . append ( historyItem ) ;
157
- }
158
-
159
- function playAudio ( audioURL ) {
160
- const audioElement = $ ( '#audio' ) [ 0 ] ;
161
- audioElement . src = audioURL ;
162
- audioElement . load ( ) ; // 确保加载音频文件
163
- audioElement . play ( ) ;
164
- }
165
-
166
- function downloadAudio ( audioURL ) {
167
- const link = document . createElement ( 'a' ) ;
168
- link . href = audioURL ;
169
- link . download = 'audio.mp3' ;
170
- link . click ( ) ;
171
- }
172
-
173
- function clearHistory ( ) {
174
- $ ( '#historyItems' ) . empty ( ) ;
175
- alert ( "历史记录已清除!" ) ;
176
- }
177
-
142
+ } ) ;
143
+ }
144
+
145
+ function addHistoryItem ( timestamp , text , audioURL ) {
146
+ const historyItems = $ ( '#historyItems' ) ;
147
+ const historyItem = $ ( `
148
+ <div class="history-item">
149
+ <span>${ timestamp } - ${ text } </span>
150
+ <div>
151
+ <button class="btn btn-secondary" onclick="playAudio('${ audioURL } ')">播放</button>
152
+ <button class="btn btn-info" onclick="downloadAudio('${ audioURL } ')">下载</button>
153
+ </div>
154
+ </div>
155
+ ` ) ;
156
+ historyItems . append ( historyItem ) ;
157
+ }
158
+
159
+ function playAudio ( audioURL ) {
160
+ const audioElement = $ ( '#audio' ) [ 0 ] ;
161
+ audioElement . src = audioURL ;
162
+ audioElement . load ( ) ; // 确保加载音频文件
163
+ audioElement . play ( ) ;
164
+ }
165
+
166
+ function downloadAudio ( audioURL ) {
167
+ const link = document . createElement ( 'a' ) ;
168
+ link . href = audioURL ;
169
+ link . download = 'audio.mp3' ;
170
+ link . click ( ) ;
171
+ }
172
+
173
+ function clearHistory ( ) {
174
+ $ ( '#historyItems' ) . empty ( ) ;
175
+ alert ( "历史记录已清除!" ) ;
176
+ }
177
+
0 commit comments