Blame Raw
Cohee · e3f41666 · · 200 lines (5.3 KB)
1 contributor
1import { saveTtsProviderSettings } from './index.js';
2
3export { CosyVoiceProvider };
4
5class 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 <span>Windows users Use <a target="_blank" href="https://github.com/v3ucn/CosyVoice_For_Windows">CosyVoice_For_Windows</a>(Unofficial).</span><br/>
56 <span>Macos Users Use <a target="_blank" href="https://github.com/v3ucn/CosyVoice_for_MacOs">CosyVoice_for_MacOs</a>(Unofficial).</span><br/>
57 <br/>
58
59 `;
60
61 return html;
62 }
63
64 onSettingsChange() {
65 // Used when provider settings are updated from UI
66 this.settings.provider_endpoint = $('#tts_endpoint').val();
67
68
69 saveTtsProviderSettings();
70 this.changeTTSSettings();
71 }
72
73 async loadSettings(settings) {
74 // Pupulate Provider UI given input settings
75 if (Object.keys(settings).length == 0) {
76 console.info('Using default TTS Provider settings');
77 }
78
79 // Only accept keys defined in defaultSettings
80 this.settings = this.defaultSettings;
81
82 for (const key in settings) {
83 if (key in this.settings) {
84 this.settings[key] = settings[key];
85 } else {
86 console.debug(`Ignoring non-user-configurable setting: ${key}`);
87 }
88 }
89
90 // Set initial values from the settings
91 $('#tts_endpoint').val(this.settings.provider_endpoint).on('change', this.onSettingsChange.bind(this));
92
93
94 await this.checkReady();
95
96 console.info('ITS: Settings loaded');
97 }
98
99 // Perform a simple readiness check by trying to fetch voiceIds
100 async checkReady() {
101 await Promise.allSettled([this.fetchTtsVoiceObjects(), this.changeTTSSettings()]);
102 }
103
104 async onRefreshClick() {
105 return await this.checkReady();
106 }
107
108 //#################//
109 // TTS Interfaces //
110 //#################//
111
112 async getVoice(voiceName) {
113 if (this.voices.length == 0) {
114 this.voices = await this.fetchTtsVoiceObjects();
115 }
116
117
118 const match = this.voices.filter(
119 v => v.name == voiceName,
120 )[0];
121 console.log(match);
122 if (!match) {
123 throw `TTS Voice name ${voiceName} not found`;
124 }
125 return match;
126 }
127
128
129 async generateTts(text, voiceId) {
130 const response = await this.fetchTtsGeneration(text, voiceId);
131 return response;
132 }
133
134 //###########//
135 // API CALLS //
136 //###########//
137 async fetchTtsVoiceObjects() {
138 const response = await fetch(`${this.settings.provider_endpoint}/speakers`);
139 console.info(response);
140
141 if (!response.ok) {
142 throw new Error(`HTTP ${response.status}: ${await response.json()}`);
143 }
144 const responseJson = await response.json();
145
146
147 this.voices = responseJson;
148
149 return responseJson;
150 }
151
152 // Each time a parameter is changed, we change the configuration
153 async changeTTSSettings() {
154 }
155
156 /**
157 * Fetch TTS generation from the API.
158 * @param {string} inputText Text to generate TTS for
159 * @param {string} voiceId Voice ID to use (model_type&speaker_id))
160 * @returns {Promise<Response|string>} Fetch response
161 */
162 async fetchTtsGeneration(inputText, voiceId, lang = null, forceNoStreaming = false) {
163 console.info(`Generating new TTS for voice_id ${voiceId}`);
164
165 const streaming = this.settings.streaming;
166
167 const params = {
168 text: inputText,
169 speaker: voiceId,
170 };
171
172 if (streaming) {
173 params.streaming = 1;
174 }
175
176 const url = `${this.settings.provider_endpoint}/`;
177
178 const response = await fetch(
179 url,
180 {
181 method: 'POST',
182 headers: {
183 'Content-Type': 'application/json',
184 },
185 body: JSON.stringify(params), // Convert parameter objects to JSON strings
186 },
187 );
188 if (!response.ok) {
189 toastr.error(response.statusText, 'TTS Generation Failed');
190 throw new Error(`HTTP ${response.status}: ${await response.text()}`);
191 }
192 return response;
193 }
194
195
196 // Interface not used
197 async fetchTtsFromHistory(history_item_id) {
198 return Promise.resolve(history_item_id);
199 }
200}