Add files via upload

a2b4f03d9d73685fea1b412f587b60398c318e9b

刘悦 <zcxey2911@hotmail.com>

Signed
1 files changed, +204 -0Showing whitespace changes
public/scripts/extensions/tts/cosyvoice.js+204 -0
@@ -0,0 +1,204 @@
1+import { getPreviewString, saveTtsProviderSettings } from './index.js';
2+
3+export { CosyVoiceProvider };
4+
5+class CosyVoiceProvider {
6+ //########//
7+ // Config //
8+ //########//
9+
10+ settings;
11+ ready = false;
12+ voices = [];
13+ separator = '. ';
14+ audioElement = document.createElement('audio');
15+
16+ /**
17+ * Perform any text processing before passing to TTS engine.
18+ * @param {string} text Input text
19+ * @returns {string} Processed text
20+ */
21+ processText(text) {
22+ return text;
23+ }
24+
25+ audioFormats = ['wav', 'ogg', 'silk', 'mp3', 'flac'];
26+
27+ languageLabels = {
28+ 'Auto': 'auto',
29+ };
30+
31+ langKey2LangCode = {
32+ 'zh': 'zh-CN',
33+ 'en': 'en-US',
34+ 'ja': 'ja-JP',
35+ 'ko': 'ko-KR',
36+ };
37+
38+ modelTypes = {
39+ CosyVoice: 'CosyVoice',
40+ };
41+
42+ defaultSettings = {
43+ provider_endpoint: 'http://localhost:9880',
44+ format: 'wav',
45+ lang: 'auto',
46+ streaming: false,
47+
48+ };
49+
50+ get settingsHtml() {
51+ let html = `
52+
53+ <label for="tts_endpoint">Provider Endpoint:</label>
54+ <input id="tts_endpoint" type="text" class="text_pole" maxlength="250" height="300" value="${this.defaultSettings.provider_endpoint}"/>
55+ <br/>
56+
57+ `;
58+
59+ return html;
60+ }
61+
62+ onSettingsChange() {
63+ // Used when provider settings are updated from UI
64+ this.settings.provider_endpoint = $('#tts_endpoint').val();
65+
66+
67+ saveTtsProviderSettings();
68+ this.changeTTSSettings();
69+ }
70+
71+ async loadSettings(settings) {
72+ // Pupulate Provider UI given input settings
73+ if (Object.keys(settings).length == 0) {
74+ console.info('Using default TTS Provider settings');
75+ }
76+
77+ // Only accept keys defined in defaultSettings
78+ this.settings = this.defaultSettings;
79+
80+ for (const key in settings) {
81+ if (key in this.settings) {
82+ this.settings[key] = settings[key];
83+ } else {
84+ console.debug(`Ignoring non-user-configurable setting: ${key}`);
85+ }
86+ }
87+
88+ // Set initial values from the settings
89+ $('#tts_endpoint').val(this.settings.provider_endpoint);
90+
91+
92+ await this.checkReady();
93+
94+ console.info('ITS: Settings loaded');
95+ }
96+
97+ // Perform a simple readiness check by trying to fetch voiceIds
98+ async checkReady() {
99+ await Promise.allSettled([this.fetchTtsVoiceObjects(), this.changeTTSSettings()]);
100+ }
101+
102+ async onRefreshClick() {
103+ return;
104+ }
105+
106+ //#################//
107+ // TTS Interfaces //
108+ //#################//
109+
110+ async getVoice(voiceName) {
111+
112+
113+
114+ if (this.voices.length == 0) {
115+ this.voices = await this.fetchTtsVoiceObjects();
116+ }
117+
118+
119+
120+ const match = this.voices.filter(
121+ v => v.name == voiceName,
122+ )[0];
123+ console.log(match);
124+ if (!match) {
125+ throw `TTS Voice name ${voiceName} not found`;
126+ }
127+ return match;
128+ }
129+
130+
131+
132+ async generateTts(text, voiceId) {
133+ const response = await this.fetchTtsGeneration(text, voiceId);
134+ return response;
135+ }
136+
137+ //###########//
138+ // API CALLS //
139+ //###########//
140+ async fetchTtsVoiceObjects() {
141+ const response = await fetch(`${this.settings.provider_endpoint}/speakers`);
142+ console.info(response);
143+
144+ if (!response.ok) {
145+ throw new Error(`HTTP ${response.status}: ${await response.json()}`);
146+ }
147+ const responseJson = await response.json();
148+
149+
150+ this.voices = responseJson;
151+
152+ return responseJson;
153+ }
154+
155+ // Each time a parameter is changed, we change the configuration
156+ async changeTTSSettings() {
157+ }
158+
159+ /**
160+ * Fetch TTS generation from the API.
161+ * @param {string} inputText Text to generate TTS for
162+ * @param {string} voiceId Voice ID to use (model_type&speaker_id))
163+ * @returns {Promise<Response|string>} Fetch response
164+ */
165+ async fetchTtsGeneration(inputText, voiceId, lang = null, forceNoStreaming = false) {
166+ console.info(`Generating new TTS for voice_id ${voiceId}`);
167+
168+ const streaming = this.settings.streaming;
169+
170+ const params = {
171+ text: inputText,
172+ speaker: voiceId,
173+ };
174+
175+ if (streaming) {
176+ params['streaming'] = 1;
177+ }
178+
179+ const url = `${this.settings.provider_endpoint}/`;
180+
181+ const response = await fetch(
182+ url,
183+ {
184+ method: 'POST',
185+ headers: {
186+ 'Content-Type': 'application/json',
187+ },
188+ body: JSON.stringify(params), // 将参数对象转换为 JSON 字符串
189+ },
190+ );
191+ if (!response.ok) {
192+ toastr.error(response.statusText, 'TTS Generation Failed');
193+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
194+ }
195+ return response;
196+ }
197+
198+
199+
200+ // Interface not used
201+ async fetchTtsFromHistory(history_item_id) {
202+ return Promise.resolve(history_item_id);
203+ }
204+}