Merge pull request #3060 from erew123/release Support for AllTalk V1 and V2

85d25a8e1372d5b5c47d0c45138d81019923b622

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
1 files changed, +449 -217Showing whitespace changes
public/scripts/extensions/tts/alltalk.js+449 -217
@@ -1,4 +1,5 @@
1import { doExtrasFetch } from '../../extensions.js'; 1import { doExtrasFetch } from '../../extensions.js';
2import { debounce } from '../../utils.js';
2import { saveTtsProviderSettings } from './index.js'; 3import { saveTtsProviderSettings } from './index.js';
3 4
4export { AllTalkTtsProvider }; 5export { AllTalkTtsProvider };
@@ -13,12 +14,17 @@ class AllTalkTtsProvider {
13 // Initialize with default settings if they are not already set 14 // Initialize with default settings if they are not already set
14 this.settings = { 15 this.settings = {
15 provider_endpoint: this.settings.provider_endpoint || 'http://localhost:7851', 16 provider_endpoint: this.settings.provider_endpoint || 'http://localhost:7851',
17 server_version: this.settings.server_version || 'v2',
16 language: this.settings.language || 'en', 18 language: this.settings.language || 'en',
17 voiceMap: this.settings.voiceMap || {}, 19 voiceMap: this.settings.voiceMap || {},
18 at_generation_method: this.settings.at_generation_method || 'standard_generation', 20 at_generation_method: this.settings.at_generation_method || 'standard_generation',
19 narrator_enabled: this.settings.narrator_enabled || 'false', 21 narrator_enabled: this.settings.narrator_enabled || 'false',
20 at_narrator_text_not_inside: this.settings.at_narrator_text_not_inside || 'narrator', 22 at_narrator_text_not_inside: this.settings.at_narrator_text_not_inside || 'narrator',
21 narrator_voice_gen: this.settings.narrator_voice_gen || 'female_01.wav',23 narrator_voice_gen: this.settings.narrator_voice_gen || 'Please set a voice',
24 rvc_character_voice: this.settings.rvc_character_voice || 'Disabled',
25 rvc_character_pitch: this.settings.rvc_character_pitch || '0',
26 rvc_narrator_voice: this.settings.rvc_narrator_voice || 'Disabled',
27 rvc_narrator_pitch: this.settings.rvc_narrator_pitch || '0',
22 finetuned_model: this.settings.finetuned_model || 'false', 28 finetuned_model: this.settings.finetuned_model || 'false',
23 }; 29 };
24 // Separate property for dynamically updated settings from the server 30 // Separate property for dynamically updated settings from the server
@@ -26,9 +32,11 @@ class AllTalkTtsProvider {
26 modelsAvailable: [], 32 modelsAvailable: [],
27 currentModel: '', 33 currentModel: '',
28 deepspeed_available: false, 34 deepspeed_available: false,
29 deepSpeedEnabled: false,35 deepspeed_enabled: false,
30 lowVramEnabled: false,36 lowvram_capable: false,
37 lowvram_enabled: false,
31 }; 38 };
39 this.rvcVoices = []; // Initialize rvcVoices as an empty array
32 } 40 }
33 ready = false; 41 ready = false;
34 voices = []; 42 voices = [];
@@ -56,113 +64,162 @@ class AllTalkTtsProvider {
56 }; 64 };
57 65
58 get settingsHtml() { 66 get settingsHtml() {
59 let html = '<div class="at-settings-separator">AllTalk Settings</div>';67 // HTML template literals can trigger ESLint quotes warnings when quotes are used in HTML attributes.
6068 // Disabling quotes rule for this one line as it's a false positive with HTML template literals.
61 html += `<div class="at-settings-row">69 // eslint-disable-next-line quotes
6270 let html = `<div class="at-settings-separator">AllTalk V2 Settings</div>`;
63 <div class="at-settings-option">71
64 <label for="at_generation_method">AllTalk TTS Generation Method</label>72 html += `<div class='at-settings-row'>
65 <select id="at_generation_method">73 <div class='at-settings-option'>
66 <option value="standard_generation">Standard Audio Generation (AT Narrator - Optional)</option>74 <label for='at_generation_method'>AllTalk TTS Generation Method</label>
67 <option value="streaming_enabled">Streaming Audio Generation (AT Narrator - Disabled)</option>75 <select id='at_generation_method'>
76 <option value='standard_generation'>Standard Audio Generation (AT Narrator - Optional)</option>
77 <option value='streaming_enabled'>Streaming Audio Generation (AT Narrator - Disabled)</option>
68 </select> 78 </select>
69 </div> 79 </div>
70 </div>`; 80 </div>`;
71 81
72 html += `<div class="at-settings-row">82 html += `<div class='at-settings-row'>
7383 <div class='at-settings-option'>
74 <div class="at-settings-option">84 <label for='at_narrator_enabled'>AT Narrator</label>
75 <label for="at_narrator_enabled">AT Narrator</label>85 <select id='at_narrator_enabled'>
76 <select id="at_narrator_enabled">86 <option value='true'>Enabled</option>
77 <option value="true">Enabled</option>87 <option value='silent'>Enabled (Silenced)</option>
78 <option value="false">Disabled</option>88 <option value='false'>Disabled</option>
79 </select> 89 </select>
80 </div> 90 </div>
81 91
82 <div class="at-settings-option">92 <div class='at-settings-option'>
83 <label for="at_narrator_text_not_inside">Text Not Inside * or " is</label>93 <label for='at_narrator_text_not_inside'>Text Not Inside * or " is</label>
84 <select id="at_narrator_text_not_inside">94 <select id='at_narrator_text_not_inside'>
85 <option value="narrator">Narrator</option>95 <option value='character'>Character</option>
86 <option value="character">Character</option>96 <option value='narrator'>Narrator</option>
97 <option value='silent'>Silent</option>
87 </select> 98 </select>
88 </div> 99 </div>
89
90 </div>`; 100 </div>`;
91 101
92 html += `<div class="at-settings-row">102 html += `<div class='at-settings-row'>
93 <div class="at-settings-option">103 <div class='at-settings-option'>
94 <label for="narrator_voice">Narrator Voice</label>104 <label for='narrator_voice'>Narrator Voice</label>
95 <select id="narrator_voice">`;105 <select id='narrator_voice'>`;
96 if (this.voices) { 106 if (this.voices) {
97 for (let voice of this.voices) { 107 for (let voice of this.voices) {
98 html += `<option value="${voice.voice_id}">${voice.name}</option>`;108 html += `<option value='${voice.voice_id}'>${voice.name}</option>`;
99 } 109 }
100 } 110 }
101 html += `</select> 111 html += `</select>
102 </div> 112 </div>
103 <div class="at-settings-option">113 <div class='at-settings-option'>
104 <label for="language_options">Language</label>114 <label for='language_options'>Language</label>
105 <select id="language_options">`;115 <select id='language_options'>`;
106 for (let language in this.languageLabels) { 116 for (let language in this.languageLabels) {
107 html += `<option value="${this.languageLabels[language]}" ${this.languageLabels[language] === this.settings?.language ? 'selected="selected"' : ''}>${language}</option>`;117 html += `<option value='${this.languageLabels[language]}' ${this.languageLabels[language] === this.settings?.language ? 'selected="selected"' : ''}>${language}</option>`;
108 } 118 }
109 html += `</select> 119 html += `</select>
110 </div> 120 </div>
111 </div>`; 121 </div>`;
112 122
123 html += `<div class='at-settings-row'>
124 <div class='at-settings-option'>
125 <label for='rvc_character_voice'>RVC Character</label>
126 <select id='rvc_character_voice'>`;
127 if (this.rvcVoices) {
128 for (let rvccharvoice of this.rvcVoices) {
129 html += `<option value='${rvccharvoice.voice_id}'>${rvccharvoice.name}</option>`;
130 }
131 }
132 html += `</select>
133 </div>
134 <div class='at-settings-option'>
135 <label for='rvc_narrator_voice'>RVC Narrator</label>
136 <select id='rvc_narrator_voice'>`;
137 if (this.rvcVoices) {
138 for (let rvcnarrvoice of this.rvcVoices) {
139 html += `<option value='${rvcnarrvoice.voice_id}'>${rvcnarrvoice.name}</option>`;
140 }
141 }
142 html += `</select>
143 </div>
144</div>`;
113 145
114 html += `<div class="at-model-endpoint-row">146 html += `<div class='at-settings-row'>
115 <div class="at-model-option">147 <div class='at-settings-option'>
116 <label for="switch_model">Switch Model</label>148 <label for='rvc_character_pitch'>RVC Character Pitch</label>
117 <select id="switch_model">149 <select id='rvc_character_pitch'>`;
118 <option value="api_tts">API TTS</option>150 for (let i = -24; i <= 24; i++) {
119 <option value="api_local">API Local</option>151 const selected = i === 0 ? 'selected="selected"' : '';
120 <option value="xttsv2_local">XTTSv2 Local</option>152 html += `<option value='${i}' ${selected}>${i}</option>`;
121 </select>153 }
154 html += `</select>
122 </div> 155 </div>
156 <div class='at-settings-option'>
157 <label for='rvc_narrator_pitch'>RVC Narrator Pitch</label>
158 <select id='rvc_narrator_pitch'>`;
159 for (let i = -24; i <= 24; i++) {
160 const selected = i === 0 ? 'selected="selected"' : '';
161 html += `<option value='${i}' ${selected}>${i}</option>`;
162 }
163 html += `</select>
123 </div> 164 </div>
165 </div>`;
124 166
125 <div class="at-model-endpoint-row">167 html += `<div class='at-model-endpoint-row'>
168 <div class='at-model-option'>
169 <label for='switch_model'>Switch Model</label>
170 <select id='switch_model'>
171 <!-- Options will be dynamically populated -->
172 </select>
173 </div>
126 174
127 <div class="at-endpoint-option">175 <div class='at-endpoint-option'>
128 <label for="at_server">AllTalk Endpoint:</label>176 <label for='at_server'>AllTalk Endpoint:</label>
129 <input id="at_server" type="text" class="text_pole" maxlength="80" value="${this.settings.provider_endpoint}"/>177 <input id='at_server' type='text' class='text_pole' maxlength='80' value='${this.settings.provider_endpoint}'/>
130 <i><b>Important:</b> Must match IP address & port in AllTalk settings.</i>
131 </div> 178 </div>
132 </div>`; 179 </div>`;
133 180
181 html += `<div class='at-settings-row'>
182 <div class='at-settings-option'>
183 <label for='server_version'>AllTalk Server Version</label>
184 <select id='server_version'>
185 <option value='v1'>AllTalk V1</option>
186 <option value='v2'>AllTalk V2</option>
187 </select>
188 </div>
189 </div>`;
134 190
135 html += `<div class="at-model-endpoint-row">191 html += `<div class='at-model-endpoint-row'>
136 <div class="at-settings-option">192 <div class='at-settings-option'>
137 <label for="low_vram">Low VRAM</label>193 <label for='low_vram'>Low VRAM</label>
138 <input id="low_vram" type="checkbox"/>194 <input id='low_vram' type='checkbox'/>
139 </div> 195 </div>
140 <div class="at-settings-option">196 <div class='at-settings-option'>
141 <label for="deepspeed">DeepSpeed</label>197 <label for='deepspeed'>DeepSpeed</label>
142 <input id="deepspeed" type="checkbox"/>198 <input id='deepspeed' type='checkbox'/>
143 </div> 199 </div>
144 <div class="at-settings-option status-option">200 <div class='at-settings-option status-option'>
145 <span>Status: <span id="status_info">Ready</span></span>201 <span>Status: <span id='status_info'>Ready</span></span>
146 </div> 202 </div>
147 <div class="at-settings-option empty-option">203 <div class='at-settings-option empty-option'>
148 <!-- This div remains empty for spacing --> 204 <!-- This div remains empty for spacing -->
149 </div> 205 </div>
150</div>`; 206</div>`;
151 207
152208 html += `<div class='at-website-row'>
153 html += `<div class="at-website-row">209 <div class='at-website-option'>
154 <div class="at-website-option">210 <span>AllTalk V2<a target='_blank' href='${this.settings.provider_endpoint}'>Config & Docs</a>.</span>
155 <span>AllTalk <a target="_blank" href="${this.settings.provider_endpoint}">Config & Docs</a>.</span>
156 </div> 211 </div>
157 212
158 <div class="at-website-option">213 <div class='at-website-option'>
159 <span>AllTalk <a target="_blank" href="https://github.com/erew123/alltalk_tts/">Website</a>.</span>214 <span>AllTalk <a target='_blank' href='https://github.com/erew123/alltalk_tts/'>Website</a>.</span>
160 </div> 215 </div>
161</div>`; 216</div>`;
162 217
163 html += `<div class="at-website-row">218 html += `<div class='at-website-row'>
164<div class="at-website-option">219<div class='at-website-option'>
165<span><strong>Text-generation-webui</strong> users - Uncheck <strong>Enable TTS</strong> in Text-generation-webui.</span>220<span>- If you <strong>change your TTS engine</strong> in AllTalk, you will need to <strong>Reload</strong> (button above) and re-select your voices.</span><br><br>
221<span>- Assuming the server is <strong>Status: Ready</strong>, most problems will be resolved by hitting Reload and selecting voices that match the loaded TTS engine.</span><br><br>
222<span>- <strong>Text-generation-webui</strong> users - Uncheck <strong>Enable TTS</strong> in the TGWUI interface, or you will hear 2x voices and file names being generated.</span>
166</div> 223</div>
167</div>`; 224</div>`;
168 225
@@ -193,25 +250,25 @@ class AllTalkTtsProvider {
193 // Update UI elements to reflect the loaded settings 250 // Update UI elements to reflect the loaded settings
194 $('#at_server').val(this.settings.provider_endpoint); 251 $('#at_server').val(this.settings.provider_endpoint);
195 $('#language_options').val(this.settings.language); 252 $('#language_options').val(this.settings.language);
196 //$('#voicemap').val(this.settings.voiceMap);
197 $('#at_generation_method').val(this.settings.at_generation_method); 253 $('#at_generation_method').val(this.settings.at_generation_method);
198 $('#at_narrator_enabled').val(this.settings.narrator_enabled); 254 $('#at_narrator_enabled').val(this.settings.narrator_enabled);
199 $('#at_narrator_text_not_inside').val(this.settings.at_narrator_text_not_inside); 255 $('#at_narrator_text_not_inside').val(this.settings.at_narrator_text_not_inside);
200 $('#narrator_voice').val(this.settings.narrator_voice_gen); 256 $('#narrator_voice').val(this.settings.narrator_voice_gen);
257 $('#rvc_character_voice').val(this.settings.rvc_character_voice);
258 $('#rvc_narrator_voice').val(this.settings.rvc_narrator_voice);
259 $('#rvc_character_pitch').val(this.settings.rvc_character_pitch);
260 $('#rvc_narrator_pitch').val(this.settings.rvc_narrator_pitch);
201 261
202 console.debug('AllTalkTTS: Settings loaded'); 262 console.debug('AllTalkTTS: Settings loaded');
203 await this.initEndpoint();
204 }
205
206 async initEndpoint() {
207 try { 263 try {
208 // Check if TTS provider is ready 264 // Check if TTS provider is ready
209 this.setupEventListeners();
210 this.updateLanguageDropdown();
211 await this.checkReady(); 265 await this.checkReady();
212 await this.updateSettingsFromServer(); // Fetch dynamic settings from the TTS server 266 await this.updateSettingsFromServer(); // Fetch dynamic settings from the TTS server
213 await this.fetchTtsVoiceObjects(); // Fetch voices only if service is ready 267 await this.fetchTtsVoiceObjects(); // Fetch voices only if service is ready
268 await this.fetchRvcVoiceObjects(); // Fetch RVC voices
214 this.updateNarratorVoicesDropdown(); 269 this.updateNarratorVoicesDropdown();
270 this.updateLanguageDropdown();
271 this.setupEventListeners();
215 this.applySettingsToHTML(); 272 this.applySettingsToHTML();
216 updateStatus('Ready'); 273 updateStatus('Ready');
217 } catch (error) { 274 } catch (error) {
@@ -220,8 +277,8 @@ class AllTalkTtsProvider {
220 } 277 }
221 } 278 }
222 279
280
223 applySettingsToHTML() { 281 applySettingsToHTML() {
224 // Apply loaded settings or use defaults
225 const narratorVoiceSelect = document.getElementById('narrator_voice'); 282 const narratorVoiceSelect = document.getElementById('narrator_voice');
226 const atNarratorSelect = document.getElementById('at_narrator_enabled'); 283 const atNarratorSelect = document.getElementById('at_narrator_enabled');
227 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside'); 284 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
@@ -229,30 +286,26 @@ class AllTalkTtsProvider {
229 this.settings.narrator_voice = this.settings.narrator_voice_gen; 286 this.settings.narrator_voice = this.settings.narrator_voice_gen;
230 // Apply settings to Narrator Voice dropdown 287 // Apply settings to Narrator Voice dropdown
231 if (narratorVoiceSelect && this.settings.narrator_voice) { 288 if (narratorVoiceSelect && this.settings.narrator_voice) {
232 narratorVoiceSelect.value = this.settings.narrator_voice.replace('.wav', '');289 narratorVoiceSelect.value = this.settings.narrator_voice; // Remove the parentheses
233 } 290 }
234 // Apply settings to AT Narrator Enabled dropdown 291 // Apply settings to AT Narrator Enabled dropdown
235 if (atNarratorSelect) { 292 if (atNarratorSelect) {
236 // Sync the state with the checkbox in index.js293 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks');
237 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks'); // Access the checkbox from index.js294 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted');
238 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted'); // Access the checkbox from index.js295 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues');
239 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); // Access the checkbox from index.js
240 // Sync the state with the checkbox in index.js
241 if (this.settings.narrator_enabled) { 296 if (this.settings.narrator_enabled) {
242 ttsPassAsterisksCheckbox.checked = false; 297 ttsPassAsterisksCheckbox.checked = false;
243 $('#tts_pass_asterisks').click(); // Simulate a click event298 $('#tts_pass_asterisks').click();
244 $('#tts_pass_asterisks').trigger('change'); 299 $('#tts_pass_asterisks').trigger('change');
245 } 300 }
246 if (!this.settings.narrator_enabled) { 301 if (!this.settings.narrator_enabled) {
247 ttsPassAsterisksCheckbox.checked = true; 302 ttsPassAsterisksCheckbox.checked = true;
248 $('#tts_pass_asterisks').click(); // Simulate a click event303 $('#tts_pass_asterisks').click();
249 $('#tts_pass_asterisks').trigger('change'); 304 $('#tts_pass_asterisks').trigger('change');
250 } 305 }
251 // Uncheck and set tts_narrate_quoted to false if narrator is enabled306 if (this.settings.narrator_enabled) {
252 if (this.settings.narrator_enabledd) {
253 ttsNarrateQuotedCheckbox.checked = true; 307 ttsNarrateQuotedCheckbox.checked = true;
254 ttsNarrateDialoguesCheckbox.checked = true; 308 ttsNarrateDialoguesCheckbox.checked = true;
255 // Trigger click events instead of change events
256 $('#tts_narrate_quoted').click(); 309 $('#tts_narrate_quoted').click();
257 $('#tts_narrate_quoted').trigger('change'); 310 $('#tts_narrate_quoted').trigger('change');
258 $('#tts_narrate_dialogues').click(); 311 $('#tts_narrate_dialogues').click();
@@ -261,42 +314,30 @@ class AllTalkTtsProvider {
261 atNarratorSelect.value = this.settings.narrator_enabled.toString(); 314 atNarratorSelect.value = this.settings.narrator_enabled.toString();
262 this.settings.narrator_enabled = this.settings.narrator_enabled.toString(); 315 this.settings.narrator_enabled = this.settings.narrator_enabled.toString();
263 } 316 }
264 // Apply settings to the Language dropdown
265 const languageSelect = document.getElementById('language_options'); 317 const languageSelect = document.getElementById('language_options');
266 if (languageSelect && this.settings.language) { 318 if (languageSelect && this.settings.language) {
267 languageSelect.value = this.settings.language; 319 languageSelect.value = this.settings.language;
268 } 320 }
269 // Apply settings to Text Not Inside dropdown
270 if (textNotInsideSelect && this.settings.text_not_inside) { 321 if (textNotInsideSelect && this.settings.text_not_inside) {
271 textNotInsideSelect.value = this.settings.text_not_inside; 322 textNotInsideSelect.value = this.settings.text_not_inside;
272 this.settings.at_narrator_text_not_inside = this.settings.text_not_inside; 323 this.settings.at_narrator_text_not_inside = this.settings.text_not_inside;
273 } 324 }
274 // Apply settings to Generation Method dropdown
275 if (generationMethodSelect && this.settings.at_generation_method) { 325 if (generationMethodSelect && this.settings.at_generation_method) {
276 generationMethodSelect.value = this.settings.at_generation_method; 326 generationMethodSelect.value = this.settings.at_generation_method;
277 } 327 }
278 // Additional logic to disable/enable dropdowns based on the selected generation method
279 const isStreamingEnabled = this.settings.at_generation_method === 'streaming_enabled'; 328 const isStreamingEnabled = this.settings.at_generation_method === 'streaming_enabled';
280 if (isStreamingEnabled) { 329 if (isStreamingEnabled) {
281 // Disable certain dropdowns when streaming is enabled
282 if (atNarratorSelect) atNarratorSelect.disabled = true; 330 if (atNarratorSelect) atNarratorSelect.disabled = true;
283 if (textNotInsideSelect) textNotInsideSelect.disabled = true; 331 if (textNotInsideSelect) textNotInsideSelect.disabled = true;
284 if (narratorVoiceSelect) narratorVoiceSelect.disabled = true; 332 if (narratorVoiceSelect) narratorVoiceSelect.disabled = true;
285 } else { 333 } else {
286 // Enable dropdowns for standard generation
287 if (atNarratorSelect) atNarratorSelect.disabled = false; 334 if (atNarratorSelect) atNarratorSelect.disabled = false;
288 if (textNotInsideSelect) textNotInsideSelect.disabled = !this.settings.narrator_enabled; 335 if (textNotInsideSelect) textNotInsideSelect.disabled = !this.settings.narrator_enabled;
289 if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled; 336 if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
290 } 337 }
291 const modelSelect = document.getElementById('switch_model');
292 if (this.settings.finetuned_model === 'true') {
293 const ftOption = document.createElement('option');
294 ftOption.value = 'XTTSv2 FT';
295 ftOption.textContent = 'XTTSv2 FT';
296 modelSelect.appendChild(ftOption);
297 }
298 } 338 }
299 339
340
300 //##############################// 341 //##############################//
301 // Check AT Server is Available // 342 // Check AT Server is Available //
302 //##############################// 343 //##############################//
@@ -320,7 +361,6 @@ class AllTalkTtsProvider {
320 } catch (error) { 361 } catch (error) {
321 console.error('Error checking TTS service readiness:', error); 362 console.error('Error checking TTS service readiness:', error);
322 this.ready = false; // Ensure ready flag is set to false in case of error 363 this.ready = false; // Ensure ready flag is set to false in case of error
323 throw error; // Rethrow the error for further handling
324 } 364 }
325 } 365 }
326 366
@@ -336,10 +376,9 @@ class AllTalkTtsProvider {
336 } 376 }
337 const data = await response.json(); 377 const data = await response.json();
338 const voices = data.voices.map(filename => { 378 const voices = data.voices.map(filename => {
339 const voiceName = filename.replace('.wav', '');
340 return { 379 return {
341 name: voiceName,380 name: filename,
342 voice_id: voiceName,381 voice_id: filename,
343 preview_url: null, // Preview URL will be dynamically generated 382 preview_url: null, // Preview URL will be dynamically generated
344 lang: 'en', // Default language 383 lang: 'en', // Default language
345 }; 384 };
@@ -348,33 +387,138 @@ class AllTalkTtsProvider {
348 return voices; // Also return this list 387 return voices; // Also return this list
349 } 388 }
350 389
390 async fetchRvcVoiceObjects() {
391 if (this.settings.server_version !== 'v2') {
392 console.log('Skipping RVC voices fetch for V1 server');
393 return [];
394 }
395
396 console.log('Fetching RVC Voices');
397 try {
398 const response = await fetch(`${this.settings.provider_endpoint}/api/rvcvoices`);
399 if (!response.ok) {
400 const errorText = await response.text();
401 console.error('Error text:', errorText);
402 throw new Error(`HTTP ${response.status}: ${errorText}`);
403 }
404
405 const data = await response.json();
406 if (!data || !data.rvcvoices) {
407 console.error('Invalid data format:', data);
408 throw new Error('Invalid data format received from /api/rvcvoices');
409 }
410
411 const voices = data.rvcvoices.map(filename => {
412 return {
413 name: filename,
414 voice_id: filename,
415 };
416 });
417
418 console.log('RVC voices:', voices);
419 this.rvcVoices = voices; // Assign to the class property
420 this.updateRvcVoiceDropdowns(); // Update UI after fetching voices
421 return voices; // Also return this list
422 } catch (error) {
423 console.error('Error fetching RVC voices:', error);
424 this.rvcVoices = [{ name: 'Disabled', voice_id: 'Disabled' }]; // Set default on error
425 throw error;
426 } finally {
427 // Ensure dropdowns are updated even if there was an error
428 this.updateRvcVoiceDropdowns();
429 }
430 }
431
351 //##########################################// 432 //##########################################//
352 // Get Current AT Server Config & Update ST // 433 // Get Current AT Server Config & Update ST //
353 //##########################################// 434 //##########################################//
354 435
355 async updateSettingsFromServer() { 436 async updateSettingsFromServer() {
356 try { 437 try {
357 // Fetch current settings
358 const response = await fetch(`${this.settings.provider_endpoint}/api/currentsettings`); 438 const response = await fetch(`${this.settings.provider_endpoint}/api/currentsettings`);
359 if (!response.ok) { 439 if (!response.ok) {
360 throw new Error(`Failed to fetch current settings: ${response.statusText}`); 440 throw new Error(`Failed to fetch current settings: ${response.statusText}`);
361 } 441 }
362 const currentSettings = await response.json(); 442 const currentSettings = await response.json();
363 // Update internal settings443 currentSettings.models_available.sort((a, b) => a.name.localeCompare(b.name));
444
445 this.settings.enginesAvailable = currentSettings.engines_available;
446 this.settings.currentEngineLoaded = currentSettings.current_engine_loaded;
364 this.settings.modelsAvailable = currentSettings.models_available; 447 this.settings.modelsAvailable = currentSettings.models_available;
365 this.settings.currentModel = currentSettings.current_model_loaded; 448 this.settings.currentModel = currentSettings.current_model_loaded;
449 this.settings.deepspeed_capable = currentSettings.deepspeed_capable;
366 this.settings.deepspeed_available = currentSettings.deepspeed_available; 450 this.settings.deepspeed_available = currentSettings.deepspeed_available;
367 this.settings.deepSpeedEnabled = currentSettings.deepspeed_status;451 this.settings.deepspeed_enabled = currentSettings.deepspeed_enabled;
368 this.settings.lowVramEnabled = currentSettings.low_vram_status;452 this.settings.lowvram_capable = currentSettings.lowvram_capable;
369 this.settings.finetuned_model = currentSettings.finetuned_model;453 this.settings.lowvram_enabled = currentSettings.lowvram_enabled;
370 // Update HTML elements454
455 await this.fetchRvcVoiceObjects(); // Fetch RVC voices
456
371 this.updateModelDropdown(); 457 this.updateModelDropdown();
372 this.updateCheckboxes(); 458 this.updateCheckboxes();
459 this.updateRvcVoiceDropdowns(); // Update the RVC voice dropdowns
373 } catch (error) { 460 } catch (error) {
374 console.error(`Error updating settings from server: ${error}`); 461 console.error(`Error updating settings from server: ${error}`);
375 } 462 }
376 } 463 }
377 464
465 updateRvcVoiceDropdowns() {
466 // Handle all RVC-related elements
467 const rvcElements = document.querySelectorAll('.rvc-setting');
468 const isV2 = this.settings.server_version === 'v2';
469
470 rvcElements.forEach(element => {
471 element.style.display = isV2 ? 'block' : 'none';
472 });
473
474 // Update and disable/enable character voice dropdown
475 const rvcCharacterVoiceSelect = document.getElementById('rvc_character_voice');
476 if (rvcCharacterVoiceSelect) {
477 rvcCharacterVoiceSelect.disabled = !isV2;
478 if (this.rvcVoices) {
479 rvcCharacterVoiceSelect.innerHTML = '';
480 for (let voice of this.rvcVoices) {
481 const option = document.createElement('option');
482 option.value = voice.voice_id;
483 option.textContent = voice.name;
484 if (voice.voice_id === this.settings.rvc_character_voice) {
485 option.selected = true;
486 }
487 rvcCharacterVoiceSelect.appendChild(option);
488 }
489 }
490 }
491
492 // Update and disable/enable narrator voice dropdown
493 const rvcNarratorVoiceSelect = document.getElementById('rvc_narrator_voice');
494 if (rvcNarratorVoiceSelect) {
495 rvcNarratorVoiceSelect.disabled = !isV2;
496 if (this.rvcVoices) {
497 rvcNarratorVoiceSelect.innerHTML = '';
498 for (let voice of this.rvcVoices) {
499 const option = document.createElement('option');
500 option.value = voice.voice_id;
501 option.textContent = voice.name;
502 if (voice.voice_id === this.settings.rvc_narrator_voice) {
503 option.selected = true;
504 }
505 rvcNarratorVoiceSelect.appendChild(option);
506 }
507 }
508 }
509
510 // Update pitch inputs
511 const characterPitch = document.getElementById('rvc_character_pitch');
512 if (characterPitch) {
513 characterPitch.disabled = !isV2;
514 }
515
516 const narratorPitch = document.getElementById('rvc_narrator_pitch');
517 if (narratorPitch) {
518 narratorPitch.disabled = !isV2;
519 }
520 }
521
378 //###################################################// 522 //###################################################//
379 // Get Current AT Server Config & Update ST (Models) // 523 // Get Current AT Server Config & Update ST (Models) //
380 //###################################################// 524 //###################################################//
@@ -385,9 +529,9 @@ class AllTalkTtsProvider {
385 modelSelect.innerHTML = ''; // Clear existing options 529 modelSelect.innerHTML = ''; // Clear existing options
386 this.settings.modelsAvailable.forEach(model => { 530 this.settings.modelsAvailable.forEach(model => {
387 const option = document.createElement('option'); 531 const option = document.createElement('option');
388 option.value = model.model_name;532 option.value = model.name;
389 option.textContent = model.model_name; // Use model_name instead of name533 option.textContent = model.name; // Use model name directly
390 option.selected = model.model_name === this.settings.currentModel;534 option.selected = model.name === this.settings.currentModel;
391 modelSelect.appendChild(option); 535 modelSelect.appendChild(option);
392 }); 536 });
393 } 537 }
@@ -400,13 +544,36 @@ class AllTalkTtsProvider {
400 updateCheckboxes() { 544 updateCheckboxes() {
401 const deepspeedCheckbox = document.getElementById('deepspeed'); 545 const deepspeedCheckbox = document.getElementById('deepspeed');
402 const lowVramCheckbox = document.getElementById('low_vram'); 546 const lowVramCheckbox = document.getElementById('low_vram');
403 if (lowVramCheckbox) lowVramCheckbox.checked = this.settings.lowVramEnabled;547
548 // Handle DeepSpeed checkbox
404 if (deepspeedCheckbox) { 549 if (deepspeedCheckbox) {
405 deepspeedCheckbox.checked = this.settings.deepSpeedEnabled;550 if (this.settings.deepspeed_capable) {
406 deepspeedCheckbox.disabled = !this.settings.deepspeed_available; // Disable checkbox if deepspeed is not available551 // If TTS engine is capable of using DeepSpeed
552 deepspeedCheckbox.disabled = !this.settings.deepspeed_available;
553 this.settings.deepspeed_enabled = this.settings.deepspeed_available && this.settings.deepspeed_enabled;
554 } else {
555 // If TTS engine is NOT capable of using DeepSpeed
556 deepspeedCheckbox.disabled = true;
557 this.settings.deepspeed_enabled = false;
558 }
559 deepspeedCheckbox.checked = this.settings.deepspeed_enabled;
560 }
561
562 // Handle Low VRAM checkbox
563 if (lowVramCheckbox) {
564 if (this.settings.lowvram_capable) {
565 // If TTS engine is capable of low VRAM
566 lowVramCheckbox.disabled = false;
567 } else {
568 // If TTS engine is NOT capable of low VRAM
569 lowVramCheckbox.disabled = true;
570 this.settings.lowvram_enabled = false;
571 }
572 lowVramCheckbox.checked = this.settings.lowvram_enabled;
407 } 573 }
408 } 574 }
409 575
576
410 //###############################################################// 577 //###############################################################//
411 // Get Current AT Server Config & Update ST (AT Narrator Voices) // 578 // Get Current AT Server Config & Update ST (AT Narrator Voices) //
412 //###############################################################// 579 //###############################################################//
@@ -433,8 +600,8 @@ class AllTalkTtsProvider {
433 updateLanguageDropdown() { 600 updateLanguageDropdown() {
434 const languageSelect = document.getElementById('language_options'); 601 const languageSelect = document.getElementById('language_options');
435 if (languageSelect) { 602 if (languageSelect) {
436 // Ensure default language is set (??? whatever that means)603 // Ensure default language is set
437 // this.settings.language = this.settings.language;604 this.settings.language = this.settings.language || 'en';
438 605
439 languageSelect.innerHTML = ''; 606 languageSelect.innerHTML = '';
440 for (let language in this.languageLabels) { 607 for (let language in this.languageLabels) {
@@ -454,16 +621,11 @@ class AllTalkTtsProvider {
454 //########################################// 621 //########################################//
455 622
456 setupEventListeners() { 623 setupEventListeners() {
457
458 let debounceTimeout;
459 const debounceDelay = 500; // Milliseconds
460
461 // Define the event handler function 624 // Define the event handler function
462 const onModelSelectChange = async (event) => { 625 const onModelSelectChange = async (event) => {
463 console.log('Model select change event triggered'); // Debugging statement626 console.log('Model select change event triggered');
464 const selectedModel = event.target.value; 627 const selectedModel = event.target.value;
465 console.log(`Selected model: ${selectedModel}`); // Debugging statement628 console.log(`Selected model: ${selectedModel}`);
466 // Set status to Processing
467 updateStatus('Processing'); 629 updateStatus('Processing');
468 try { 630 try {
469 const response = await fetch(`${this.settings.provider_endpoint}/api/reload?tts_method=${encodeURIComponent(selectedModel)}`, { 631 const response = await fetch(`${this.settings.provider_endpoint}/api/reload?tts_method=${encodeURIComponent(selectedModel)}`, {
@@ -473,39 +635,72 @@ class AllTalkTtsProvider {
473 throw new Error(`HTTP Error: ${response.status}`); 635 throw new Error(`HTTP Error: ${response.status}`);
474 } 636 }
475 const data = await response.json(); 637 const data = await response.json();
476 console.log('POST response data:', data); // Debugging statement638 console.log('POST response data:', data);
477 // Set status to Ready if successful
478 updateStatus('Ready'); 639 updateStatus('Ready');
479 } catch (error) { 640 } catch (error) {
480 console.error('POST request error:', error); // Debugging statement641 console.error('POST request error:', error);
481 // Set status to Error in case of failure
482 updateStatus('Error'); 642 updateStatus('Error');
483 } 643 }
484
485 // Handle response or error
486 };
487
488 const debouncedModelSelectChange = (event) => {
489 clearTimeout(debounceTimeout);
490 debounceTimeout = setTimeout(() => {
491 onModelSelectChange(event);
492 }, debounceDelay);
493 }; 644 };
494 645
495 // Switch Model Listener646 // Switch Model Listener with debounce
496 const modelSelect = document.getElementById('switch_model'); 647 const modelSelect = document.getElementById('switch_model');
497 if (modelSelect) { 648 if (modelSelect) {
498 // Remove the event listener if it was previously added649 const debouncedModelSelectChange = debounce(onModelSelectChange, 1400);
499 // Add the debounced event listener650 modelSelect.addEventListener('change', debouncedModelSelectChange);
500 $(modelSelect).off('change').on('change', debouncedModelSelectChange);651 }
652
653 // AllTalk Server version change listener
654 const serverVersionSelect = document.getElementById('server_version');
655 if (serverVersionSelect) {
656 serverVersionSelect.addEventListener('change', async (event) => {
657 this.settings.server_version = event.target.value;
658 if (event.target.value === 'v2') {
659 await this.fetchRvcVoiceObjects();
660 }
661 this.updateRvcVoiceDropdowns();
662 this.onSettingsChange();
663 });
664 }
665
666 // RVC Voice and Pitch listeners
667 const rvcCharacterVoiceSelect = document.getElementById('rvc_character_voice');
668 if (rvcCharacterVoiceSelect) {
669 rvcCharacterVoiceSelect.addEventListener('change', (event) => {
670 this.settings.rvccharacter_voice_gen = event.target.value;
671 this.onSettingsChange();
672 });
673 }
674
675 const rvcNarratorVoiceSelect = document.getElementById('rvc_narrator_voice');
676 if (rvcNarratorVoiceSelect) {
677 rvcNarratorVoiceSelect.addEventListener('change', (event) => {
678 this.settings.rvcnarrator_voice_gen = event.target.value;
679 this.onSettingsChange();
680 });
681 }
682
683 const rvcCharacterPitchSelect = document.getElementById('rvc_character_pitch');
684 if (rvcCharacterPitchSelect) {
685 rvcCharacterPitchSelect.addEventListener('change', (event) => {
686 this.settings.rvc_character_pitch = event.target.value;
687 this.onSettingsChange();
688 });
689 }
690
691 const rvcNarratorPitchSelect = document.getElementById('rvc_narrator_pitch');
692 if (rvcNarratorPitchSelect) {
693 rvcNarratorPitchSelect.addEventListener('change', (event) => {
694 this.settings.rvc_narrator_pitch = event.target.value;
695 this.onSettingsChange();
696 });
501 } 697 }
502 698
503 // DeepSpeed Listener 699 // DeepSpeed Listener
504 const deepspeedCheckbox = document.getElementById('deepspeed'); 700 const deepspeedCheckbox = document.getElementById('deepspeed');
505 if (deepspeedCheckbox) { 701 if (deepspeedCheckbox) {
506 $(deepspeedCheckbox).off('change').on('change', async (event) => {702 const handleDeepSpeedChange = async (event) => {
507 const deepSpeedValue = event.target.checked ? 'True' : 'False'; 703 const deepSpeedValue = event.target.checked ? 'True' : 'False';
508 // Set status to Processing
509 updateStatus('Processing'); 704 updateStatus('Processing');
510 try { 705 try {
511 const response = await fetch(`${this.settings.provider_endpoint}/api/deepspeed?new_deepspeed_value=${deepSpeedValue}`, { 706 const response = await fetch(`${this.settings.provider_endpoint}/api/deepspeed?new_deepspeed_value=${deepSpeedValue}`, {
@@ -515,23 +710,23 @@ class AllTalkTtsProvider {
515 throw new Error(`HTTP Error: ${response.status}`); 710 throw new Error(`HTTP Error: ${response.status}`);
516 } 711 }
517 const data = await response.json(); 712 const data = await response.json();
518 console.log('POST response data:', data); // Debugging statement713 console.log('POST response data:', data);
519 // Set status to Ready if successful
520 updateStatus('Ready'); 714 updateStatus('Ready');
521 } catch (error) { 715 } catch (error) {
522 console.error('POST request error:', error); // Debugging statement716 console.error('POST request error:', error);
523 // Set status to Error in case of failure
524 updateStatus('Error'); 717 updateStatus('Error');
525 } 718 }
526 });719 };
720
721 const debouncedHandleDeepSpeedChange = debounce(handleDeepSpeedChange, 300);
722 deepspeedCheckbox.addEventListener('change', debouncedHandleDeepSpeedChange);
527 } 723 }
528 724
529 // Low VRAM Listener 725 // Low VRAM Listener
530 const lowVramCheckbox = document.getElementById('low_vram'); 726 const lowVramCheckbox = document.getElementById('low_vram');
531 if (lowVramCheckbox) { 727 if (lowVramCheckbox) {
532 $(lowVramCheckbox).off('change').on('change', async (event) => {728 const handleLowVramChange = async (event) => {
533 const lowVramValue = event.target.checked ? 'True' : 'False'; 729 const lowVramValue = event.target.checked ? 'True' : 'False';
534 // Set status to Processing
535 updateStatus('Processing'); 730 updateStatus('Processing');
536 try { 731 try {
537 const response = await fetch(`${this.settings.provider_endpoint}/api/lowvramsetting?new_low_vram_value=${lowVramValue}`, { 732 const response = await fetch(`${this.settings.provider_endpoint}/api/lowvramsetting?new_low_vram_value=${lowVramValue}`, {
@@ -541,113 +736,112 @@ class AllTalkTtsProvider {
541 throw new Error(`HTTP Error: ${response.status}`); 736 throw new Error(`HTTP Error: ${response.status}`);
542 } 737 }
543 const data = await response.json(); 738 const data = await response.json();
544 console.log('POST response data:', data); // Debugging statement739 console.log('POST response data:', data);
545 // Set status to Ready if successful
546 updateStatus('Ready'); 740 updateStatus('Ready');
547 } catch (error) { 741 } catch (error) {
548 console.error('POST request error:', error); // Debugging statement742 console.error('POST request error:', error);
549 // Set status to Error in case of failure
550 updateStatus('Error'); 743 updateStatus('Error');
551 } 744 }
552 });745 };
746
747 const debouncedHandleLowVramChange = debounce(handleLowVramChange, 300);
748 lowVramCheckbox.addEventListener('change', debouncedHandleLowVramChange);
553 } 749 }
554 750
555 // Narrator Voice Dropdown Listener751 // Other listeners without debounce since they don't need it
556 const narratorVoiceSelect = document.getElementById('narrator_voice'); 752 const narratorVoiceSelect = document.getElementById('narrator_voice');
557 if (narratorVoiceSelect) { 753 if (narratorVoiceSelect) {
558 $(narratorVoiceSelect).off('change').on('change', (event) => {754 narratorVoiceSelect.addEventListener('change', (event) => {
559 this.settings.narrator_voice_gen = `${event.target.value}.wav`;755 this.settings.narrator_voice_gen = `${event.target.value}`;
560 this.onSettingsChange(); // Save the settings after change756 this.onSettingsChange();
561 }); 757 });
562 } 758 }
563 759
564 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside'); 760 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
565 if (textNotInsideSelect) { 761 if (textNotInsideSelect) {
566 $(textNotInsideSelect).off('change').on('change', (event) => {762 textNotInsideSelect.addEventListener('change', (event) => {
567 this.settings.text_not_inside = event.target.value; 763 this.settings.text_not_inside = event.target.value;
568 this.onSettingsChange(); // Save the settings after change764 this.onSettingsChange();
569 }); 765 });
570 } 766 }
571 767
572 // AT Narrator Dropdown Listener 768 // AT Narrator Dropdown Listener
573 const atNarratorSelect = document.getElementById('at_narrator_enabled'); 769 const atNarratorSelect = document.getElementById('at_narrator_enabled');
574 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks'); // Access the checkbox from index.js770 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks');
575 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted'); // Access the checkbox from index.js771 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted');
576 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); // Access the checkbox from index.js772 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues');
577 773
578 if (atNarratorSelect && textNotInsideSelect && narratorVoiceSelect) { 774 if (atNarratorSelect && textNotInsideSelect && narratorVoiceSelect) {
579 $(atNarratorSelect).off('change').on('change', (event) => {775 atNarratorSelect.addEventListener('change', (event) => {
580 const isNarratorEnabled = event.target.value === 'true';776 const narratorOption = event.target.value;
581 this.settings.narrator_enabled = isNarratorEnabled; // Update the setting here777 this.settings.narrator_enabled = narratorOption;
582 textNotInsideSelect.disabled = !isNarratorEnabled;778
583 narratorVoiceSelect.disabled = !isNarratorEnabled;779 const isNarratorDisabled = narratorOption === 'false';
584780 textNotInsideSelect.disabled = isNarratorDisabled;
585 // Sync the state with the checkbox in index.js781 narratorVoiceSelect.disabled = isNarratorDisabled;
586 if (isNarratorEnabled) {782
783 if (narratorOption === 'true') {
587 ttsPassAsterisksCheckbox.checked = false; 784 ttsPassAsterisksCheckbox.checked = false;
588 $('#tts_pass_asterisks').click(); // Simulate a click event785 $('#tts_pass_asterisks').click();
589 $('#tts_pass_asterisks').trigger('change'); 786 $('#tts_pass_asterisks').trigger('change');
590 }
591 if (!isNarratorEnabled) {
592 ttsPassAsterisksCheckbox.checked = true;
593 $('#tts_pass_asterisks').click(); // Simulate a click event
594 $('#tts_pass_asterisks').trigger('change');
595 }
596 // Uncheck and set tts_narrate_quoted to false if narrator is enabled
597 if (isNarratorEnabled) {
598 ttsNarrateQuotedCheckbox.checked = true; 787 ttsNarrateQuotedCheckbox.checked = true;
599 ttsNarrateDialoguesCheckbox.checked = true; 788 ttsNarrateDialoguesCheckbox.checked = true;
600 // Trigger click events instead of change events
601 $('#tts_narrate_quoted').click(); 789 $('#tts_narrate_quoted').click();
602 $('#tts_narrate_quoted').trigger('change'); 790 $('#tts_narrate_quoted').trigger('change');
603 $('#tts_narrate_dialogues').click(); 791 $('#tts_narrate_dialogues').click();
604 $('#tts_narrate_dialogues').trigger('change'); 792 $('#tts_narrate_dialogues').trigger('change');
793 } else if (narratorOption === 'silent') {
794 ttsPassAsterisksCheckbox.checked = false;
795 $('#tts_pass_asterisks').click();
796 $('#tts_pass_asterisks').trigger('change');
797 } else {
798 ttsPassAsterisksCheckbox.checked = true;
799 $('#tts_pass_asterisks').click();
800 $('#tts_pass_asterisks').trigger('change');
605 } 801 }
606 this.onSettingsChange(); // Save the settings after change802
803 this.onSettingsChange();
607 }); 804 });
608 } 805 }
609 806
610
611 // Event Listener for AT Generation Method Dropdown 807 // Event Listener for AT Generation Method Dropdown
612 const atGenerationMethodSelect = document.getElementById('at_generation_method'); 808 const atGenerationMethodSelect = document.getElementById('at_generation_method');
613 const atNarratorEnabledSelect = document.getElementById('at_narrator_enabled');
614 if (atGenerationMethodSelect) { 809 if (atGenerationMethodSelect) {
615 $(atGenerationMethodSelect).off('change').on('change', (event) => {810 atGenerationMethodSelect.addEventListener('change', (event) => {
616 const selectedMethod = event.target.value; 811 const selectedMethod = event.target.value;
617 812
618 if (selectedMethod === 'streaming_enabled') { 813 if (selectedMethod === 'streaming_enabled') {
619 // Disable and unselect AT Narrator 814 // Disable and unselect AT Narrator
620 atNarratorEnabledSelect.disabled = true;815 atNarratorSelect.disabled = true;
621 atNarratorEnabledSelect.value = 'false';816 atNarratorSelect.value = 'false';
622 textNotInsideSelect.disabled = true; 817 textNotInsideSelect.disabled = true;
623 narratorVoiceSelect.disabled = true; 818 narratorVoiceSelect.disabled = true;
624 } else if (selectedMethod === 'standard_generation') { 819 } else if (selectedMethod === 'standard_generation') {
625 // Enable AT Narrator 820 // Enable AT Narrator
626 atNarratorEnabledSelect.disabled = false;821 atNarratorSelect.disabled = false;
627 } 822 }
628 this.settings.at_generation_method = selectedMethod; // Update the setting here823 this.settings.at_generation_method = selectedMethod;
629 this.onSettingsChange(); // Save the settings after change824 this.onSettingsChange();
630 }); 825 });
631 } 826 }
632 827
633 // Listener for Language Dropdown828 // Language Dropdown Listener
634 const languageSelect = document.getElementById('language_options'); 829 const languageSelect = document.getElementById('language_options');
635 if (languageSelect) { 830 if (languageSelect) {
636 $(languageSelect).off('change').on('change', (event) => {831 languageSelect.addEventListener('change', (event) => {
637 this.settings.language = event.target.value; 832 this.settings.language = event.target.value;
638 this.onSettingsChange(); // Save the settings after change833 this.onSettingsChange();
639 }); 834 });
640 } 835 }
641 836
642 // Listener for AllTalk Endpoint Input837 // AllTalk Endpoint Input Listener
643 const atServerInput = document.getElementById('at_server'); 838 const atServerInput = document.getElementById('at_server');
644 if (atServerInput) { 839 if (atServerInput) {
645 $(atServerInput).off('input').on('input', (event) => {840 atServerInput.addEventListener('input', (event) => {
646 this.settings.provider_endpoint = event.target.value; 841 this.settings.provider_endpoint = event.target.value;
647 this.onSettingsChange(); // Save the settings after change842 this.onSettingsChange();
648 }); 843 });
649 } 844 }
650
651 } 845 }
652 846
653 //#############################// 847 //#############################//
@@ -662,6 +856,10 @@ class AllTalkTtsProvider {
662 this.settings.at_generation_method = $('#at_generation_method').val(); 856 this.settings.at_generation_method = $('#at_generation_method').val();
663 this.settings.narrator_enabled = $('#at_narrator_enabled').val(); 857 this.settings.narrator_enabled = $('#at_narrator_enabled').val();
664 this.settings.at_narrator_text_not_inside = $('#at_narrator_text_not_inside').val(); 858 this.settings.at_narrator_text_not_inside = $('#at_narrator_text_not_inside').val();
859 this.settings.rvc_character_voice = $('#rvc_character_voice').val();
860 this.settings.rvc_narrator_voice = $('#rvc_narrator_voice').val();
861 this.settings.rvc_character_pitch = $('#rvc_character_pitch').val();
862 this.settings.rvc_narrator_pitch = $('#rvc_narrator_pitch').val();
665 this.settings.narrator_voice_gen = $('#narrator_voice').val(); 863 this.settings.narrator_voice_gen = $('#narrator_voice').val();
666 // Save the updated settings 864 // Save the updated settings
667 saveTtsProviderSettings(); 865 saveTtsProviderSettings();
@@ -672,8 +870,16 @@ class AllTalkTtsProvider {
672 //#########################// 870 //#########################//
673 871
674 async onRefreshClick() { 872 async onRefreshClick() {
675 await this.initEndpoint();873 try {
676 // Additional actions as needed874 updateStatus('Processing'); // Set status to Processing while refreshing
875 await this.checkReady(); // Check if the TTS provider is ready
876 await this.loadSettings(this.settings); // Reload the settings
877 await this.checkReady(); // Check if the TTS provider is ready
878 updateStatus(this.ready ? 'Ready' : 'Offline'); // Update the status based on readiness
879 } catch (error) {
880 console.error('Error during refresh:', error);
881 updateStatus('Error'); // Set status to Error in case of failure
882 }
677 } 883 }
678 884
679 //##################// 885 //##################//
@@ -684,7 +890,14 @@ class AllTalkTtsProvider {
684 try { 890 try {
685 // Prepare data for POST request 891 // Prepare data for POST request
686 const postData = new URLSearchParams(); 892 const postData = new URLSearchParams();
687 postData.append('voice', `${voiceName}.wav`);893 postData.append('voice', `${voiceName}`);
894
895 // Add RVC parameters for V2 if applicable
896 if (this.settings.server_version === 'v2' && this.settings.rvc_character_voice !== 'Disabled') {
897 postData.append('rvccharacter_voice_gen', this.settings.rvc_character_voice);
898 postData.append('rvccharacter_pitch', this.settings.rvc_character_pitch || '0');
899 }
900
688 // Making the POST request 901 // Making the POST request
689 const response = await fetch(`${this.settings.provider_endpoint}/api/previewvoice/`, { 902 const response = await fetch(`${this.settings.provider_endpoint}/api/previewvoice/`, {
690 method: 'POST', 903 method: 'POST',
@@ -693,24 +906,28 @@ class AllTalkTtsProvider {
693 }, 906 },
694 body: postData, 907 body: postData,
695 }); 908 });
909
696 if (!response.ok) { 910 if (!response.ok) {
697 const errorText = await response.text(); 911 const errorText = await response.text();
698 console.error('[previewTtsVoice] Error Response Text:', errorText);912 console.error('previewTtsVoice Error Response Text:', errorText);
699 throw new Error(`HTTP ${response.status}: ${errorText}`); 913 throw new Error(`HTTP ${response.status}: ${errorText}`);
700 } 914 }
701 // Assuming the server returns a URL to the .wav file915
702 const data = await response.json(); 916 const data = await response.json();
703 if (data.output_file_url) { 917 if (data.output_file_url) {
704 // Use an audio element to play the .wav file918 // Handle V1/V2 URL differences
705 const audioElement = new Audio(data.output_file_url);919 const fullUrl = this.settings.server_version === 'v1'
920 ? data.output_file_url
921 : `${this.settings.provider_endpoint}${data.output_file_url}`;
922
923 const audioElement = new Audio(fullUrl);
706 audioElement.play().catch(e => console.error('Error playing audio:', e)); 924 audioElement.play().catch(e => console.error('Error playing audio:', e));
707 } else { 925 } else {
708 console.warn('[previewTtsVoice] No output file URL received in the response');926 console.warn('previewTtsVoice No output file URL received in the response');
709 throw new Error('No output file URL received in the response'); 927 throw new Error('No output file URL received in the response');
710 } 928 }
711
712 } catch (error) { 929 } catch (error) {
713 console.error('[previewTtsVoice] Exception caught during preview generation:', error);930 console.error('previewTtsVoice Exception caught during preview generation:', error);
714 throw error; 931 throw error;
715 } 932 }
716 } 933 }
@@ -744,7 +961,7 @@ class AllTalkTtsProvider {
744 try { 961 try {
745 if (this.settings.at_generation_method === 'streaming_enabled') { 962 if (this.settings.at_generation_method === 'streaming_enabled') {
746 // Construct the streaming URL 963 // Construct the streaming URL
747 const streamingUrl = `${this.settings.provider_endpoint}/api/tts-generate-streaming?text=${encodeURIComponent(inputText)}&voice=${encodeURIComponent(voiceId)}.wav&language=${encodeURIComponent(this.settings.language)}&output_file=stream_output.wav`;964 const streamingUrl = `${this.settings.provider_endpoint}/api/tts-generate-streaming?text=${encodeURIComponent(inputText)}&voice=${encodeURIComponent(voiceId)}&language=${encodeURIComponent(this.settings.language)}&output_file=stream_output.wav`;
748 console.log('Streaming URL:', streamingUrl); 965 console.log('Streaming URL:', streamingUrl);
749 966
750 // Return the streaming URL directly 967 // Return the streaming URL directly
@@ -770,20 +987,31 @@ class AllTalkTtsProvider {
770 //####################// 987 //####################//
771 988
772 async fetchTtsGeneration(inputText, voiceId) { 989 async fetchTtsGeneration(inputText, voiceId) {
773 // Prepare the request payload
774 const requestBody = new URLSearchParams({ 990 const requestBody = new URLSearchParams({
775 'text_input': inputText, 991 'text_input': inputText,
776 'text_filtering': 'standard', 992 'text_filtering': 'standard',
777 'character_voice_gen': voiceId + '.wav',993 'character_voice_gen': voiceId,
778 'narrator_enabled': this.settings.narrator_enabled, 994 'narrator_enabled': this.settings.narrator_enabled,
779 'narrator_voice_gen': this.settings.narrator_voice_gen + '.wav',995 'narrator_voice_gen': this.settings.narrator_voice_gen,
780 'text_not_inside': this.settings.at_narrator_text_not_inside, 996 'text_not_inside': this.settings.at_narrator_text_not_inside,
781 'language': this.settings.language, 997 'language': this.settings.language,
782 'output_file_name': 'st_output', 998 'output_file_name': 'st_output',
783 'output_file_timestamp': 'true', 999 'output_file_timestamp': 'true',
784 'autoplay': 'false', 1000 'autoplay': 'false',
785 'autoplay_volume': '0.8', 1001 'autoplay_volume': '0.8',
786 }).toString();1002 });
1003
1004 // Add RVC parameters only for V2
1005 if (this.settings.server_version === 'v2') {
1006 if (this.settings.rvc_character_voice !== 'Disabled') {
1007 requestBody.append('rvccharacter_voice_gen', this.settings.rvc_character_voice);
1008 requestBody.append('rvccharacter_pitch', this.settings.rvc_character_pitch || '0');
1009 }
1010 if (this.settings.rvc_narrator_voice !== 'Disabled') {
1011 requestBody.append('rvcnarrator_voice_gen', this.settings.rvc_narrator_voice);
1012 requestBody.append('rvcnarrator_pitch', this.settings.rvc_narrator_pitch || '0');
1013 }
1014 }
787 1015
788 try { 1016 try {
789 const response = await doExtrasFetch( 1017 const response = await doExtrasFetch(
@@ -800,16 +1028,20 @@ class AllTalkTtsProvider {
800 1028
801 if (!response.ok) { 1029 if (!response.ok) {
802 const errorText = await response.text(); 1030 const errorText = await response.text();
803 console.error('[fetchTtsGeneration] Error Response Text:', errorText);1031 console.error('fetchTtsGeneration Error Response Text:', errorText);
804 // toastr.error(response.statusText, 'TTS Generation Failed');
805 throw new Error(`HTTP ${response.status}: ${errorText}`); 1032 throw new Error(`HTTP ${response.status}: ${errorText}`);
806 } 1033 }
807 const data = await response.json(); 1034 const data = await response.json();
808 const outputUrl = data.output_file_url;1035
809 return outputUrl; // Return only the output_file_url1036 // Handle V1/V2 URL differences
1037 const outputUrl = this.settings.server_version === 'v1'
1038 ? data.output_file_url // V1 returns full URL
1039 : `${this.settings.provider_endpoint}${data.output_file_url}`; // V2 returns relative path
1040
1041 return outputUrl;
810 } catch (error) { 1042 } catch (error) {
811 console.error('[fetchTtsGeneration] Exception caught:', error); 1043 console.error('[fetchTtsGeneration] Exception caught:', error);
812 throw error; // Rethrow the error for further handling1044 throw error;
813 } 1045 }
814 } 1046 }
815} 1047}