| @@ -27,7 +27,7 @@ class ChatterboxTtsProvider { | ||
| 27 | 27 | voiceMap: this.settings.voiceMap || {}, |
| 28 | 28 | }; |
| 29 | 29 | } |
| 30 | - | |
| 30 | + | |
| 31 | 31 | ready = false; |
| 32 | 32 | voices = []; |
| 33 | 33 | separator = '. '; |
| @@ -134,7 +134,7 @@ class ChatterboxTtsProvider { | ||
| 134 | 134 | </select> |
| 135 | 135 | </div>`; |
| 136 | 136 | |
| 137 | 137 | html += `'</div>`'; // End params section |
| 138 | 138 | |
| 139 | 139 | // Footer with links |
| 140 | 140 | html += `<div class="chatterbox-footer"> |
| @@ -142,7 +142,7 @@ class ChatterboxTtsProvider { | ||
| 142 | 142 | <a href="https://github.com/devnen/Chatterbox-TTS-Server" target="_blank">Documentation</a> |
| 143 | 143 | </div>`; |
| 144 | 144 | |
| 145 | 145 | html += `'</div>`'; // End container |
| 146 | 146 | |
| 147 | 147 | // Add CSS styles |
| 148 | 148 | html += `<style> |
| @@ -224,19 +224,19 @@ class ChatterboxTtsProvider { | ||
| 224 | 224 | this.updateUIFromSettings(); |
| 225 | 225 | |
| 226 | 226 | console.debug('ChatterboxTTS: Settings loaded'); |
| 227 | - | |
| 227 | + | |
| 228 | 228 | try { |
| 229 | 229 | // Check if TTS provider is ready |
| 230 | 230 | await this.checkReady(); |
| 231 | - | |
| 231 | + | |
| 232 | 232 | if (this.ready) { |
| 233 | 233 | // Fetch all voice types for the voice map |
| 234 | 234 | await this.fetchTtsVoiceObjects(); |
| 235 | 235 | this.updateStatus('Ready'); |
| 236 | 236 | } |
| 237 | - | |
| 237 | + | |
| 238 | 238 | this.setupEventListeners(); |
| 239 | - | |
| 239 | + | |
| 240 | 240 | } catch (error) { |
| 241 | 241 | console.error('Error loading Chatterbox settings:', error); |
| 242 | 242 | this.updateStatus('Offline'); |
| @@ -274,13 +274,13 @@ class ChatterboxTtsProvider { | ||
| 274 | 274 | async checkReady() { |
| 275 | 275 | try { |
| 276 | 276 | const response = await fetch(`${this.settings.provider_endpoint}/api/ui/initial-data`); |
| 277 | - | |
| 277 | + | |
| 278 | 278 | if (!response.ok) { |
| 279 | 279 | throw new Error(`HTTP Error Response: ${response.status} ${response.statusText}`); |
| 280 | 280 | } |
| 281 | - | |
| 281 | + | |
| 282 | 282 | const data = await response.json(); |
| 283 | - | |
| 283 | + | |
| 284 | 284 | // Check if we got valid data |
| 285 | 285 | if (data) { |
| 286 | 286 | this.ready = true; |
| @@ -306,15 +306,15 @@ class ChatterboxTtsProvider { | ||
| 306 | 306 | if (!predefinedResponse.ok) { |
| 307 | 307 | throw new Error(`HTTP ${predefinedResponse.status}: ${predefinedResponse.statusText}`); |
| 308 | 308 | } |
| 309 | - | |
| 309 | + | |
| 310 | 310 | const predefinedData = await predefinedResponse.json(); |
| 311 | - | |
| 311 | + | |
| 312 | 312 | // Transform predefined voices |
| 313 | 313 | const predefinedVoices = predefinedData.map(voice => ({ |
| 314 | 314 | name: voice.display_name, |
| 315 | 315 | voice_id: voice.voice_id, |
| 316 | 316 | preview_url: null, |
| 317 | 317 | lang: voice.language || 'en', |
| 318 | 318 | })); |
| 319 | 319 | |
| 320 | 320 | // Always try to fetch reference voices |
| @@ -327,16 +327,16 @@ class ChatterboxTtsProvider { | ||
| 327 | 327 | name: `[Clone] ${filename}`, |
| 328 | 328 | voice_id: `ref_${filename}`, |
| 329 | 329 | preview_url: null, |
| 330 | 330 | lang: 'en', |
| 331 | 331 | })); |
| 332 | 332 | } |
| 333 | 333 | } catch (error) { |
| 334 | 334 | console.warn('Failed to fetch reference voices:', error); |
| 335 | 335 | } |
| 336 | - | |
| 336 | + | |
| 337 | 337 | // Combine all voices |
| 338 | 338 | this.voices = [...predefinedVoices, ...referenceVoices]; |
| 339 | - | |
| 339 | + | |
| 340 | 340 | console.log(`Loaded ${this.voices.length} voices (${predefinedVoices.length} predefined, ${referenceVoices.length} reference)`); |
| 341 | 341 | return this.voices; |
| 342 | 342 | } catch (error) { |
| @@ -439,7 +439,7 @@ class ChatterboxTtsProvider { | ||
| 439 | 439 | try { |
| 440 | 440 | this.updateStatus('Processing'); |
| 441 | 441 | await this.checkReady(); |
| 442 | - | |
| 442 | + | |
| 443 | 443 | if (this.ready) { |
| 444 | 444 | await this.fetchTtsVoiceObjects(); |
| 445 | 445 | this.updateStatus('Ready'); |
| @@ -459,18 +459,18 @@ class ChatterboxTtsProvider { | ||
| 459 | 459 | async previewTtsVoice(voiceId) { |
| 460 | 460 | try { |
| 461 | 461 | this.updateStatus('Processing'); |
| 462 | - | |
| 462 | + | |
| 463 | 463 | const previewText = "'Hello! This is a preview of the selected voice."'; |
| 464 | - | |
| 464 | + | |
| 465 | 465 | // Determine if this is a reference voice |
| 466 | 466 | let isReferenceVoice = false; |
| 467 | 467 | let actualVoiceId = voiceId; |
| 468 | - | |
| 468 | + | |
| 469 | 469 | if (voiceId && voiceId.startsWith('ref_')) { |
| 470 | 470 | isReferenceVoice = true; |
| 471 | 471 | actualVoiceId = voiceId.substring(4); // Remove 'ref_' prefix |
| 472 | 472 | } |
| 473 | - | |
| 473 | + | |
| 474 | 474 | // Generate preview using the main TTS endpoint |
| 475 | 475 | const requestBody = { |
| 476 | 476 | text: previewText, |
| @@ -482,7 +482,7 @@ class ChatterboxTtsProvider { | ||
| 482 | 482 | speed_factor: this.settings.speed_factor, |
| 483 | 483 | language: this.settings.language, |
| 484 | 484 | split_text: false, // Don't split for preview |
| 485 | 485 | output_format: this.settings.output_format, |
| 486 | 486 | }; |
| 487 | 487 | |
| 488 | 488 | // Add voice-specific parameters |
| @@ -495,9 +495,9 @@ class ChatterboxTtsProvider { | ||
| 495 | 495 | const response = await fetch(`${this.settings.provider_endpoint}/tts`, { |
| 496 | 496 | method: 'POST', |
| 497 | 497 | headers: { |
| 498 | 498 | 'Content-Type': 'application/json', |
| 499 | 499 | }, |
| 500 | 500 | body: JSON.stringify(requestBody), |
| 501 | 501 | }); |
| 502 | 502 | |
| 503 | 503 | if (!response.ok) { |
| @@ -507,15 +507,15 @@ class ChatterboxTtsProvider { | ||
| 507 | 507 | // Get the audio blob and play it |
| 508 | 508 | const audioBlob = await response.blob(); |
| 509 | 509 | const audioUrl = URL.createObjectURL(audioBlob); |
| 510 | - | |
| 510 | + | |
| 511 | 511 | const audio = new Audio(audioUrl); |
| 512 | 512 | audio.addEventListener('ended', () => { |
| 513 | 513 | URL.revokeObjectURL(audioUrl); |
| 514 | 514 | this.updateStatus('Ready'); |
| 515 | 515 | }); |
| 516 | - | |
| 516 | + | |
| 517 | 517 | await audio.play(); |
| 518 | - | |
| 518 | + | |
| 519 | 519 | } catch (error) { |
| 520 | 520 | console.error('Error previewing voice:', error); |
| 521 | 521 | this.updateStatus('Ready'); |
| @@ -532,14 +532,14 @@ class ChatterboxTtsProvider { | ||
| 532 | 532 | if (this.voices.length === 0) { |
| 533 | 533 | await this.fetchTtsVoiceObjects(); |
| 534 | 534 | } |
| 535 | - | |
| 535 | + | |
| 536 | 536 | // Find the voice object by name or voice_id |
| 537 | 537 | let match = this.voices.find(voice => |
| 538 | 538 | voice.name === voiceName || |
| 539 | 539 | voice.voice_id === voiceName || |
| 540 | 540 | voice.display_name === voiceName, |
| 541 | 541 | ); |
| 542 | - | |
| 542 | + | |
| 543 | 543 | if (!match) { |
| 544 | 544 | console.warn(`Voice not found: ${voiceName}`); |
| 545 | 545 | // Check if it's a reference voice that wasn't in the list |
| @@ -549,7 +549,7 @@ class ChatterboxTtsProvider { | ||
| 549 | 549 | name: `[Clone] ${filename}`, |
| 550 | 550 | voice_id: voiceName, |
| 551 | 551 | preview_url: null, |
| 552 | 552 | lang: 'en', |
| 553 | 553 | }; |
| 554 | 554 | } |
| 555 | 555 | // Return a default voice object |
| @@ -557,10 +557,10 @@ class ChatterboxTtsProvider { | ||
| 557 | 557 | name: voiceName || 'Default', |
| 558 | 558 | voice_id: voiceName || this.settings.predefined_voice || 'S1', |
| 559 | 559 | preview_url: null, |
| 560 | 560 | lang: 'en', |
| 561 | 561 | }; |
| 562 | 562 | } |
| 563 | - | |
| 563 | + | |
| 564 | 564 | return match; |
| 565 | 565 | } |
| 566 | 566 | |
| @@ -571,16 +571,16 @@ class ChatterboxTtsProvider { | ||
| 571 | 571 | async generateTts(inputText, voiceId) { |
| 572 | 572 | try { |
| 573 | 573 | this.updateStatus('Processing'); |
| 574 | - | |
| 574 | + | |
| 575 | 575 | // Determine if this is a reference voice |
| 576 | 576 | let isReferenceVoice = false; |
| 577 | 577 | let actualVoiceId = voiceId; |
| 578 | - | |
| 578 | + | |
| 579 | 579 | if (voiceId && voiceId.startsWith('ref_')) { |
| 580 | 580 | isReferenceVoice = true; |
| 581 | 581 | actualVoiceId = voiceId.substring(4); // Remove 'ref_' prefix |
| 582 | 582 | } |
| 583 | - | |
| 583 | + | |
| 584 | 584 | // Prepare the request body |
| 585 | 585 | const requestBody = { |
| 586 | 586 | text: inputText, |
| @@ -593,7 +593,7 @@ class ChatterboxTtsProvider { | ||
| 593 | 593 | language: this.settings.language, |
| 594 | 594 | split_text: this.settings.split_text, |
| 595 | 595 | chunk_size: this.settings.chunk_size, |
| 596 | 596 | output_format: this.settings.output_format, |
| 597 | 597 | }; |
| 598 | 598 | |
| 599 | 599 | // Add voice-specific parameters |
| @@ -609,9 +609,9 @@ class ChatterboxTtsProvider { | ||
| 609 | 609 | method: 'POST', |
| 610 | 610 | headers: { |
| 611 | 611 | 'Content-Type': 'application/json', |
| 612 | 612 | 'Cache-Control': 'no-cache', |
| 613 | 613 | }, |
| 614 | 614 | body: JSON.stringify(requestBody), |
| 615 | 615 | }); |
| 616 | 616 | |
| 617 | 617 | if (!response.ok) { |
| @@ -621,10 +621,10 @@ class ChatterboxTtsProvider { | ||
| 621 | 621 | } |
| 622 | 622 | |
| 623 | 623 | this.updateStatus('Ready'); |
| 624 | - | |
| 624 | + | |
| 625 | 625 | // Return the response directly - SillyTavern expects a Response object |
| 626 | 626 | return response; |
| 627 | - | |
| 627 | + | |
| 628 | 628 | } catch (error) { |
| 629 | 629 | console.error('Error in generateTts:', error); |
| 630 | 630 | this.updateStatus('Ready'); |
| @@ -643,4 +643,4 @@ class ChatterboxTtsProvider { | ||
| 643 | 643 | statusElement.className = status.toLowerCase(); |
| 644 | 644 | } |
| 645 | 645 | } |
| 646 | -} | |
| 646 | \ No newline at end of file | |
| 646 | +} | |