Merge branch 'release' into staging

12db782a308e0177218106c065f38875d797270b

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

1 files changed, +1072 -1072Ignore whitespace
public/scripts/extensions/tts/alltalk.js+1072 -1072
@@ -1,1072 +1,1072 @@
11import { doExtrasFetch } from '../../extensions.js';
22import { debounce } from '../../utils.js';
33import { saveTtsProviderSettings } from './index.js';
4-
4+
55export { AllTalkTtsProvider };
6-
6+
77class AllTalkTtsProvider {
88 //########//
99 // Config //
1010 //########//
11-
11+
1212 settings = {};
1313 constructor() {
1414 // Initialize with default settings if they are not already set
1515 this.settings = {
1616 provider_endpoint: this.settings.provider_endpoint || 'http://localhost:7851',
1717 server_version: this.settings.server_version || 'v2',
1818 language: this.settings.language || 'en',
1919 voiceMap: this.settings.voiceMap || {},
2020 at_generation_method: this.settings.at_generation_method || 'standard_generation',
2121 narrator_enabled: this.settings.narrator_enabled || 'false',
2222 at_narrator_text_not_inside: this.settings.at_narrator_text_not_inside || 'narrator',
2323 narrator_voice_gen: this.settings.narrator_voice_gen || 'Please set a voice',
2424 rvc_character_voice: this.settings.rvc_character_voice || 'Disabled',
2525 rvc_character_pitch: this.settings.rvc_character_pitch || '0',
2626 rvc_narrator_voice: this.settings.rvc_narrator_voice || 'Disabled',
2727 rvc_narrator_pitch: this.settings.rvc_narrator_pitch || '0',
2828 finetuned_model: this.settings.finetuned_model || 'false',
2929 };
3030 // Separate property for dynamically updated settings from the server
3131 this.dynamicSettings = {
3232 modelsAvailable: [],
3333 currentModel: '',
3434 deepspeed_available: false,
3535 deepspeed_enabled: false,
3636 lowvram_capable: false,
3737 lowvram_enabled: false,
3838 };
3939 this.rvcVoices = []; // Initialize rvcVoices as an empty array
4040 }
4141 ready = false;
4242 voices = [];
4343 separator = '. ';
4444 audioElement = document.createElement('audio');
45-
45+
4646 languageLabels = {
4747 'Arabic': 'ar',
4848 'Brazilian Portuguese': 'pt',
4949 'Chinese': 'zh-cn',
5050 'Czech': 'cs',
5151 'Dutch': 'nl',
5252 'English': 'en',
5353 'French': 'fr',
5454 'German': 'de',
5555 'Italian': 'it',
5656 'Polish': 'pl',
5757 'Russian': 'ru',
5858 'Spanish': 'es',
5959 'Turkish': 'tr',
6060 'Japanese': 'ja',
6161 'Korean': 'ko',
6262 'Hungarian': 'hu',
6363 'Hindi': 'hi',
6464 };
65-
65+
6666 get settingsHtml() {
6767 // HTML template literals can trigger ESLint quotes warnings when quotes are used in HTML attributes.
6868 // Disabling quotes rule for this one line as it's a false positive with HTML template literals.
6969 // eslint-disable-next-line quotes
7070 let html = `<div class="at-settings-separator">AllTalk V2 Settings</div>`;
71-
71+
7272 html += `<div class='at-settings-row'>
7373 <div class='at-settings-option'>
7474 <label for='at_generation_method'>AllTalk TTS Generation Method</label>
7575 <select id='at_generation_method'>
7676 <option value='standard_generation'>Standard Audio Generation (AT Narrator - Optional)</option>
7777 <option value='streaming_enabled'>Streaming Audio Generation (AT Narrator - Disabled)</option>
7878 </select>
7979 </div>
8080 </div>`;
81-
81+
8282 html += `<div class='at-settings-row'>
8383 <div class='at-settings-option'>
8484 <label for='at_narrator_enabled'>AT Narrator</label>
8585 <select id='at_narrator_enabled'>
8686 <option value='true'>Enabled</option>
8787 <option value='silent'>Enabled (Silenced)</option>
8888 <option value='false'>Disabled</option>
8989 </select>
9090 </div>
91-
91+
9292 <div class='at-settings-option'>
9393 <label for='at_narrator_text_not_inside'>Text Not Inside * or " is</label>
9494 <select id='at_narrator_text_not_inside'>
9595 <option value='character'>Character</option>
9696 <option value='narrator'>Narrator</option>
9797 <option value='silent'>Silent</option>
9898 </select>
9999 </div>
100100 </div>`;
101-
101+
102102 html += `<div class='at-settings-row'>
103103 <div class='at-settings-option'>
104104 <label for='narrator_voice'>Narrator Voice</label>
105105 <select id='narrator_voice'>`;
106106 if (this.voices) {
107107 for (let voice of this.voices) {
108108 html += `<option value='${voice.voice_id}'>${voice.name}</option>`;
109109 }
110110 }
111111 html += `</select>
112112 </div>
113113 <div class='at-settings-option'>
114114 <label for='language_options'>Language</label>
115115 <select id='language_options'>`;
116116 for (let language in this.languageLabels) {
117117 html += `<option value='${this.languageLabels[language]}' ${this.languageLabels[language] === this.settings?.language ? 'selected="selected"' : ''}>${language}</option>`;
118118 }
119119 html += `</select>
120120 </div>
121121 </div>`;
122-
122+
123123 html += `<div class='at-settings-row'>
124124 <div class='at-settings-option'>
125125 <label for='rvc_character_voice'>RVC Character</label>
126126 <select id='rvc_character_voice'>`;
127127 if (this.rvcVoices) {
128128 for (let rvccharvoice of this.rvcVoices) {
129129 html += `<option value='${rvccharvoice.voice_id}'>${rvccharvoice.name}</option>`;
130130 }
131131 }
132132 html += `</select>
133133 </div>
134134 <div class='at-settings-option'>
135135 <label for='rvc_narrator_voice'>RVC Narrator</label>
136136 <select id='rvc_narrator_voice'>`;
137137 if (this.rvcVoices) {
138138 for (let rvcnarrvoice of this.rvcVoices) {
139139 html += `<option value='${rvcnarrvoice.voice_id}'>${rvcnarrvoice.name}</option>`;
140140 }
141141 }
142142 html += `</select>
143143 </div>
144144</div>`;
145-
145+
146146 html += `<div class='at-settings-row'>
147147 <div class='at-settings-option'>
148148 <label for='rvc_character_pitch'>RVC Character Pitch</label>
149149 <select id='rvc_character_pitch'>`;
150150 for (let i = -24; i <= 24; i++) {
151151 const selected = i === 0 ? 'selected="selected"' : '';
152152 html += `<option value='${i}' ${selected}>${i}</option>`;
153153 }
154154 html += `</select>
155155 </div>
156156 <div class='at-settings-option'>
157157 <label for='rvc_narrator_pitch'>RVC Narrator Pitch</label>
158158 <select id='rvc_narrator_pitch'>`;
159159 for (let i = -24; i <= 24; i++) {
160160 const selected = i === 0 ? 'selected="selected"' : '';
161161 html += `<option value='${i}' ${selected}>${i}</option>`;
162162 }
163163 html += `</select>
164164 </div>
165165 </div>`;
166-
166+
167167 html += `<div class='at-model-endpoint-row'>
168168 <div class='at-model-option'>
169169 <label for='switch_model'>Switch Model</label>
170170 <select id='switch_model'>
171171 <!-- Options will be dynamically populated -->
172172 </select>
173173 </div>
174-
174+
175175 <div class='at-endpoint-option'>
176176 <label for='at_server'>AllTalk Endpoint:</label>
177177 <input id='at_server' type='text' class='text_pole' maxlength='80' value='${this.settings.provider_endpoint}'/>
178178 </div>
179179 </div>`;
180-
180+
181181 html += `<div class='at-settings-row'>
182182 <div class='at-settings-option'>
183183 <label for='server_version'>AllTalk Server Version</label>
184184 <select id='server_version'>
185185 <option value='v1'>AllTalk V1</option>
186186 <option value='v2'>AllTalk V2</option>
187187 </select>
188188 </div>
189189 </div>`;
190-
190+
191191 html += `<div class='at-model-endpoint-row'>
192192 <div class='at-settings-option'>
193193 <label for='low_vram'>Low VRAM</label>
194194 <input id='low_vram' type='checkbox'/>
195195 </div>
196196 <div class='at-settings-option'>
197197 <label for='deepspeed'>DeepSpeed</label>
198198 <input id='deepspeed' type='checkbox'/>
199199 </div>
200200 <div class='at-settings-option status-option'>
201201 <span>Status: <span id='status_info'>Ready</span></span>
202202 </div>
203203 <div class='at-settings-option empty-option'>
204204 <!-- This div remains empty for spacing -->
205205 </div>
206206</div>`;
207-
207+
208208 html += `<div class='at-website-row'>
209209 <div class='at-website-option'>
210210 <span>AllTalk V2<a target='_blank' href='${this.settings.provider_endpoint}'>Config & Docs</a>.</span>
211211 </div>
212-
212+
213213 <div class='at-website-option'>
214214 <span>AllTalk <a target='_blank' href='https://github.com/erew123/alltalk_tts/'>Website</a>.</span>
215215 </div>
216216</div>`;
217-
217+
218218 html += `<div class='at-website-row'>
219219<div class='at-website-option'>
220220<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>
221221<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>
222222<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>
223223</div>
224224</div>`;
225-
225+
226226 return html;
227227 }
228-
228+
229-
229+
230230 //#################//
231231 // Startup ST & AT //
232232 //#################//
233-
233+
234234 async loadSettings(settings) {
235235 updateStatus('Offline');
236-
236+
237237 if (Object.keys(settings).length === 0) {
238238 console.info('Using default AllTalk TTS Provider settings');
239239 } else {
240240 // Populate settings with provided values, ignoring server-provided settings
241241 for (const key in settings) {
242242 if (key in this.settings) {
243243 this.settings[key] = settings[key];
244244 } else {
245245 console.debug(`Ignoring non-user-configurable setting: ${key}`);
246246 }
247247 }
248248 }
249-
249+
250250 // Update UI elements to reflect the loaded settings
251251 $('#at_server').val(this.settings.provider_endpoint);
252252 $('#language_options').val(this.settings.language);
253253 $('#at_generation_method').val(this.settings.at_generation_method);
254254 $('#at_narrator_enabled').val(this.settings.narrator_enabled);
255255 $('#at_narrator_text_not_inside').val(this.settings.at_narrator_text_not_inside);
256256 $('#narrator_voice').val(this.settings.narrator_voice_gen);
257257 $('#rvc_character_voice').val(this.settings.rvc_character_voice);
258258 $('#rvc_narrator_voice').val(this.settings.rvc_narrator_voice);
259259 $('#rvc_character_pitch').val(this.settings.rvc_character_pitch);
260260 $('#rvc_narrator_pitch').val(this.settings.rvc_narrator_pitch);
261-
261+
262262 console.debug('AllTalkTTS: Settings loaded');
263263 try {
264264 // Check if TTS provider is ready
265265 await this.checkReadysetupEventListeners();
266- await this.updateSettingsFromServer(); // Fetch dynamic settings from the TTS server
266+ this.updateLanguageDropdown();
267- await this.fetchTtsVoiceObjects(); // Fetch voices only if service is ready
267+ await this.checkReady();
268268 await this.fetchRvcVoiceObjectsupdateSettingsFromServer(); // Fetch RVCdynamic voices settings from the TTS server
269- this.updateNarratorVoicesDropdown();
269+ await this.fetchTtsVoiceObjects(); // Fetch voices only if service is ready
270- this.updateLanguageDropdown();
270+ await this.fetchRvcVoiceObjects(); // Fetch RVC voices
271271 this.setupEventListenersupdateNarratorVoicesDropdown();
272272 this.applySettingsToHTML();
273273 updateStatus('Ready');
274274 } catch (error) {
275275 console.error('Error loading settings:', error);
276276 updateStatus('Offline');
277277 }
278278 }
279-
279+
280-
280+
281281 applySettingsToHTML() {
282282 const narratorVoiceSelect = document.getElementById('narrator_voice');
283283 const atNarratorSelect = document.getElementById('at_narrator_enabled');
284284 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
285285 const generationMethodSelect = document.getElementById('at_generation_method');
286286 this.settings.narrator_voice = this.settings.narrator_voice_gen;
287287 // Apply settings to Narrator Voice dropdown
288288 if (narratorVoiceSelect && this.settings.narrator_voice) {
289289 narratorVoiceSelect.value = this.settings.narrator_voice; // Remove the parentheses
290290 }
291291 // Apply settings to AT Narrator Enabled dropdown
292292 if (atNarratorSelect) {
293293 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks');
294294 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted');
295295 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues');
296296 if (this.settings.narrator_enabled) {
297297 ttsPassAsterisksCheckbox.checked = false;
298298 $('#tts_pass_asterisks').click();
299299 $('#tts_pass_asterisks').trigger('change');
300300 }
301301 if (!this.settings.narrator_enabled) {
302302 ttsPassAsterisksCheckbox.checked = true;
303303 $('#tts_pass_asterisks').click();
304304 $('#tts_pass_asterisks').trigger('change');
305305 }
306306 if (this.settings.narrator_enabled) {
307307 ttsNarrateQuotedCheckbox.checked = true;
308308 ttsNarrateDialoguesCheckbox.checked = true;
309309 $('#tts_narrate_quoted').click();
310310 $('#tts_narrate_quoted').trigger('change');
311311 $('#tts_narrate_dialogues').click();
312312 $('#tts_narrate_dialogues').trigger('change');
313313 }
314314 atNarratorSelect.value = this.settings.narrator_enabled.toString();
315315 this.settings.narrator_enabled = this.settings.narrator_enabled.toString();
316316 }
317317 const languageSelect = document.getElementById('language_options');
318318 if (languageSelect && this.settings.language) {
319319 languageSelect.value = this.settings.language;
320320 }
321321 if (textNotInsideSelect && this.settings.text_not_inside) {
322322 textNotInsideSelect.value = this.settings.text_not_inside;
323323 this.settings.at_narrator_text_not_inside = this.settings.text_not_inside;
324324 }
325325 if (generationMethodSelect && this.settings.at_generation_method) {
326326 generationMethodSelect.value = this.settings.at_generation_method;
327327 }
328328 const isStreamingEnabled = this.settings.at_generation_method === 'streaming_enabled';
329329 if (isStreamingEnabled) {
330330 if (atNarratorSelect) atNarratorSelect.disabled = true;
331331 if (textNotInsideSelect) textNotInsideSelect.disabled = true;
332332 if (narratorVoiceSelect) narratorVoiceSelect.disabled = true;
333333 } else {
334334 if (atNarratorSelect) atNarratorSelect.disabled = false;
335335 if (textNotInsideSelect) textNotInsideSelect.disabled = !this.settings.narrator_enabled;
336336 if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
337337 }
338338 }
339-
339+
340-
340+
341341 //##############################//
342342 // Check AT Server is Available //
343343 //##############################//
344-
344+
345345 async checkReady() {
346346 try {
347347 const response = await fetch(`${this.settings.provider_endpoint}/api/ready`);
348348 // Check if the HTTP request was successful
349349 if (!response.ok) {
350350 throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`);
351351 }
352352 const statusText = await response.text();
353353 // Check if the response is 'Ready'
354354 if (statusText === 'Ready') {
355355 this.ready = true; // Set the ready flag to true
356356 console.log('TTS service is ready.');
357357 } else {
358358 this.ready = false;
359359 console.log('TTS service is not ready.');
360360 }
361361 } catch (error) {
362362 console.error('Error checking TTS service readiness:', error);
363363 this.ready = false; // Ensure ready flag is set to false in case of error
364364 }
365365 }
366-
366+
367367 //######################//
368368 // Get Available Voices //
369369 //######################//
370-
370+
371371 async fetchTtsVoiceObjects() {
372372 const response = await fetch(`${this.settings.provider_endpoint}/api/voices`);
373373 if (!response.ok) {
374374 const errorText = await response.text();
375375 throw new Error(`HTTP ${response.status}: ${errorText}`);
376376 }
377377 const data = await response.json();
378378 const voices = data.voices.map(filename => {
379379 return {
380380 name: filename,
381381 voice_id: filename,
382382 preview_url: null, // Preview URL will be dynamically generated
383383 lang: 'en', // Default language
384384 };
385385 });
386386 this.voices = voices; // Assign to the class property
387387 return voices; // Also return this list
388388 }
389-
389+
390390 async fetchRvcVoiceObjects() {
391391 if (this.settings.server_version !== 'v2') {
392392 console.log('Skipping RVC voices fetch for V1 server');
393393 return [];
394394 }
395-
395+
396396 console.log('Fetching RVC Voices');
397397 try {
398398 const response = await fetch(`${this.settings.provider_endpoint}/api/rvcvoices`);
399399 if (!response.ok) {
400400 const errorText = await response.text();
401401 console.error('Error text:', errorText);
402402 throw new Error(`HTTP ${response.status}: ${errorText}`);
403403 }
404-
404+
405405 const data = await response.json();
406406 if (!data || !data.rvcvoices) {
407407 console.error('Invalid data format:', data);
408408 throw new Error('Invalid data format received from /api/rvcvoices');
409409 }
410-
410+
411411 const voices = data.rvcvoices.map(filename => {
412412 return {
413413 name: filename,
414414 voice_id: filename,
415415 };
416416 });
417-
417+
418418 console.log('RVC voices:', voices);
419419 this.rvcVoices = voices; // Assign to the class property
420420 this.updateRvcVoiceDropdowns(); // Update UI after fetching voices
421421 return voices; // Also return this list
422422 } catch (error) {
423423 console.error('Error fetching RVC voices:', error);
424424 this.rvcVoices = [{ name: 'Disabled', voice_id: 'Disabled' }]; // Set default on error
425425 throw error;
426426 } finally {
427427 // Ensure dropdowns are updated even if there was an error
428428 this.updateRvcVoiceDropdowns();
429429 }
430430 }
431-
431+
432432 //##########################################//
433433 // Get Current AT Server Config & Update ST //
434434 //##########################################//
435-
435+
436436 async updateSettingsFromServer() {
437437 try {
438438 const response = await fetch(`${this.settings.provider_endpoint}/api/currentsettings`);
439439 if (!response.ok) {
440440 throw new Error(`Failed to fetch current settings: ${response.statusText}`);
441441 }
442442 const currentSettings = await response.json();
443443 currentSettings.models_available.sort((a, b) => a.name.localeCompare(b.name));
444-
444+
445445 this.settings.enginesAvailable = currentSettings.engines_available;
446446 this.settings.currentEngineLoaded = currentSettings.current_engine_loaded;
447447 this.settings.modelsAvailable = currentSettings.models_available;
448448 this.settings.currentModel = currentSettings.current_model_loaded;
449449 this.settings.deepspeed_capable = currentSettings.deepspeed_capable;
450450 this.settings.deepspeed_available = currentSettings.deepspeed_available;
451451 this.settings.deepspeed_enabled = currentSettings.deepspeed_enabled;
452452 this.settings.lowvram_capable = currentSettings.lowvram_capable;
453453 this.settings.lowvram_enabled = currentSettings.lowvram_enabled;
454-
454+
455455 await this.fetchRvcVoiceObjects(); // Fetch RVC voices
456-
456+
457457 this.updateModelDropdown();
458458 this.updateCheckboxes();
459459 this.updateRvcVoiceDropdowns(); // Update the RVC voice dropdowns
460460 } catch (error) {
461461 console.error(`Error updating settings from server: ${error}`);
462462 }
463463 }
464-
464+
465465 updateRvcVoiceDropdowns() {
466466 // Handle all RVC-related elements
467467 const rvcElements = document.querySelectorAll('.rvc-setting');
468468 const isV2 = this.settings.server_version === 'v2';
469-
469+
470470 rvcElements.forEach(element => {
471471 element.style.display = isV2 ? 'block' : 'none';
472472 });
473-
473+
474474 // Update and disable/enable character voice dropdown
475475 const rvcCharacterVoiceSelect = document.getElementById('rvc_character_voice');
476476 if (rvcCharacterVoiceSelect) {
477477 rvcCharacterVoiceSelect.disabled = !isV2;
478478 if (this.rvcVoices) {
479479 rvcCharacterVoiceSelect.innerHTML = '';
480480 for (let voice of this.rvcVoices) {
481481 const option = document.createElement('option');
482482 option.value = voice.voice_id;
483483 option.textContent = voice.name;
484484 if (voice.voice_id === this.settings.rvc_character_voice) {
485485 option.selected = true;
486486 }
487487 rvcCharacterVoiceSelect.appendChild(option);
488488 }
489489 }
490490 }
491-
491+
492492 // Update and disable/enable narrator voice dropdown
493493 const rvcNarratorVoiceSelect = document.getElementById('rvc_narrator_voice');
494494 if (rvcNarratorVoiceSelect) {
495495 rvcNarratorVoiceSelect.disabled = !isV2;
496496 if (this.rvcVoices) {
497497 rvcNarratorVoiceSelect.innerHTML = '';
498498 for (let voice of this.rvcVoices) {
499499 const option = document.createElement('option');
500500 option.value = voice.voice_id;
501501 option.textContent = voice.name;
502502 if (voice.voice_id === this.settings.rvc_narrator_voice) {
503503 option.selected = true;
504504 }
505505 rvcNarratorVoiceSelect.appendChild(option);
506506 }
507507 }
508508 }
509-
509+
510510 // Update pitch inputs
511511 const characterPitch = document.getElementById('rvc_character_pitch');
512512 if (characterPitch) {
513513 characterPitch.disabled = !isV2;
514514 }
515-
515+
516516 const narratorPitch = document.getElementById('rvc_narrator_pitch');
517517 if (narratorPitch) {
518518 narratorPitch.disabled = !isV2;
519519 }
520520 }
521-
521+
522522 //###################################################//
523523 // Get Current AT Server Config & Update ST (Models) //
524524 //###################################################//
525-
525+
526526 updateModelDropdown() {
527527 const modelSelect = document.getElementById('switch_model');
528528 if (modelSelect) {
529529 modelSelect.innerHTML = ''; // Clear existing options
530530 this.settings.modelsAvailable.forEach(model => {
531531 const option = document.createElement('option');
532532 option.value = model.name;
533533 option.textContent = model.name; // Use model name directly
534534 option.selected = model.name === this.settings.currentModel;
535535 modelSelect.appendChild(option);
536536 });
537537 }
538538 }
539-
539+
540540 //#######################################################//
541541 // Get Current AT Server Config & Update ST (DS and LVR) //
542542 //#######################################################//
543-
543+
544544 updateCheckboxes() {
545545 const deepspeedCheckbox = document.getElementById('deepspeed');
546546 const lowVramCheckbox = document.getElementById('low_vram');
547-
547+
548548 // Handle DeepSpeed checkbox
549549 if (deepspeedCheckbox) {
550550 if (this.settings.deepspeed_capable) {
551551 // If TTS engine is capable of using DeepSpeed
552552 deepspeedCheckbox.disabled = !this.settings.deepspeed_available;
553553 this.settings.deepspeed_enabled = this.settings.deepspeed_available && this.settings.deepspeed_enabled;
554554 } else {
555555 // If TTS engine is NOT capable of using DeepSpeed
556556 deepspeedCheckbox.disabled = true;
557557 this.settings.deepspeed_enabled = false;
558558 }
559559 deepspeedCheckbox.checked = this.settings.deepspeed_enabled;
560560 }
561-
561+
562562 // Handle Low VRAM checkbox
563563 if (lowVramCheckbox) {
564564 if (this.settings.lowvram_capable) {
565565 // If TTS engine is capable of low VRAM
566566 lowVramCheckbox.disabled = false;
567567 } else {
568568 // If TTS engine is NOT capable of low VRAM
569569 lowVramCheckbox.disabled = true;
570570 this.settings.lowvram_enabled = false;
571571 }
572572 lowVramCheckbox.checked = this.settings.lowvram_enabled;
573573 }
574574 }
575-
575+
576-
576+
577577 //###############################################################//
578578 // Get Current AT Server Config & Update ST (AT Narrator Voices) //
579579 //###############################################################//
580-
580+
581581 updateNarratorVoicesDropdown() {
582582 const narratorVoiceSelect = document.getElementById('narrator_voice');
583583 if (narratorVoiceSelect && this.voices) {
584584 // Clear existing options
585585 narratorVoiceSelect.innerHTML = '';
586586 // Add new options
587587 for (let voice of this.voices) {
588588 const option = document.createElement('option');
589589 option.value = voice.voice_id;
590590 option.textContent = voice.name;
591591 narratorVoiceSelect.appendChild(option);
592592 }
593593 }
594594 }
595-
595+
596596 //######################################################//
597597 // Get Current AT Server Config & Update ST (Languages) //
598598 //######################################################//
599-
599+
600600 updateLanguageDropdown() {
601601 const languageSelect = document.getElementById('language_options');
602602 if (languageSelect) {
603603 // Ensure default language is set
604604 this.settings.language = this.settings.language || 'en';
605-
605+
606606 languageSelect.innerHTML = '';
607607 for (let language in this.languageLabels) {
608608 const option = document.createElement('option');
609609 option.value = this.languageLabels[language];
610610 option.textContent = language;
611611 if (this.languageLabels[language] === this.settings.language) {
612612 option.selected = true;
613613 }
614614 languageSelect.appendChild(option);
615615 }
616616 }
617617 }
618-
618+
619619 //########################################//
620620 // Start AT TTS extenstion page listeners //
621621 //########################################//
622-
622+
623623 setupEventListeners() {
624624 // Define the event handler function
625625 const onModelSelectChange = async (event) => {
626626 console.log('Model select change event triggered');
627627 const selectedModel = event.target.value;
628628 console.log(`Selected model: ${selectedModel}`);
629629 updateStatus('Processing');
630630 try {
631631 const response = await fetch(`${this.settings.provider_endpoint}/api/reload?tts_method=${encodeURIComponent(selectedModel)}`, {
632632 method: 'POST',
633633 });
634634 if (!response.ok) {
635635 throw new Error(`HTTP Error: ${response.status}`);
636636 }
637637 const data = await response.json();
638638 console.log('POST response data:', data);
639639 updateStatus('Ready');
640640 } catch (error) {
641641 console.error('POST request error:', error);
642642 updateStatus('Error');
643643 }
644644 };
645-
645+
646646 // Switch Model Listener with debounce
647647 const modelSelect = document.getElementById('switch_model');
648648 if (modelSelect) {
649649 const debouncedModelSelectChange = debounce(onModelSelectChange, 1400);
650650 modelSelect.addEventListener('change', debouncedModelSelectChange);
651651 }
652-
652+
653653 // AllTalk Server version change listener
654654 const serverVersionSelect = document.getElementById('server_version');
655655 if (serverVersionSelect) {
656656 serverVersionSelect.addEventListener('change', async (event) => {
657657 this.settings.server_version = event.target.value;
658658 if (event.target.value === 'v2') {
659659 await this.fetchRvcVoiceObjects();
660660 }
661661 this.updateRvcVoiceDropdowns();
662662 this.onSettingsChange();
663663 });
664664 }
665-
665+
666666 // RVC Voice and Pitch listeners
667667 const rvcCharacterVoiceSelect = document.getElementById('rvc_character_voice');
668668 if (rvcCharacterVoiceSelect) {
669669 rvcCharacterVoiceSelect.addEventListener('change', (event) => {
670670 this.settings.rvccharacter_voice_gen = event.target.value;
671671 this.onSettingsChange();
672672 });
673673 }
674-
674+
675675 const rvcNarratorVoiceSelect = document.getElementById('rvc_narrator_voice');
676676 if (rvcNarratorVoiceSelect) {
677677 rvcNarratorVoiceSelect.addEventListener('change', (event) => {
678678 this.settings.rvcnarrator_voice_gen = event.target.value;
679679 this.onSettingsChange();
680680 });
681681 }
682-
682+
683683 const rvcCharacterPitchSelect = document.getElementById('rvc_character_pitch');
684684 if (rvcCharacterPitchSelect) {
685685 rvcCharacterPitchSelect.addEventListener('change', (event) => {
686686 this.settings.rvc_character_pitch = event.target.value;
687687 this.onSettingsChange();
688688 });
689689 }
690-
690+
691691 const rvcNarratorPitchSelect = document.getElementById('rvc_narrator_pitch');
692692 if (rvcNarratorPitchSelect) {
693693 rvcNarratorPitchSelect.addEventListener('change', (event) => {
694694 this.settings.rvc_narrator_pitch = event.target.value;
695695 this.onSettingsChange();
696696 });
697697 }
698-
698+
699699 // DeepSpeed Listener
700700 const deepspeedCheckbox = document.getElementById('deepspeed');
701701 if (deepspeedCheckbox) {
702702 const handleDeepSpeedChange = async (event) => {
703703 const deepSpeedValue = event.target.checked ? 'True' : 'False';
704704 updateStatus('Processing');
705705 try {
706706 const response = await fetch(`${this.settings.provider_endpoint}/api/deepspeed?new_deepspeed_value=${deepSpeedValue}`, {
707707 method: 'POST',
708708 });
709709 if (!response.ok) {
710710 throw new Error(`HTTP Error: ${response.status}`);
711711 }
712712 const data = await response.json();
713713 console.log('POST response data:', data);
714714 updateStatus('Ready');
715715 } catch (error) {
716716 console.error('POST request error:', error);
717717 updateStatus('Error');
718718 }
719719 };
720-
720+
721721 const debouncedHandleDeepSpeedChange = debounce(handleDeepSpeedChange, 300);
722722 deepspeedCheckbox.addEventListener('change', debouncedHandleDeepSpeedChange);
723723 }
724-
724+
725725 // Low VRAM Listener
726726 const lowVramCheckbox = document.getElementById('low_vram');
727727 if (lowVramCheckbox) {
728728 const handleLowVramChange = async (event) => {
729729 const lowVramValue = event.target.checked ? 'True' : 'False';
730730 updateStatus('Processing');
731731 try {
732732 const response = await fetch(`${this.settings.provider_endpoint}/api/lowvramsetting?new_low_vram_value=${lowVramValue}`, {
733733 method: 'POST',
734734 });
735735 if (!response.ok) {
736736 throw new Error(`HTTP Error: ${response.status}`);
737737 }
738738 const data = await response.json();
739739 console.log('POST response data:', data);
740740 updateStatus('Ready');
741741 } catch (error) {
742742 console.error('POST request error:', error);
743743 updateStatus('Error');
744744 }
745745 };
746-
746+
747747 const debouncedHandleLowVramChange = debounce(handleLowVramChange, 300);
748748 lowVramCheckbox.addEventListener('change', debouncedHandleLowVramChange);
749749 }
750-
750+
751751 // Other listeners without debounce since they don't need it
752752 const narratorVoiceSelect = document.getElementById('narrator_voice');
753753 if (narratorVoiceSelect) {
754754 narratorVoiceSelect.addEventListener('change', (event) => {
755755 this.settings.narrator_voice_gen = `${event.target.value}`;
756756 this.onSettingsChange();
757757 });
758758 }
759-
759+
760760 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
761761 if (textNotInsideSelect) {
762762 textNotInsideSelect.addEventListener('change', (event) => {
763763 this.settings.text_not_inside = event.target.value;
764764 this.onSettingsChange();
765765 });
766766 }
767-
767+
768768 // AT Narrator Dropdown Listener
769769 const atNarratorSelect = document.getElementById('at_narrator_enabled');
770770 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks');
771771 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted');
772772 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues');
773-
773+
774774 if (atNarratorSelect && textNotInsideSelect && narratorVoiceSelect) {
775775 atNarratorSelect.addEventListener('change', (event) => {
776776 const narratorOption = event.target.value;
777777 this.settings.narrator_enabled = narratorOption;
778-
778+
779779 const isNarratorDisabled = narratorOption === 'false';
780780 textNotInsideSelect.disabled = isNarratorDisabled;
781781 narratorVoiceSelect.disabled = isNarratorDisabled;
782-
782+
783783 if (narratorOption === 'true') {
784784 ttsPassAsterisksCheckbox.checked = false;
785785 $('#tts_pass_asterisks').click();
786786 $('#tts_pass_asterisks').trigger('change');
787787 ttsNarrateQuotedCheckbox.checked = true;
788788 ttsNarrateDialoguesCheckbox.checked = true;
789789 $('#tts_narrate_quoted').click();
790790 $('#tts_narrate_quoted').trigger('change');
791791 $('#tts_narrate_dialogues').click();
792792 $('#tts_narrate_dialogues').trigger('change');
793793 } else if (narratorOption === 'silent') {
794794 ttsPassAsterisksCheckbox.checked = false;
795795 $('#tts_pass_asterisks').click();
796796 $('#tts_pass_asterisks').trigger('change');
797797 } else {
798798 ttsPassAsterisksCheckbox.checked = true;
799799 $('#tts_pass_asterisks').click();
800800 $('#tts_pass_asterisks').trigger('change');
801801 }
802-
802+
803803 this.onSettingsChange();
804804 });
805805 }
806-
806+
807807 // Event Listener for AT Generation Method Dropdown
808808 const atGenerationMethodSelect = document.getElementById('at_generation_method');
809809 if (atGenerationMethodSelect) {
810810 atGenerationMethodSelect.addEventListener('change', (event) => {
811811 const selectedMethod = event.target.value;
812-
812+
813813 if (selectedMethod === 'streaming_enabled') {
814814 // Disable and unselect AT Narrator
815815 atNarratorSelect.disabled = true;
816816 atNarratorSelect.value = 'false';
817817 textNotInsideSelect.disabled = true;
818818 narratorVoiceSelect.disabled = true;
819819 } else if (selectedMethod === 'standard_generation') {
820820 // Enable AT Narrator
821821 atNarratorSelect.disabled = false;
822822 }
823823 this.settings.at_generation_method = selectedMethod;
824824 this.onSettingsChange();
825825 });
826826 }
827-
827+
828828 // Language Dropdown Listener
829829 const languageSelect = document.getElementById('language_options');
830830 if (languageSelect) {
831831 languageSelect.addEventListener('change', (event) => {
832832 this.settings.language = event.target.value;
833833 this.onSettingsChange();
834834 });
835835 }
836-
836+
837837 // AllTalk Endpoint Input Listener
838838 const atServerInput = document.getElementById('at_server');
839839 if (atServerInput) {
840840 atServerInput.addEventListener('input', (event) => {
841841 this.settings.provider_endpoint = event.target.value;
842842 this.onSettingsChange();
843843 });
844844 }
845845 }
846-
846+
847847 //#############################//
848848 // Store ST interface settings //
849849 //#############################//
850-
850+
851851 onSettingsChange() {
852852 // Update settings based on the UI elements
853853 //this.settings.provider_endpoint = $('#at_server').val();
854854 this.settings.language = $('#language_options').val();
855855 //this.settings.voiceMap = $('#voicemap').val();
856856 this.settings.at_generation_method = $('#at_generation_method').val();
857857 this.settings.narrator_enabled = $('#at_narrator_enabled').val();
858858 this.settings.at_narrator_text_not_inside = $('#at_narrator_text_not_inside').val();
859859 this.settings.rvc_character_voice = $('#rvc_character_voice').val();
860860 this.settings.rvc_narrator_voice = $('#rvc_narrator_voice').val();
861861 this.settings.rvc_character_pitch = $('#rvc_character_pitch').val();
862862 this.settings.rvc_narrator_pitch = $('#rvc_narrator_pitch').val();
863863 this.settings.narrator_voice_gen = $('#narrator_voice').val();
864864 // Save the updated settings
865865 saveTtsProviderSettings();
866866 }
867-
867+
868868 //#########################//
869869 // ST Handle Reload button //
870870 //#########################//
871-
871+
872872 async onRefreshClick() {
873873 try {
874874 updateStatus('Processing'); // Set status to Processing while refreshing
875875 await this.checkReady(); // Check if the TTS provider is ready
876876 await this.loadSettings(this.settings); // Reload the settings
877877 await this.checkReady(); // Check if the TTS provider is ready
878878 updateStatus(this.ready ? 'Ready' : 'Offline'); // Update the status based on readiness
879879 } catch (error) {
880880 console.error('Error during refresh:', error);
881881 updateStatus('Error'); // Set status to Error in case of failure
882882 }
883883 }
884-
884+
885885 //##################//
886886 // Preview AT Voice //
887887 //##################//
888-
888+
889889 async previewTtsVoice(voiceName) {
890890 try {
891891 // Prepare data for POST request
892892 const postData = new URLSearchParams();
893893 postData.append('voice', `${voiceName}`);
894-
894+
895895 // Add RVC parameters for V2 if applicable
896896 if (this.settings.server_version === 'v2' && this.settings.rvc_character_voice !== 'Disabled') {
897897 postData.append('rvccharacter_voice_gen', this.settings.rvc_character_voice);
898898 postData.append('rvccharacter_pitch', this.settings.rvc_character_pitch || '0');
899899 }
900-
900+
901901 // Making the POST request
902902 const response = await fetch(`${this.settings.provider_endpoint}/api/previewvoice/`, {
903903 method: 'POST',
904904 headers: {
905905 'Content-Type': 'application/x-www-form-urlencoded',
906906 },
907907 body: postData,
908908 });
909-
909+
910910 if (!response.ok) {
911911 const errorText = await response.text();
912912 console.error('previewTtsVoice Error Response Text:', errorText);
913913 throw new Error(`HTTP ${response.status}: ${errorText}`);
914914 }
915-
915+
916916 const data = await response.json();
917917 if (data.output_file_url) {
918918 // Handle V1/V2 URL differences
919919 const fullUrl = this.settings.server_version === 'v1'
920920 ? data.output_file_url
921921 : `${this.settings.provider_endpoint}${data.output_file_url}`;
922-
922+
923923 const audioElement = new Audio(fullUrl);
924924 audioElement.play().catch(e => console.error('Error playing audio:', e));
925925 } else {
926926 console.warn('previewTtsVoice No output file URL received in the response');
927927 throw new Error('No output file URL received in the response');
928928 }
929929 } catch (error) {
930930 console.error('previewTtsVoice Exception caught during preview generation:', error);
931931 throw error;
932932 }
933933 }
934-
934+
935935 //#####################//
936936 // Populate ST voices //
937937 //#####################//
938-
938+
939939 async getVoice(voiceName, generatePreview = false) {
940940 // Ensure this.voices is populated
941941 if (this.voices.length === 0) {
942942 // Fetch voice objects logic
943943 }
944944 // Find the object where the name matches voiceName
945945 const match = this.voices.find(voice => voice.name === voiceName);
946946 if (!match) {
947947 // Error handling
948948 }
949949 // Generate preview URL only if requested
950950 if (!match.preview_url && generatePreview) {
951951 // Generate preview logic
952952 }
953953 return match; // Return the found voice object
954954 }
955-
955+
956956 //##########################################//
957957 // Generate TTS Streaming or call Standard //
958958 //##########################################//
959-
959+
960960 async generateTts(inputText, voiceId) {
961961 try {
962962 if (this.settings.at_generation_method === 'streaming_enabled') {
963963 // Construct the streaming URL
964964 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`;
965965 console.log('Streaming URL:', streamingUrl);
966-
966+
967967 // Return the streaming URL directly
968968 return streamingUrl;
969969 } else {
970970 // For standard method
971971 const outputUrl = await this.fetchTtsGeneration(inputText, voiceId);
972972 const audioResponse = await fetch(outputUrl);
973973 if (!audioResponse.ok) {
974974 throw new Error(`HTTP ${audioResponse.status}: Failed to fetch audio data`);
975975 }
976976 return audioResponse; // Return the fetch response directly
977977 }
978978 } catch (error) {
979979 console.error('Error in generateTts:', error);
980980 throw error;
981981 }
982982 }
983-
983+
984-
984+
985985 //####################//
986986 // Generate Standard //
987987 //####################//
988-
988+
989989 async fetchTtsGeneration(inputText, voiceId) {
990990 const requestBody = new URLSearchParams({
991991 'text_input': inputText,
992992 'text_filtering': 'standard',
993993 'character_voice_gen': voiceId,
994994 'narrator_enabled': this.settings.narrator_enabled,
995995 'narrator_voice_gen': this.settings.narrator_voice_gen,
996996 'text_not_inside': this.settings.at_narrator_text_not_inside,
997997 'language': this.settings.language,
998998 'output_file_name': 'st_output',
999999 'output_file_timestamp': 'true',
10001000 'autoplay': 'false',
10011001 'autoplay_volume': '0.8',
10021002 });
1003-
1003+
10041004 // Add RVC parameters only for V2
10051005 if (this.settings.server_version === 'v2') {
10061006 if (this.settings.rvc_character_voice !== 'Disabled') {
10071007 requestBody.append('rvccharacter_voice_gen', this.settings.rvc_character_voice);
10081008 requestBody.append('rvccharacter_pitch', this.settings.rvc_character_pitch || '0');
10091009 }
10101010 if (this.settings.rvc_narrator_voice !== 'Disabled') {
10111011 requestBody.append('rvcnarrator_voice_gen', this.settings.rvc_narrator_voice);
10121012 requestBody.append('rvcnarrator_pitch', this.settings.rvc_narrator_pitch || '0');
10131013 }
10141014 }
1015-
1015+
10161016 try {
10171017 const response = await doExtrasFetch(
10181018 `${this.settings.provider_endpoint}/api/tts-generate`,
10191019 {
10201020 method: 'POST',
10211021 headers: {
10221022 'Content-Type': 'application/x-www-form-urlencoded',
10231023 'Cache-Control': 'no-cache',
10241024 },
10251025 body: requestBody,
10261026 },
10271027 );
1028-
1028+
10291029 if (!response.ok) {
10301030 const errorText = await response.text();
10311031 console.error('fetchTtsGeneration Error Response Text:', errorText);
10321032 throw new Error(`HTTP ${response.status}: ${errorText}`);
10331033 }
10341034 const data = await response.json();
1035-
1035+
10361036 // Handle V1/V2 URL differences
10371037 const outputUrl = this.settings.server_version === 'v1'
10381038 ? data.output_file_url // V1 returns full URL
10391039 : `${this.settings.provider_endpoint}${data.output_file_url}`; // V2 returns relative path
1040-
1040+
10411041 return outputUrl;
10421042 } catch (error) {
10431043 console.error('[fetchTtsGeneration] Exception caught:', error);
10441044 throw error;
10451045 }
10461046 }
10471047}
1048-
1048+
10491049//#########################//
10501050// Update Status Messages //
10511051//#########################//
1052-
1052+
10531053function updateStatus(message) {
10541054 const statusElement = document.getElementById('status_info');
10551055 if (statusElement) {
10561056 statusElement.textContent = message;
10571057 switch (message) {
10581058 case 'Offline':
10591059 statusElement.style.color = 'red';
10601060 break;
10611061 case 'Ready':
10621062 statusElement.style.color = 'lightgreen';
10631063 break;
10641064 case 'Processing':
10651065 statusElement.style.color = 'blue';
10661066 break;
10671067 case 'Error':
10681068 statusElement.style.color = 'red';
10691069 break;
10701070 }
10711071 }
10721072}