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 @@
11import { doExtrasFetch } from '../../extensions.js';
2+import { debounce } from '../../utils.js';
23import { saveTtsProviderSettings } from './index.js';
34
45export { AllTalkTtsProvider };
@@ -13,12 +14,17 @@ class AllTalkTtsProvider {
1314 // Initialize with default settings if they are not already set
1415 this.settings = {
1516 provider_endpoint: this.settings.provider_endpoint || 'http://localhost:7851',
17+ server_version: this.settings.server_version || 'v2',
1618 language: this.settings.language || 'en',
1719 voiceMap: this.settings.voiceMap || {},
1820 at_generation_method: this.settings.at_generation_method || 'standard_generation',
1921 narrator_enabled: this.settings.narrator_enabled || 'false',
2022 at_narrator_text_not_inside: this.settings.at_narrator_text_not_inside || 'narrator',
2123 narrator_voice_gen: this.settings.narrator_voice_gen || 'female_01.wavPlease 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',
2228 finetuned_model: this.settings.finetuned_model || 'false',
2329 };
2430 // Separate property for dynamically updated settings from the server
@@ -26,9 +32,11 @@ class AllTalkTtsProvider {
2632 modelsAvailable: [],
2733 currentModel: '',
2834 deepspeed_available: false,
2935 deepSpeedEnableddeepspeed_enabled: false,
3036 lowVramEnabledlowvram_capable: false,
37+ lowvram_enabled: false,
3138 };
39+ this.rvcVoices = []; // Initialize rvcVoices as an empty array
3240 }
3341 ready = false;
3442 voices = [];
@@ -56,113 +64,162 @@ class AllTalkTtsProvider {
5664 };
5765
5866 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.
60-
68+ // 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
62-
70+ 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>
6878 </select>
6979 </div>
7080 </div>`;
7181
7282 html += `<div class="'at-settings-row"'>
73-
83+ <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>
7787 <option value="true"'silent'>Enabled (Silenced)</option>
7888 <option value="'false"'>Disabled</option>
7989 </select>
8090 </div>
8191
8292 <div class="'at-settings-option"'>
8393 <label for="'at_narrator_text_not_inside"'>Text Not Inside * or " is</label>
8494 <select id="'at_narrator_text_not_inside"'>
8595 <option value="narrator"'character'>NarratorCharacter</option>
8696 <option value="character"'narrator'>CharacterNarrator</option>
97+ <option value='silent'>Silent</option>
8798 </select>
8899 </div>
89-
90100 </div>`;
91101
92102 html += `<div class="'at-settings-row"'>
93103 <div class="'at-settings-option"'>
94104 <label for="'narrator_voice"'>Narrator Voice</label>
95105 <select id="'narrator_voice"'>`;
96106 if (this.voices) {
97107 for (let voice of this.voices) {
98108 html += `<option value="'${voice.voice_id}"'>${voice.name}</option>`;
99109 }
100110 }
101111 html += `</select>
102112 </div>
103113 <div class="'at-settings-option"'>
104114 <label for="'language_options"'>Language</label>
105115 <select id="'language_options"'>`;
106116 for (let language in this.languageLabels) {
107117 html += `<option value="'${this.languageLabels[language]}"' ${this.languageLabels[language] === this.settings?.language ? 'selected="selected"' : ''}>${language}</option>`;
108118 }
109119 html += `</select>
110120 </div>
111121 </div>`;
112122
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>`;
113145
114146 html += `<div class="'at-model-endpointsettings-row"'>
115147 <div class="'at-modelsettings-option"'>
116148 <label for="switch_model"'rvc_character_pitch'>SwitchRVC ModelCharacter Pitch</label>
117149 <select id="switch_model"'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>
122155 </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>
123164 </div>
165+ </div>`;
124166
125167 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>
126174
127175 <div class="'at-endpoint-option"'>
128176 <label for="'at_server"'>AllTalk Endpoint:</label>
129177 <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>
131178 </div>
132179 </div>`;
133180
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>`;
134190
135191 html += `<div class="'at-model-endpoint-row"'>
136192 <div class="'at-settings-option"'>
137193 <label for="'low_vram"'>Low VRAM</label>
138194 <input id="'low_vram"' type="'checkbox"'/>
139195 </div>
140196 <div class="'at-settings-option"'>
141197 <label for="'deepspeed"'>DeepSpeed</label>
142198 <input id="'deepspeed"' type="'checkbox"'/>
143199 </div>
144200 <div class="'at-settings-option status-option"'>
145201 <span>Status: <span id="'status_info"'>Ready</span></span>
146202 </div>
147203 <div class="'at-settings-option empty-option"'>
148204 <!-- This div remains empty for spacing -->
149205 </div>
150206</div>`;
151207
152-
208+ html += `<div class='at-website-row'>
153209 html += `<div class="'at-website-row"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>
156211 </div>
157212
158213 <div class="'at-website-option"'>
159214 <span>AllTalk <a target="'_blank"' href="'https://github.com/erew123/alltalk_tts/"'>Website</a>.</span>
160215 </div>
161216</div>`;
162217
163218 html += `<div class="'at-website-row"'>
164219<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>
166223</div>
167224</div>`;
168225
@@ -193,25 +250,25 @@ class AllTalkTtsProvider {
193250 // Update UI elements to reflect the loaded settings
194251 $('#at_server').val(this.settings.provider_endpoint);
195252 $('#language_options').val(this.settings.language);
196- //$('#voicemap').val(this.settings.voiceMap);
197253 $('#at_generation_method').val(this.settings.at_generation_method);
198254 $('#at_narrator_enabled').val(this.settings.narrator_enabled);
199255 $('#at_narrator_text_not_inside').val(this.settings.at_narrator_text_not_inside);
200256 $('#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);
201261
202262 console.debug('AllTalkTTS: Settings loaded');
203- await this.initEndpoint();
204- }
205-
206- async initEndpoint() {
207263 try {
208264 // Check if TTS provider is ready
209- this.setupEventListeners();
210- this.updateLanguageDropdown();
211265 await this.checkReady();
212266 await this.updateSettingsFromServer(); // Fetch dynamic settings from the TTS server
213267 await this.fetchTtsVoiceObjects(); // Fetch voices only if service is ready
268+ await this.fetchRvcVoiceObjects(); // Fetch RVC voices
214269 this.updateNarratorVoicesDropdown();
270+ this.updateLanguageDropdown();
271+ this.setupEventListeners();
215272 this.applySettingsToHTML();
216273 updateStatus('Ready');
217274 } catch (error) {
@@ -220,8 +277,8 @@ class AllTalkTtsProvider {
220277 }
221278 }
222279
280+
223281 applySettingsToHTML() {
224- // Apply loaded settings or use defaults
225282 const narratorVoiceSelect = document.getElementById('narrator_voice');
226283 const atNarratorSelect = document.getElementById('at_narrator_enabled');
227284 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
@@ -229,30 +286,26 @@ class AllTalkTtsProvider {
229286 this.settings.narrator_voice = this.settings.narrator_voice_gen;
230287 // Apply settings to Narrator Voice dropdown
231288 if (narratorVoiceSelect && this.settings.narrator_voice) {
232289 narratorVoiceSelect.value = this.settings.narrator_voice.replace('.wav', ''); // Remove the parentheses
233290 }
234291 // Apply settings to AT Narrator Enabled dropdown
235292 if (atNarratorSelect) {
236- // Sync the state with the checkbox in index.js
293+ const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks');
237294 const ttsPassAsterisksCheckboxttsNarrateQuotedCheckbox = document.getElementById('tts_pass_asteriskstts_narrate_quoted'); // Access the checkbox from index.js
238295 const ttsNarrateQuotedCheckboxttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_quotedtts_narrate_dialogues'); // Access the checkbox from index.js
239- const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); // Access the checkbox from index.js
240- // Sync the state with the checkbox in index.js
241296 if (this.settings.narrator_enabled) {
242297 ttsPassAsterisksCheckbox.checked = false;
243298 $('#tts_pass_asterisks').click(); // Simulate a click event
244299 $('#tts_pass_asterisks').trigger('change');
245300 }
246301 if (!this.settings.narrator_enabled) {
247302 ttsPassAsterisksCheckbox.checked = true;
248303 $('#tts_pass_asterisks').click(); // Simulate a click event
249304 $('#tts_pass_asterisks').trigger('change');
250305 }
251- // Uncheck and set tts_narrate_quoted to false if narrator is enabled
306+ if (this.settings.narrator_enabled) {
252- if (this.settings.narrator_enabledd) {
253307 ttsNarrateQuotedCheckbox.checked = true;
254308 ttsNarrateDialoguesCheckbox.checked = true;
255- // Trigger click events instead of change events
256309 $('#tts_narrate_quoted').click();
257310 $('#tts_narrate_quoted').trigger('change');
258311 $('#tts_narrate_dialogues').click();
@@ -261,42 +314,30 @@ class AllTalkTtsProvider {
261314 atNarratorSelect.value = this.settings.narrator_enabled.toString();
262315 this.settings.narrator_enabled = this.settings.narrator_enabled.toString();
263316 }
264- // Apply settings to the Language dropdown
265317 const languageSelect = document.getElementById('language_options');
266318 if (languageSelect && this.settings.language) {
267319 languageSelect.value = this.settings.language;
268320 }
269- // Apply settings to Text Not Inside dropdown
270321 if (textNotInsideSelect && this.settings.text_not_inside) {
271322 textNotInsideSelect.value = this.settings.text_not_inside;
272323 this.settings.at_narrator_text_not_inside = this.settings.text_not_inside;
273324 }
274- // Apply settings to Generation Method dropdown
275325 if (generationMethodSelect && this.settings.at_generation_method) {
276326 generationMethodSelect.value = this.settings.at_generation_method;
277327 }
278- // Additional logic to disable/enable dropdowns based on the selected generation method
279328 const isStreamingEnabled = this.settings.at_generation_method === 'streaming_enabled';
280329 if (isStreamingEnabled) {
281- // Disable certain dropdowns when streaming is enabled
282330 if (atNarratorSelect) atNarratorSelect.disabled = true;
283331 if (textNotInsideSelect) textNotInsideSelect.disabled = true;
284332 if (narratorVoiceSelect) narratorVoiceSelect.disabled = true;
285333 } else {
286- // Enable dropdowns for standard generation
287334 if (atNarratorSelect) atNarratorSelect.disabled = false;
288335 if (textNotInsideSelect) textNotInsideSelect.disabled = !this.settings.narrator_enabled;
289336 if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
290337 }
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- }
298338 }
299339
340+
300341 //##############################//
301342 // Check AT Server is Available //
302343 //##############################//
@@ -320,7 +361,6 @@ class AllTalkTtsProvider {
320361 } catch (error) {
321362 console.error('Error checking TTS service readiness:', error);
322363 this.ready = false; // Ensure ready flag is set to false in case of error
323- throw error; // Rethrow the error for further handling
324364 }
325365 }
326366
@@ -336,10 +376,9 @@ class AllTalkTtsProvider {
336376 }
337377 const data = await response.json();
338378 const voices = data.voices.map(filename => {
339- const voiceName = filename.replace('.wav', '');
340379 return {
341380 name: voiceNamefilename,
342381 voice_id: voiceNamefilename,
343382 preview_url: null, // Preview URL will be dynamically generated
344383 lang: 'en', // Default language
345384 };
@@ -348,33 +387,138 @@ class AllTalkTtsProvider {
348387 return voices; // Also return this list
349388 }
350389
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+
351432 //##########################################//
352433 // Get Current AT Server Config & Update ST //
353434 //##########################################//
354435
355436 async updateSettingsFromServer() {
356437 try {
357- // Fetch current settings
358438 const response = await fetch(`${this.settings.provider_endpoint}/api/currentsettings`);
359439 if (!response.ok) {
360440 throw new Error(`Failed to fetch current settings: ${response.statusText}`);
361441 }
362442 const currentSettings = await response.json();
363- // Update internal settings
443+ 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;
364447 this.settings.modelsAvailable = currentSettings.models_available;
365448 this.settings.currentModel = currentSettings.current_model_loaded;
449+ this.settings.deepspeed_capable = currentSettings.deepspeed_capable;
366450 this.settings.deepspeed_available = currentSettings.deepspeed_available;
367451 this.settings.deepSpeedEnableddeepspeed_enabled = currentSettings.deepspeed_statusdeepspeed_enabled;
368452 this.settings.lowVramEnabledlowvram_capable = currentSettings.low_vram_statuslowvram_capable;
369453 this.settings.finetuned_modellowvram_enabled = currentSettings.finetuned_modellowvram_enabled;
370- // Update HTML elements
454+
455+ await this.fetchRvcVoiceObjects(); // Fetch RVC voices
456+
371457 this.updateModelDropdown();
372458 this.updateCheckboxes();
459+ this.updateRvcVoiceDropdowns(); // Update the RVC voice dropdowns
373460 } catch (error) {
374461 console.error(`Error updating settings from server: ${error}`);
375462 }
376463 }
377464
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+
378522 //###################################################//
379523 // Get Current AT Server Config & Update ST (Models) //
380524 //###################################################//
@@ -385,9 +529,9 @@ class AllTalkTtsProvider {
385529 modelSelect.innerHTML = ''; // Clear existing options
386530 this.settings.modelsAvailable.forEach(model => {
387531 const option = document.createElement('option');
388532 option.value = model.model_namename;
389533 option.textContent = model.model_namename; // Use model_name instead ofmodel name directly
390534 option.selected = model.model_namename === this.settings.currentModel;
391535 modelSelect.appendChild(option);
392536 });
393537 }
@@ -400,13 +544,36 @@ class AllTalkTtsProvider {
400544 updateCheckboxes() {
401545 const deepspeedCheckbox = document.getElementById('deepspeed');
402546 const lowVramCheckbox = document.getElementById('low_vram');
403- if (lowVramCheckbox) lowVramCheckbox.checked = this.settings.lowVramEnabled;
547+
548+ // Handle DeepSpeed checkbox
404549 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 available
551+ // 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;
407573 }
408574 }
409575
576+
410577 //###############################################################//
411578 // Get Current AT Server Config & Update ST (AT Narrator Voices) //
412579 //###############################################################//
@@ -433,8 +600,8 @@ class AllTalkTtsProvider {
433600 updateLanguageDropdown() {
434601 const languageSelect = document.getElementById('language_options');
435602 if (languageSelect) {
436603 // Ensure default language is set (??? whatever that means)
437604 // this.settings.language = this.settings.language || 'en';
438605
439606 languageSelect.innerHTML = '';
440607 for (let language in this.languageLabels) {
@@ -454,16 +621,11 @@ class AllTalkTtsProvider {
454621 //########################################//
455622
456623 setupEventListeners() {
457-
458- let debounceTimeout;
459- const debounceDelay = 500; // Milliseconds
460-
461624 // Define the event handler function
462625 const onModelSelectChange = async (event) => {
463626 console.log('Model select change event triggered'); // Debugging statement
464627 const selectedModel = event.target.value;
465628 console.log(`Selected model: ${selectedModel}`); // Debugging statement
466- // Set status to Processing
467629 updateStatus('Processing');
468630 try {
469631 const response = await fetch(`${this.settings.provider_endpoint}/api/reload?tts_method=${encodeURIComponent(selectedModel)}`, {
@@ -473,39 +635,72 @@ class AllTalkTtsProvider {
473635 throw new Error(`HTTP Error: ${response.status}`);
474636 }
475637 const data = await response.json();
476638 console.log('POST response data:', data); // Debugging statement
477- // Set status to Ready if successful
478639 updateStatus('Ready');
479640 } catch (error) {
480641 console.error('POST request error:', error); // Debugging statement
481- // Set status to Error in case of failure
482642 updateStatus('Error');
483643 }
484-
485- // Handle response or error
486- };
487-
488- const debouncedModelSelectChange = (event) => {
489- clearTimeout(debounceTimeout);
490- debounceTimeout = setTimeout(() => {
491- onModelSelectChange(event);
492- }, debounceDelay);
493644 };
494645
495646 // Switch Model Listener with debounce
496647 const modelSelect = document.getElementById('switch_model');
497648 if (modelSelect) {
498- // Remove the event listener if it was previously added
649+ const debouncedModelSelectChange = debounce(onModelSelectChange, 1400);
499- // Add the debounced event listener
650+ 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+ });
501697 }
502698
503699 // DeepSpeed Listener
504700 const deepspeedCheckbox = document.getElementById('deepspeed');
505701 if (deepspeedCheckbox) {
506702 $(deepspeedCheckbox).off('change').on('change',const handleDeepSpeedChange = async (event) => {
507703 const deepSpeedValue = event.target.checked ? 'True' : 'False';
508- // Set status to Processing
509704 updateStatus('Processing');
510705 try {
511706 const response = await fetch(`${this.settings.provider_endpoint}/api/deepspeed?new_deepspeed_value=${deepSpeedValue}`, {
@@ -515,23 +710,23 @@ class AllTalkTtsProvider {
515710 throw new Error(`HTTP Error: ${response.status}`);
516711 }
517712 const data = await response.json();
518713 console.log('POST response data:', data); // Debugging statement
519- // Set status to Ready if successful
520714 updateStatus('Ready');
521715 } catch (error) {
522716 console.error('POST request error:', error); // Debugging statement
523- // Set status to Error in case of failure
524717 updateStatus('Error');
525718 }
526719 });
720+
721+ const debouncedHandleDeepSpeedChange = debounce(handleDeepSpeedChange, 300);
722+ deepspeedCheckbox.addEventListener('change', debouncedHandleDeepSpeedChange);
527723 }
528724
529725 // Low VRAM Listener
530726 const lowVramCheckbox = document.getElementById('low_vram');
531727 if (lowVramCheckbox) {
532728 $(lowVramCheckbox).off('change').on('change',const handleLowVramChange = async (event) => {
533729 const lowVramValue = event.target.checked ? 'True' : 'False';
534- // Set status to Processing
535730 updateStatus('Processing');
536731 try {
537732 const response = await fetch(`${this.settings.provider_endpoint}/api/lowvramsetting?new_low_vram_value=${lowVramValue}`, {
@@ -541,113 +736,112 @@ class AllTalkTtsProvider {
541736 throw new Error(`HTTP Error: ${response.status}`);
542737 }
543738 const data = await response.json();
544739 console.log('POST response data:', data); // Debugging statement
545- // Set status to Ready if successful
546740 updateStatus('Ready');
547741 } catch (error) {
548742 console.error('POST request error:', error); // Debugging statement
549- // Set status to Error in case of failure
550743 updateStatus('Error');
551744 }
552745 });
746+
747+ const debouncedHandleLowVramChange = debounce(handleLowVramChange, 300);
748+ lowVramCheckbox.addEventListener('change', debouncedHandleLowVramChange);
553749 }
554750
555- // Narrator Voice Dropdown Listener
751+ // Other listeners without debounce since they don't need it
556752 const narratorVoiceSelect = document.getElementById('narrator_voice');
557753 if (narratorVoiceSelect) {
558754 $(narratorVoiceSelect).off('change').onaddEventListener('change', (event) => {
559755 this.settings.narrator_voice_gen = `${event.target.value}.wav`;
560756 this.onSettingsChange(); // Save the settings after change
561757 });
562758 }
563759
564760 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
565761 if (textNotInsideSelect) {
566762 $(textNotInsideSelect).off('change').onaddEventListener('change', (event) => {
567763 this.settings.text_not_inside = event.target.value;
568764 this.onSettingsChange(); // Save the settings after change
569765 });
570766 }
571767
572768 // AT Narrator Dropdown Listener
573769 const atNarratorSelect = document.getElementById('at_narrator_enabled');
574770 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks'); // Access the checkbox from index.js
575771 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted'); // Access the checkbox from index.js
576772 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); // Access the checkbox from index.js
577773
578774 if (atNarratorSelect && textNotInsideSelect && narratorVoiceSelect) {
579775 $(atNarratorSelect).off('change').onaddEventListener('change', (event) => {
580776 const isNarratorEnablednarratorOption = event.target.value === 'true';
581777 this.settings.narrator_enabled = isNarratorEnablednarratorOption; // Update the setting here
582- textNotInsideSelect.disabled = !isNarratorEnabled;
778+
583- narratorVoiceSelect.disabled = !isNarratorEnabled;
779+ const isNarratorDisabled = narratorOption === 'false';
584-
780+ textNotInsideSelect.disabled = isNarratorDisabled;
585- // Sync the state with the checkbox in index.js
781+ narratorVoiceSelect.disabled = isNarratorDisabled;
586- if (isNarratorEnabled) {
782+
783+ if (narratorOption === 'true') {
587784 ttsPassAsterisksCheckbox.checked = false;
588785 $('#tts_pass_asterisks').click(); // Simulate a click event
589786 $('#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) {
598787 ttsNarrateQuotedCheckbox.checked = true;
599788 ttsNarrateDialoguesCheckbox.checked = true;
600- // Trigger click events instead of change events
601789 $('#tts_narrate_quoted').click();
602790 $('#tts_narrate_quoted').trigger('change');
603791 $('#tts_narrate_dialogues').click();
604792 $('#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');
605801 }
606- this.onSettingsChange(); // Save the settings after change
802+
803+ this.onSettingsChange();
607804 });
608805 }
609806
610-
611807 // Event Listener for AT Generation Method Dropdown
612808 const atGenerationMethodSelect = document.getElementById('at_generation_method');
613- const atNarratorEnabledSelect = document.getElementById('at_narrator_enabled');
614809 if (atGenerationMethodSelect) {
615810 $(atGenerationMethodSelect).off('change').onaddEventListener('change', (event) => {
616811 const selectedMethod = event.target.value;
617812
618813 if (selectedMethod === 'streaming_enabled') {
619814 // Disable and unselect AT Narrator
620815 atNarratorEnabledSelectatNarratorSelect.disabled = true;
621816 atNarratorEnabledSelectatNarratorSelect.value = 'false';
622817 textNotInsideSelect.disabled = true;
623818 narratorVoiceSelect.disabled = true;
624819 } else if (selectedMethod === 'standard_generation') {
625820 // Enable AT Narrator
626821 atNarratorEnabledSelectatNarratorSelect.disabled = false;
627822 }
628823 this.settings.at_generation_method = selectedMethod; // Update the setting here
629824 this.onSettingsChange(); // Save the settings after change
630825 });
631826 }
632827
633828 // Listener for Language Dropdown Listener
634829 const languageSelect = document.getElementById('language_options');
635830 if (languageSelect) {
636831 $(languageSelect).off('change').onaddEventListener('change', (event) => {
637832 this.settings.language = event.target.value;
638833 this.onSettingsChange(); // Save the settings after change
639834 });
640835 }
641836
642837 // Listener for AllTalk Endpoint Input Listener
643838 const atServerInput = document.getElementById('at_server');
644839 if (atServerInput) {
645840 $(atServerInput).off('input').onaddEventListener('input', (event) => {
646841 this.settings.provider_endpoint = event.target.value;
647842 this.onSettingsChange(); // Save the settings after change
648843 });
649844 }
650-
651845 }
652846
653847 //#############################//
@@ -662,6 +856,10 @@ class AllTalkTtsProvider {
662856 this.settings.at_generation_method = $('#at_generation_method').val();
663857 this.settings.narrator_enabled = $('#at_narrator_enabled').val();
664858 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();
665863 this.settings.narrator_voice_gen = $('#narrator_voice').val();
666864 // Save the updated settings
667865 saveTtsProviderSettings();
@@ -672,8 +870,16 @@ class AllTalkTtsProvider {
672870 //#########################//
673871
674872 async onRefreshClick() {
675- await this.initEndpoint();
873+ try {
676- // Additional actions as needed
874+ 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+ }
677883 }
678884
679885 //##################//
@@ -684,7 +890,14 @@ class AllTalkTtsProvider {
684890 try {
685891 // Prepare data for POST request
686892 const postData = new URLSearchParams();
687893 postData.append('voice', `${voiceName}.wav`);
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+
688901 // Making the POST request
689902 const response = await fetch(`${this.settings.provider_endpoint}/api/previewvoice/`, {
690903 method: 'POST',
@@ -693,24 +906,28 @@ class AllTalkTtsProvider {
693906 },
694907 body: postData,
695908 });
909+
696910 if (!response.ok) {
697911 const errorText = await response.text();
698912 console.error('[previewTtsVoice] Error Response Text:', errorText);
699913 throw new Error(`HTTP ${response.status}: ${errorText}`);
700914 }
701- // Assuming the server returns a URL to the .wav file
915+
702916 const data = await response.json();
703917 if (data.output_file_url) {
704- // Use an audio element to play the .wav file
918+ // 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);
706924 audioElement.play().catch(e => console.error('Error playing audio:', e));
707925 } else {
708926 console.warn('[previewTtsVoice] No output file URL received in the response');
709927 throw new Error('No output file URL received in the response');
710928 }
711-
712929 } catch (error) {
713930 console.error('[previewTtsVoice] Exception caught during preview generation:', error);
714931 throw error;
715932 }
716933 }
@@ -744,7 +961,7 @@ class AllTalkTtsProvider {
744961 try {
745962 if (this.settings.at_generation_method === 'streaming_enabled') {
746963 // Construct the streaming URL
747964 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`;
748965 console.log('Streaming URL:', streamingUrl);
749966
750967 // Return the streaming URL directly
@@ -770,20 +987,31 @@ class AllTalkTtsProvider {
770987 //####################//
771988
772989 async fetchTtsGeneration(inputText, voiceId) {
773- // Prepare the request payload
774990 const requestBody = new URLSearchParams({
775991 'text_input': inputText,
776992 'text_filtering': 'standard',
777993 'character_voice_gen': voiceId + '.wav',
778994 'narrator_enabled': this.settings.narrator_enabled,
779995 'narrator_voice_gen': this.settings.narrator_voice_gen + '.wav',
780996 'text_not_inside': this.settings.at_narrator_text_not_inside,
781997 'language': this.settings.language,
782998 'output_file_name': 'st_output',
783999 'output_file_timestamp': 'true',
7841000 'autoplay': 'false',
7851001 'autoplay_volume': '0.8',
7861002 }).toString();
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+ }
7871015
7881016 try {
7891017 const response = await doExtrasFetch(
@@ -800,16 +1028,20 @@ class AllTalkTtsProvider {
8001028
8011029 if (!response.ok) {
8021030 const errorText = await response.text();
8031031 console.error('[fetchTtsGeneration] Error Response Text:', errorText);
804- // toastr.error(response.statusText, 'TTS Generation Failed');
8051032 throw new Error(`HTTP ${response.status}: ${errorText}`);
8061033 }
8071034 const data = await response.json();
808- const outputUrl = data.output_file_url;
1035+
809- return outputUrl; // Return only the output_file_url
1036+ // 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;
8101042 } catch (error) {
8111043 console.error('[fetchTtsGeneration] Exception caught:', error);
812- throw error; // Rethrow the error for further handling
1044+ throw error;
8131045 }
8141046 }
8151047}