Support for AllTalk V1 and V2 Select the version in the interface. RVC is not supported on AllTalk V1

3138252928875c0aeeb5130188c62f49b6501c47

erew123 <35898566+erew123@users.noreply.github.com>

Signed
1 files changed, +418 -145Showing whitespace changes
public/scripts/extensions/tts/alltalk.js+418 -145
@@ -1,4 +1,4 @@
11import { doExtrasFetch, getApiUrl, modules } from '../../extensions.js';
22import { saveTtsProviderSettings } from './index.js';
33
44export { AllTalkTtsProvider };
@@ -13,22 +13,29 @@ class AllTalkTtsProvider {
1313 // Initialize with default settings if they are not already set
1414 this.settings = {
1515 provider_endpoint: this.settings.provider_endpoint || 'http://localhost:7851',
16+ server_version: this.settings.server_version || 'v2',
1617 language: this.settings.language || 'en',
1718 voiceMap: this.settings.voiceMap || {},
1819 at_generation_method: this.settings.at_generation_method || 'standard_generation',
1920 narrator_enabled: this.settings.narrator_enabled || 'false',
2021 at_narrator_text_not_inside: this.settings.at_narrator_text_not_inside || 'narrator',
2122 narrator_voice_gen: this.settings.narrator_voice_gen || 'female_01.wavPlease set a voice',
2223 finetuned_modelrvc_character_voice: this.settings.finetuned_modelrvc_character_voice || 'falseDisabled',
24+ rvc_character_pitch: this.settings.rvc_character_pitch || '0',
25+ rvc_narrator_voice: this.settings.rvc_narrator_voice || 'Disabled',
26+ rvc_narrator_pitch: this.settings.rvc_narrator_pitch || '0',
27+ finetuned_model: this.settings.finetuned_model || 'false'
2328 };
2429 // Separate property for dynamically updated settings from the server
2530 this.dynamicSettings = {
2631 modelsAvailable: [],
2732 currentModel: '',
2833 deepspeed_available: false,
2934 deepSpeedEnableddeepspeed_enabled: false,
3035 lowVramEnabledlowvram_capable: false,
36+ lowvram_enabled: false,
3137 };
38+ this.rvcVoices = []; // Initialize rvcVoices as an empty array
3239 }
3340 ready = false;
3441 voices = [];
@@ -56,7 +63,7 @@ class AllTalkTtsProvider {
5663 };
5764
5865 get settingsHtml() {
5966 let html = '`<div class="at-settings-separator">AllTalk V2 Settings</div>'`;
6067
6168 html += `<div class="at-settings-row">
6269
@@ -75,6 +82,7 @@ class AllTalkTtsProvider {
7582 <label for="at_narrator_enabled">AT Narrator</label>
7683 <select id="at_narrator_enabled">
7784 <option value="true">Enabled</option>
85+ <option value="silent">Enabled (Silenced)</option>
7886 <option value="false">Disabled</option>
7987 </select>
8088 </div>
@@ -82,8 +90,9 @@ class AllTalkTtsProvider {
8290 <div class="at-settings-option">
8391 <label for="at_narrator_text_not_inside">Text Not Inside * or " is</label>
8492 <select id="at_narrator_text_not_inside">
85- <option value="narrator">Narrator</option>
8693 <option value="character">Character</option>
94+ <option value="narrator">Narrator</option>
95+ <option value="silent">Silent</option>
8796 </select>
8897 </div>
8998
@@ -110,27 +119,74 @@ class AllTalkTtsProvider {
110119 </div>
111120 </div>`;
112121
122+ html += `<div class="at-settings-row">
123+ <div class="at-settings-option">
124+ <label for="rvc_character_voice">RVC Character</label>
125+ <select id="rvc_character_voice">`;
126+ if (this.rvcVoices) {
127+ for (let rvccharvoice of this.rvcVoices) {
128+ html += `<option value="${rvccharvoice.voice_id}">${rvccharvoice.name}</option>`;
129+ }
130+ }
131+ html += `</select>
132+ </div>
133+ <div class="at-settings-option">
134+ <label for="rvc_narrator_voice">RVC Narrator</label>
135+ <select id="rvc_narrator_voice">`;
136+ if (this.rvcVoices) {
137+ for (let rvcnarrvoice of this.rvcVoices) {
138+ html += `<option value="${rvcnarrvoice.voice_id}">${rvcnarrvoice.name}</option>`;
139+ }
140+ }
141+ html += `</select>
142+ </div>
143+</div>`;
144+
145+ // Add the RVC pitch control row
146+ html += `<div class="at-settings-row">
147+ <div class="at-settings-option">
148+ <label for="rvc_character_pitch">RVC Character Pitch</label>
149+ <select id="rvc_character_pitch">`;
150+ for (let i = -24; i <= 24; i++) {
151+ const selected = i === 0 ? 'selected="selected"' : '';
152+ html += `<option value="${i}" ${selected}>${i}</option>`;
153+ }
154+ html += `</select>
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>
164+ </div>
165+ </div>`;
113166
114167 html += `<div class="at-model-endpoint-row">
115168 <div class="at-model-option">
116169 <label for="switch_model">Switch Model</label>
117170 <select id="switch_model">
118- <option value="api_tts">API TTS</option>
171+ <!-- Options will be dynamically populated -->
119- <option value="api_local">API Local</option>
120- <option value="xttsv2_local">XTTSv2 Local</option>
121172 </select>
122173 </div>
123- </div>
124-
125- <div class="at-model-endpoint-row">
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">
@@ -152,7 +208,7 @@ class AllTalkTtsProvider {
152208
153209 html += `<div class="at-website-row">
154210 <div class="at-website-option">
155211 <span>AllTalk V2<a target="_blank" href="${this.settings.provider_endpoint}">Config & Docs</a>.</span>
156212 </div>
157213
158214 <div class="at-website-option">
@@ -162,7 +218,9 @@ class AllTalkTtsProvider {
162218
163219 html += `<div class="at-website-row">
164220<div class="at-website-option">
165-<span><strong>Text-generation-webui</strong> users - Uncheck <strong>Enable TTS</strong> in Text-generation-webui.</span>
221+<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>
222+<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>
223+<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>
166224</div>
167225</div>`;
168226
@@ -193,35 +251,35 @@ class AllTalkTtsProvider {
193251 // Update UI elements to reflect the loaded settings
194252 $('#at_server').val(this.settings.provider_endpoint);
195253 $('#language_options').val(this.settings.language);
196- //$('#voicemap').val(this.settings.voiceMap);
197254 $('#at_generation_method').val(this.settings.at_generation_method);
198255 $('#at_narrator_enabled').val(this.settings.narrator_enabled);
199256 $('#at_narrator_text_not_inside').val(this.settings.at_narrator_text_not_inside);
200257 $('#narrator_voice').val(this.settings.narrator_voice_gen);
258+ $('#rvc_character_voice').val(this.settings.rvc_character_voice);
259+ $('#rvc_narrator_voice').val(this.settings.rvc_narrator_voice);
260+ $('#rvc_character_pitch').val(this.settings.rvc_character_pitch);
261+ $('#rvc_narrator_pitch').val(this.settings.rvc_narrator_pitch);
201262
202263 console.debug('AllTalkTTS: Settings loaded');
203- await this.initEndpoint();
204- }
205-
206- async initEndpoint() {
207264 try {
208265 // Check if TTS provider is ready
209- this.setupEventListeners();
210- this.updateLanguageDropdown();
211266 await this.checkReady();
212267 await this.updateSettingsFromServer(); // Fetch dynamic settings from the TTS server
213268 await this.fetchTtsVoiceObjects(); // Fetch voices only if service is ready
269+ await this.fetchRvcVoiceObjects(); // Fetch RVC voices
214270 this.updateNarratorVoicesDropdown();
271+ this.updateLanguageDropdown();
272+ this.setupEventListeners();
215273 this.applySettingsToHTML();
216274 updateStatus('Ready');
217275 } catch (error) {
218276 console.error('"Error loading settings:'", error);
219277 updateStatus('Offline');
220278 }
221279 }
222280
281+
223282 applySettingsToHTML() {
224- // Apply loaded settings or use defaults
225283 const narratorVoiceSelect = document.getElementById('narrator_voice');
226284 const atNarratorSelect = document.getElementById('at_narrator_enabled');
227285 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
@@ -229,30 +287,26 @@ class AllTalkTtsProvider {
229287 this.settings.narrator_voice = this.settings.narrator_voice_gen;
230288 // Apply settings to Narrator Voice dropdown
231289 if (narratorVoiceSelect && this.settings.narrator_voice) {
232290 narratorVoiceSelect.value = this.settings.narrator_voice.replace('.wav', ''); // Remove the parentheses
233291 }
234292 // Apply settings to AT Narrator Enabled dropdown
235293 if (atNarratorSelect) {
236- // Sync the state with the checkbox in index.js
294+ const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks');
237295 const ttsPassAsterisksCheckboxttsNarrateQuotedCheckbox = document.getElementById('tts_pass_asteriskstts_narrate_quoted'); // Access the checkbox from index.js
238296 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
241297 if (this.settings.narrator_enabled) {
242298 ttsPassAsterisksCheckbox.checked = false;
243299 $('#tts_pass_asterisks').click(); // Simulate a click event
244300 $('#tts_pass_asterisks').trigger('change');
245301 }
246302 if (!this.settings.narrator_enabled) {
247303 ttsPassAsterisksCheckbox.checked = true;
248304 $('#tts_pass_asterisks').click(); // Simulate a click event
249305 $('#tts_pass_asterisks').trigger('change');
250306 }
251- // Uncheck and set tts_narrate_quoted to false if narrator is enabled
307+ if (this.settings.narrator_enabled) {
252- if (this.settings.narrator_enabledd) {
253308 ttsNarrateQuotedCheckbox.checked = true;
254309 ttsNarrateDialoguesCheckbox.checked = true;
255- // Trigger click events instead of change events
256310 $('#tts_narrate_quoted').click();
257311 $('#tts_narrate_quoted').trigger('change');
258312 $('#tts_narrate_dialogues').click();
@@ -261,42 +315,30 @@ class AllTalkTtsProvider {
261315 atNarratorSelect.value = this.settings.narrator_enabled.toString();
262316 this.settings.narrator_enabled = this.settings.narrator_enabled.toString();
263317 }
264- // Apply settings to the Language dropdown
265318 const languageSelect = document.getElementById('language_options');
266319 if (languageSelect && this.settings.language) {
267320 languageSelect.value = this.settings.language;
268321 }
269- // Apply settings to Text Not Inside dropdown
270322 if (textNotInsideSelect && this.settings.text_not_inside) {
271323 textNotInsideSelect.value = this.settings.text_not_inside;
272324 this.settings.at_narrator_text_not_inside = this.settings.text_not_inside;
273325 }
274- // Apply settings to Generation Method dropdown
275326 if (generationMethodSelect && this.settings.at_generation_method) {
276327 generationMethodSelect.value = this.settings.at_generation_method;
277328 }
278- // Additional logic to disable/enable dropdowns based on the selected generation method
279329 const isStreamingEnabled = this.settings.at_generation_method === 'streaming_enabled';
280330 if (isStreamingEnabled) {
281- // Disable certain dropdowns when streaming is enabled
282331 if (atNarratorSelect) atNarratorSelect.disabled = true;
283332 if (textNotInsideSelect) textNotInsideSelect.disabled = true;
284333 if (narratorVoiceSelect) narratorVoiceSelect.disabled = true;
285334 } else {
286- // Enable dropdowns for standard generation
287335 if (atNarratorSelect) atNarratorSelect.disabled = false;
288336 if (textNotInsideSelect) textNotInsideSelect.disabled = !this.settings.narrator_enabled;
289337 if (narratorVoiceSelect) narratorVoiceSelect.disabled = !this.settings.narrator_enabled;
290338 }
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- }
298339 }
299340
341+
300342 //##############################//
301343 // Check AT Server is Available //
302344 //##############################//
@@ -320,7 +362,6 @@ class AllTalkTtsProvider {
320362 } catch (error) {
321363 console.error('Error checking TTS service readiness:', error);
322364 this.ready = false; // Ensure ready flag is set to false in case of error
323- throw error; // Rethrow the error for further handling
324365 }
325366 }
326367
@@ -336,45 +377,149 @@ class AllTalkTtsProvider {
336377 }
337378 const data = await response.json();
338379 const voices = data.voices.map(filename => {
339- const voiceName = filename.replace('.wav', '');
340380 return {
341381 name: voiceNamefilename,
342382 voice_id: voiceNamefilename,
343383 preview_url: null, // Preview URL will be dynamically generated
344384 lang: 'en', // Default language
345385 };
346386 });
347387 this.voices = voices; // Assign to the class property
348388 return voices; // Also return this list
349389 }
350390
391+ async fetchRvcVoiceObjects() {
392+ if (this.settings.server_version !== 'v2') {
393+ console.log('Skipping RVC voices fetch for V1 server');
394+ return [];
395+ }
396+
397+ console.log('Fetching RVC Voices');
398+ try {
399+ const response = await fetch(`${this.settings.provider_endpoint}/api/rvcvoices`);
400+ if (!response.ok) {
401+ const errorText = await response.text();
402+ console.error('Error text:', errorText);
403+ throw new Error(`HTTP ${response.status}: ${errorText}`);
404+ }
405+
406+ const data = await response.json();
407+ if (!data || !data.rvcvoices) {
408+ console.error('Invalid data format:', data);
409+ throw new Error('Invalid data format received from /api/rvcvoices');
410+ }
411+
412+ const voices = data.rvcvoices.map(filename => {
413+ return {
414+ name: filename,
415+ voice_id: filename,
416+ };
417+ });
418+
419+ console.log('RVC voices:', voices);
420+ this.rvcVoices = voices; // Assign to the class property
421+ this.updateRvcVoiceDropdowns(); // Update UI after fetching voices
422+ return voices; // Also return this list
423+ } catch (error) {
424+ console.error('Error fetching RVC voices:', error);
425+ this.rvcVoices = [{ name: 'Disabled', voice_id: 'Disabled' }]; // Set default on error
426+ throw error;
427+ } finally {
428+ // Ensure dropdowns are updated even if there was an error
429+ this.updateRvcVoiceDropdowns();
430+ }
431+ }
432+
351433 //##########################################//
352434 // Get Current AT Server Config & Update ST //
353435 //##########################################//
354436
355437 async updateSettingsFromServer() {
356438 try {
357- // Fetch current settings
358439 const response = await fetch(`${this.settings.provider_endpoint}/api/currentsettings`);
359440 if (!response.ok) {
360441 throw new Error(`Failed to fetch current settings: ${response.statusText}`);
361442 }
362443 const currentSettings = await response.json();
363- // Update internal settings
444+ currentSettings.models_available.sort((a, b) => a.name.localeCompare(b.name));
445+
446+ this.settings.enginesAvailable = currentSettings.engines_available;
447+ this.settings.currentEngineLoaded = currentSettings.current_engine_loaded;
364448 this.settings.modelsAvailable = currentSettings.models_available;
365449 this.settings.currentModel = currentSettings.current_model_loaded;
450+ this.settings.deepspeed_capable = currentSettings.deepspeed_capable;
366451 this.settings.deepspeed_available = currentSettings.deepspeed_available;
367452 this.settings.deepSpeedEnableddeepspeed_enabled = currentSettings.deepspeed_statusdeepspeed_enabled;
368453 this.settings.lowVramEnabledlowvram_capable = currentSettings.low_vram_statuslowvram_capable;
369454 this.settings.finetuned_modellowvram_enabled = currentSettings.finetuned_modellowvram_enabled;
370- // Update HTML elements
455+
456+ await this.fetchRvcVoiceObjects(); // Fetch RVC voices
457+
371458 this.updateModelDropdown();
372459 this.updateCheckboxes();
460+ this.updateRvcVoiceDropdowns(); // Update the RVC voice dropdowns
373461 } catch (error) {
374462 console.error(`Error updating settings from server: ${error}`);
375463 }
376464 }
377465
466+ updateRvcVoiceDropdowns() {
467+ // Handle all RVC-related elements
468+ const rvcElements = document.querySelectorAll('.rvc-setting');
469+ const isV2 = this.settings.server_version === 'v2';
470+
471+ rvcElements.forEach(element => {
472+ element.style.display = isV2 ? 'block' : 'none';
473+ });
474+
475+ // Update and disable/enable character voice dropdown
476+ const rvcCharacterVoiceSelect = document.getElementById('rvc_character_voice');
477+ if (rvcCharacterVoiceSelect) {
478+ rvcCharacterVoiceSelect.disabled = !isV2;
479+ if (this.rvcVoices) {
480+ rvcCharacterVoiceSelect.innerHTML = '';
481+ for (let voice of this.rvcVoices) {
482+ const option = document.createElement('option');
483+ option.value = voice.voice_id;
484+ option.textContent = voice.name;
485+ if (voice.voice_id === this.settings.rvc_character_voice) {
486+ option.selected = true;
487+ }
488+ rvcCharacterVoiceSelect.appendChild(option);
489+ }
490+ }
491+ }
492+
493+ // Update and disable/enable narrator voice dropdown
494+ const rvcNarratorVoiceSelect = document.getElementById('rvc_narrator_voice');
495+ if (rvcNarratorVoiceSelect) {
496+ rvcNarratorVoiceSelect.disabled = !isV2;
497+ if (this.rvcVoices) {
498+ rvcNarratorVoiceSelect.innerHTML = '';
499+ for (let voice of this.rvcVoices) {
500+ const option = document.createElement('option');
501+ option.value = voice.voice_id;
502+ option.textContent = voice.name;
503+ if (voice.voice_id === this.settings.rvc_narrator_voice) {
504+ option.selected = true;
505+ }
506+ rvcNarratorVoiceSelect.appendChild(option);
507+ }
508+ }
509+ }
510+
511+ // Update pitch inputs
512+ const characterPitch = document.getElementById('rvc_character_pitch');
513+ if (characterPitch) {
514+ characterPitch.disabled = !isV2;
515+ }
516+
517+ const narratorPitch = document.getElementById('rvc_narrator_pitch');
518+ if (narratorPitch) {
519+ narratorPitch.disabled = !isV2;
520+ }
521+ }
522+
378523 //###################################################//
379524 // Get Current AT Server Config & Update ST (Models) //
380525 //###################################################//
@@ -385,9 +530,9 @@ class AllTalkTtsProvider {
385530 modelSelect.innerHTML = ''; // Clear existing options
386531 this.settings.modelsAvailable.forEach(model => {
387532 const option = document.createElement('option');
388533 option.value = model.model_namename;
389534 option.textContent = model.model_namename; // Use model_name instead ofmodel name directly
390535 option.selected = model.model_namename === this.settings.currentModel;
391536 modelSelect.appendChild(option);
392537 });
393538 }
@@ -400,13 +545,36 @@ class AllTalkTtsProvider {
400545 updateCheckboxes() {
401546 const deepspeedCheckbox = document.getElementById('deepspeed');
402547 const lowVramCheckbox = document.getElementById('low_vram');
403- if (lowVramCheckbox) lowVramCheckbox.checked = this.settings.lowVramEnabled;
548+
549+ // Handle DeepSpeed checkbox
404550 if (deepspeedCheckbox) {
405- deepspeedCheckbox.checked = this.settings.deepSpeedEnabled;
551+ if (this.settings.deepspeed_capable) {
406- deepspeedCheckbox.disabled = !this.settings.deepspeed_available; // Disable checkbox if deepspeed is not available
552+ // If TTS engine is capable of using DeepSpeed
553+ deepspeedCheckbox.disabled = !this.settings.deepspeed_available;
554+ this.settings.deepspeed_enabled = this.settings.deepspeed_available && this.settings.deepspeed_enabled;
555+ } else {
556+ // If TTS engine is NOT capable of using DeepSpeed
557+ deepspeedCheckbox.disabled = true;
558+ this.settings.deepspeed_enabled = false;
407559 }
560+ deepspeedCheckbox.checked = this.settings.deepspeed_enabled;
408561 }
409562
563+ // Handle Low VRAM checkbox
564+ if (lowVramCheckbox) {
565+ if (this.settings.lowvram_capable) {
566+ // If TTS engine is capable of low VRAM
567+ lowVramCheckbox.disabled = false;
568+ } else {
569+ // If TTS engine is NOT capable of low VRAM
570+ lowVramCheckbox.disabled = true;
571+ this.settings.lowvram_enabled = false;
572+ }
573+ lowVramCheckbox.checked = this.settings.lowvram_enabled;
574+ }
575+ }
576+
577+
410578 //###############################################################//
411579 // Get Current AT Server Config & Update ST (AT Narrator Voices) //
412580 //###############################################################//
@@ -433,8 +601,8 @@ class AllTalkTtsProvider {
433601 updateLanguageDropdown() {
434602 const languageSelect = document.getElementById('language_options');
435603 if (languageSelect) {
436604 // Ensure default language is set (??? whatever that means)
437605 // this.settings.language = this.settings.language;
438606
439607 languageSelect.innerHTML = '';
440608 for (let language in this.languageLabels) {
@@ -456,28 +624,28 @@ class AllTalkTtsProvider {
456624 setupEventListeners() {
457625
458626 let debounceTimeout;
459627 const debounceDelay = 5001400; // Milliseconds
460628
461629 // Define the event handler function
462630 const onModelSelectChange = async (event) => {
463631 console.log('"Model select change event triggered'"); // Debugging statement
464632 const selectedModel = event.target.value;
465633 console.log(`Selected model: ${selectedModel}`); // Debugging statement
466634 // Set status to Processing
467635 updateStatus('Processing');
468636 try {
469637 const response = await fetch(`${this.settings.provider_endpoint}/api/reload?tts_method=${encodeURIComponent(selectedModel)}`, {
470638 method: 'POST',
471639 });
472640 if (!response.ok) {
473641 throw new Error(`HTTP Error: ${response.status}`);
474642 }
475643 const data = await response.json();
476644 console.log('"POST response data:'", data); // Debugging statement
477645 // Set status to Ready if successful
478646 updateStatus('Ready');
479647 } catch (error) {
480648 console.error('"POST request error:'", error); // Debugging statement
481649 // Set status to Error in case of failure
482650 updateStatus('Error');
483651 }
@@ -485,6 +653,52 @@ class AllTalkTtsProvider {
485653 // Handle response or error
486654 };
487655
656+ // AllTalk Server version change listener
657+ const serverVersionSelect = document.getElementById('server_version');
658+ if (serverVersionSelect) {
659+ serverVersionSelect.addEventListener('change', async (event) => {
660+ this.settings.server_version = event.target.value;
661+ // Clear and refetch voices if needed
662+ if (event.target.value === 'v2') {
663+ await this.fetchRvcVoiceObjects();
664+ }
665+ this.updateRvcVoiceDropdowns();
666+ this.onSettingsChange();
667+ });
668+ }
669+
670+ const rvcCharacterVoiceSelect = document.getElementById('rvc_character_voice');
671+ if (rvcCharacterVoiceSelect) {
672+ rvcCharacterVoiceSelect.addEventListener('change', (event) => {
673+ this.settings.rvccharacter_voice_gen = event.target.value;
674+ this.onSettingsChange(); // Save the settings after change
675+ });
676+ }
677+
678+ const rvcNarratorVoiceSelect = document.getElementById('rvc_narrator_voice');
679+ if (rvcNarratorVoiceSelect) {
680+ rvcNarratorVoiceSelect.addEventListener('change', (event) => {
681+ this.settings.rvcnarrator_voice_gen = event.target.value;
682+ this.onSettingsChange(); // Save the settings after change
683+ });
684+ }
685+
686+ const rvcCharacterPitchSelect = document.getElementById('rvc_character_pitch');
687+ if (rvcCharacterPitchSelect) {
688+ rvcCharacterPitchSelect.addEventListener('change', (event) => {
689+ this.settings.rvc_character_pitch = event.target.value;
690+ this.onSettingsChange(); // Save the settings after change
691+ });
692+ }
693+
694+ const rvcNarratorPitchSelect = document.getElementById('rvc_narrator_pitch');
695+ if (rvcNarratorPitchSelect) {
696+ rvcNarratorPitchSelect.addEventListener('change', (event) => {
697+ this.settings.rvc_narrator_pitch = event.target.value;
698+ this.onSettingsChange(); // Save the settings after change
699+ });
700+ }
701+
488702 const debouncedModelSelectChange = (event) => {
489703 clearTimeout(debounceTimeout);
490704 debounceTimeout = setTimeout(() => {
@@ -496,74 +710,89 @@ class AllTalkTtsProvider {
496710 const modelSelect = document.getElementById('switch_model');
497711 if (modelSelect) {
498712 // Remove the event listener if it was previously added
713+ modelSelect.removeEventListener('change', debouncedModelSelectChange);
499714 // Add the debounced event listener
500715 $(modelSelect).off('change').onaddEventListener('change', debouncedModelSelectChange);
501716 }
502717
503718 // DeepSpeed Listener
504719 const deepspeedCheckbox = document.getElementById('deepspeed');
505720 if (deepspeedCheckbox) {
506721 $(deepspeedCheckbox).off('change').onaddEventListener('change', async (event) => {
507722 const deepSpeedValue = event.target.checked ? 'True' : 'False';
508723 // Set status to Processing
509724 updateStatus('Processing');
510725 try {
511726 const response = await fetch(`${this.settings.provider_endpoint}/api/deepspeed?new_deepspeed_value=${deepSpeedValue}`, {
512727 method: 'POST',
513728 });
514729 if (!response.ok) {
515730 throw new Error(`HTTP Error: ${response.status}`);
516731 }
517732 const data = await response.json();
518733 console.log('"POST response data:'", data); // Debugging statement
519734 // Set status to Ready if successful
520735 updateStatus('Ready');
521736 } catch (error) {
522737 console.error('"POST request error:'", error); // Debugging statement
523738 // Set status to Error in case of failure
524739 updateStatus('Error');
525740 }
526741 });
527742 }
528743
744+ function lowvramdebounce(func, delay) {
745+ let debounceTimer;
746+ return function (...args) {
747+ const context = this;
748+ clearTimeout(debounceTimer);
749+ debounceTimer = setTimeout(() => func.apply(context, args), delay);
750+ };
751+ }
752+
529753 // Low VRAM Listener
530754 const lowVramCheckbox = document.getElementById('low_vram');
531755 if (lowVramCheckbox) {
532756 $(lowVramCheckbox).off('change').on('change',const handleLowVramChange = async (event) => {
533757 const lowVramValue = event.target.checked ? 'True' : 'False';
534758 // Set status to Processing
535759 updateStatus('Processing');
536760 try {
537761 const response = await fetch(`${this.settings.provider_endpoint}/api/lowvramsetting?new_low_vram_value=${lowVramValue}`, {
538762 method: 'POST',
539763 });
540764 if (!response.ok) {
541765 throw new Error(`HTTP Error: ${response.status}`);
542766 }
543767 const data = await response.json();
544768 console.log('"POST response data:'", data); // Debugging statement
545769 // Set status to Ready if successful
546770 updateStatus('Ready');
547771 } catch (error) {
548772 console.error('"POST request error:'", error); // Debugging statement
549773 // Set status to Error in case of failure
550774 updateStatus('Error');
551775 }
552776 });
777+
778+ const debouncedHandleLowVramChange = lowvramdebounce(handleLowVramChange, 300); // Adjust delay as needed
779+
780+ lowVramCheckbox.addEventListener('change', debouncedHandleLowVramChange);
553781 }
554782
783+
555784 // Narrator Voice Dropdown Listener
556785 const narratorVoiceSelect = document.getElementById('narrator_voice');
557786 if (narratorVoiceSelect) {
558787 $(narratorVoiceSelect).off('change').onaddEventListener('change', (event) => {
559788 this.settings.narrator_voice_gen = `${event.target.value}.wav`;
560789 this.onSettingsChange(); // Save the settings after change
561790 });
562791 }
563792
564793 const textNotInsideSelect = document.getElementById('at_narrator_text_not_inside');
565794 if (textNotInsideSelect) {
566795 $(textNotInsideSelect).off('change').onaddEventListener('change', (event) => {
567796 this.settings.text_not_inside = event.target.value;
568797 this.onSettingsChange(); // Save the settings after change
569798 });
@@ -571,39 +800,45 @@ class AllTalkTtsProvider {
571800
572801 // AT Narrator Dropdown Listener
573802 const atNarratorSelect = document.getElementById('at_narrator_enabled');
574803 const ttsPassAsterisksCheckbox = document.getElementById('tts_pass_asterisks'); // Access the checkbox from index.js
575804 const ttsNarrateQuotedCheckbox = document.getElementById('tts_narrate_quoted'); // Access the checkbox from index.js
576805 const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); // Access the checkbox from index.js
577806
578807 if (atNarratorSelect && textNotInsideSelect && narratorVoiceSelect) {
579808 $(atNarratorSelect).off('change').onaddEventListener('change', (event) => {
580809 const isNarratorEnablednarratorOption = event.target.value === 'true';
581810 this.settings.narrator_enabled = isNarratorEnablednarratorOption; // Update the setting here
582- textNotInsideSelect.disabled = !isNarratorEnabled;
811+
583- narratorVoiceSelect.disabled = !isNarratorEnabled;
812+ // Check if narrator is disabled
584-
813+ const isNarratorDisabled = narratorOption === 'false';
585- // Sync the state with the checkbox in index.js
814+ textNotInsideSelect.disabled = isNarratorDisabled;
586- if (isNarratorEnabled) {
815+ narratorVoiceSelect.disabled = isNarratorDisabled;
816+
817+ console.log(`Narrator option: ${narratorOption}`);
818+ console.log(`textNotInsideSelect disabled: ${textNotInsideSelect.disabled}`);
819+ console.log(`narratorVoiceSelect disabled: ${narratorVoiceSelect.disabled}`);
820+
821+ if (narratorOption === 'true') {
587822 ttsPassAsterisksCheckbox.checked = false;
588823 $('#tts_pass_asterisks').click(); // Simulate a click event
589824 $('#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) {
598825 ttsNarrateQuotedCheckbox.checked = true;
599826 ttsNarrateDialoguesCheckbox.checked = true;
600- // Trigger click events instead of change events
601827 $('#tts_narrate_quoted').click();
602828 $('#tts_narrate_quoted').trigger('change');
603829 $('#tts_narrate_dialogues').click();
604830 $('#tts_narrate_dialogues').trigger('change');
831+ } else if (narratorOption === 'silent') {
832+ ttsPassAsterisksCheckbox.checked = false;
833+ $('#tts_pass_asterisks').click();
834+ $('#tts_pass_asterisks').trigger('change');
835+ } else {
836+ ttsPassAsterisksCheckbox.checked = true;
837+ $('#tts_pass_asterisks').click();
838+ $('#tts_pass_asterisks').trigger('change');
605839 }
606- this.onSettingsChange(); // Save the settings after change
840+
841+ this.onSettingsChange();
607842 });
608843 }
609844
@@ -612,7 +847,7 @@ class AllTalkTtsProvider {
612847 const atGenerationMethodSelect = document.getElementById('at_generation_method');
613848 const atNarratorEnabledSelect = document.getElementById('at_narrator_enabled');
614849 if (atGenerationMethodSelect) {
615850 $(atGenerationMethodSelect).off('change').onaddEventListener('change', (event) => {
616851 const selectedMethod = event.target.value;
617852
618853 if (selectedMethod === 'streaming_enabled') {
@@ -633,7 +868,7 @@ class AllTalkTtsProvider {
633868 // Listener for Language Dropdown
634869 const languageSelect = document.getElementById('language_options');
635870 if (languageSelect) {
636871 $(languageSelect).off('change').onaddEventListener('change', (event) => {
637872 this.settings.language = event.target.value;
638873 this.onSettingsChange(); // Save the settings after change
639874 });
@@ -642,7 +877,7 @@ class AllTalkTtsProvider {
642877 // Listener for AllTalk Endpoint Input
643878 const atServerInput = document.getElementById('at_server');
644879 if (atServerInput) {
645880 $(atServerInput).off('input').onaddEventListener('input', (event) => {
646881 this.settings.provider_endpoint = event.target.value;
647882 this.onSettingsChange(); // Save the settings after change
648883 });
@@ -662,6 +897,10 @@ class AllTalkTtsProvider {
662897 this.settings.at_generation_method = $('#at_generation_method').val();
663898 this.settings.narrator_enabled = $('#at_narrator_enabled').val();
664899 this.settings.at_narrator_text_not_inside = $('#at_narrator_text_not_inside').val();
900+ this.settings.rvc_character_voice = $('#rvc_character_voice').val();
901+ this.settings.rvc_narrator_voice = $('#rvc_narrator_voice').val();
902+ this.settings.rvc_character_pitch = $('#rvc_character_pitch').val();
903+ this.settings.rvc_narrator_pitch = $('#rvc_narrator_pitch').val();
665904 this.settings.narrator_voice_gen = $('#narrator_voice').val();
666905 // Save the updated settings
667906 saveTtsProviderSettings();
@@ -672,8 +911,16 @@ class AllTalkTtsProvider {
672911 //#########################//
673912
674913 async onRefreshClick() {
675- await this.initEndpoint();
914+ try {
676- // Additional actions as needed
915+ updateStatus('Processing'); // Set status to Processing while refreshing
916+ await this.checkReady(); // Check if the TTS provider is ready
917+ await this.loadSettings(this.settings); // Reload the settings
918+ await this.checkReady(); // Check if the TTS provider is ready
919+ updateStatus(this.ready ? 'Ready' : 'Offline'); // Update the status based on readiness
920+ } catch (error) {
921+ console.error('Error during refresh:', error);
922+ updateStatus('Error'); // Set status to Error in case of failure
923+ }
677924 }
678925
679926 //##################//
@@ -684,33 +931,44 @@ class AllTalkTtsProvider {
684931 try {
685932 // Prepare data for POST request
686933 const postData = new URLSearchParams();
687934 postData.append('"voice'", `${voiceName}.wav`);
935+
936+ // Add RVC parameters for V2 if applicable
937+ if (this.settings.server_version === 'v2' && this.settings.rvc_character_voice !== 'Disabled') {
938+ postData.append("rvccharacter_voice_gen", this.settings.rvc_character_voice);
939+ postData.append("rvccharacter_pitch", this.settings.rvc_character_pitch || "0");
940+ }
941+
688942 // Making the POST request
689943 const response = await fetch(`${this.settings.provider_endpoint}/api/previewvoice/`, {
690944 method: '"POST'",
691945 headers: {
692946 'Content-Type': 'application/x-www-form-urlencoded',
693947 },
694948 body: postData,
695949 });
950+
696951 if (!response.ok) {
697952 const errorText = await response.text();
698953 console.error('`[previewTtsVoice] Error Response Text:'`, errorText);
699954 throw new Error(`HTTP ${response.status}: ${errorText}`);
700955 }
701- // Assuming the server returns a URL to the .wav file
956+
702957 const data = await response.json();
703958 if (data.output_file_url) {
704- // Use an audio element to play the .wav file
959+ // Handle V1/V2 URL differences
705- const audioElement = new Audio(data.output_file_url);
960+ const fullUrl = this.settings.server_version === 'v1'
706- audioElement.play().catch(e => console.error('Error playing audio:', e));
961+ ? data.output_file_url
962+ : `${this.settings.provider_endpoint}${data.output_file_url}`;
963+
964+ const audioElement = new Audio(fullUrl);
965+ audioElement.play().catch(e => console.error("Error playing audio:", e));
707966 } else {
708967 console.warn('"[previewTtsVoice] No output file URL received in the response'");
709968 throw new Error('"No output file URL received in the response'");
710969 }
711-
712970 } catch (error) {
713971 console.error('"[previewTtsVoice] Exception caught during preview generation:'", error);
714972 throw error;
715973 }
716974 }
@@ -744,8 +1002,8 @@ class AllTalkTtsProvider {
7441002 try {
7451003 if (this.settings.at_generation_method === 'streaming_enabled') {
7461004 // Construct the streaming URL
7471005 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`;
7481006 console.log('"Streaming URL:'", streamingUrl);
7491007
7501008 // Return the streaming URL directly
7511009 return streamingUrl;
@@ -759,7 +1017,7 @@ class AllTalkTtsProvider {
7591017 return audioResponse; // Return the fetch response directly
7601018 }
7611019 } catch (error) {
7621020 console.error('"Error in generateTts:'", error);
7631021 throw error;
7641022 }
7651023 }
@@ -770,20 +1028,31 @@ class AllTalkTtsProvider {
7701028 //####################//
7711029
7721030 async fetchTtsGeneration(inputText, voiceId) {
773- // Prepare the request payload
7741031 const requestBody = new URLSearchParams({
7751032 'text_input': inputText,
7761033 'text_filtering': '"standard'",
7771034 'character_voice_gen': voiceId + '.wav',
7781035 'narrator_enabled': this.settings.narrator_enabled,
7791036 'narrator_voice_gen': this.settings.narrator_voice_gen + '.wav',
7801037 'text_not_inside': this.settings.at_narrator_text_not_inside,
7811038 'language': this.settings.language,
7821039 'output_file_name': '"st_output'",
7831040 'output_file_timestamp': '"true'",
7841041 'autoplay': '"false'",
7851042 'autoplay_volume': '"0.8',"
7861043 }).toString();
1044+
1045+ // Add RVC parameters only for V2
1046+ if (this.settings.server_version === 'v2') {
1047+ if (this.settings.rvc_character_voice !== 'Disabled') {
1048+ requestBody.append('rvccharacter_voice_gen', this.settings.rvc_character_voice);
1049+ requestBody.append('rvccharacter_pitch', this.settings.rvc_character_pitch || "0");
1050+ }
1051+ if (this.settings.rvc_narrator_voice !== 'Disabled') {
1052+ requestBody.append('rvcnarrator_voice_gen', this.settings.rvc_narrator_voice);
1053+ requestBody.append('rvcnarrator_pitch', this.settings.rvc_narrator_pitch || "0");
1054+ }
1055+ }
7871056
7881057 try {
7891058 const response = await doExtrasFetch(
@@ -794,22 +1063,26 @@ class AllTalkTtsProvider {
7941063 'Content-Type': 'application/x-www-form-urlencoded',
7951064 'Cache-Control': 'no-cache',
7961065 },
7971066 body: requestBody,
7981067 },
7991068 );
8001069
8011070 if (!response.ok) {
8021071 const errorText = await response.text();
8031072 console.error('`[fetchTtsGeneration] Error Response Text:'`, errorText);
804- // toastr.error(response.statusText, 'TTS Generation Failed');
8051073 throw new Error(`HTTP ${response.status}: ${errorText}`);
8061074 }
8071075 const data = await response.json();
808- const outputUrl = data.output_file_url;
1076+
809- return outputUrl; // Return only the output_file_url
1077+ // Handle V1/V2 URL differences
1078+ const outputUrl = this.settings.server_version === 'v1'
1079+ ? data.output_file_url // V1 returns full URL
1080+ : `${this.settings.provider_endpoint}${data.output_file_url}`; // V2 returns relative path
1081+
1082+ return outputUrl;
8101083 } catch (error) {
8111084 console.error('"[fetchTtsGeneration] Exception caught:'", error);
812- throw error; // Rethrow the error for further handling
1085+ throw error;
8131086 }
8141087 }
8151088}