Skip to content

Commit 62e994c

Browse files
G-Fourteenclaude
andcommitted
Revert browser TTS fallback - keep Kokoro only
- Removed all browser TTS fallback code - Removed timeout that was causing fallback - Reduced chunk size to 100 chars for faster first response - Kokoro AI voices only, no robotic browser speech 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 5ddb71b commit 62e994c

1 file changed

Lines changed: 15 additions & 95 deletions

File tree

src/js/utils/kokoro-tts.js

Lines changed: 15 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -62,54 +62,7 @@ const KokoroTTS = {
6262
settings: {
6363
enabled: true,
6464
volume: 0.8,
65-
speed: 1.0,
66-
useFastMode: false // If true, use browser TTS for instant response
67-
},
68-
69-
// ═══════════════════════════════════════════════════════════
70-
// FAST MODE - Browser's built-in TTS for instant response
71-
// ═══════════════════════════════════════════════════════════
72-
73-
_webSpeechAvailable: null,
74-
75-
checkWebSpeech() {
76-
if (this._webSpeechAvailable !== null) return this._webSpeechAvailable;
77-
this._webSpeechAvailable = 'speechSynthesis' in window;
78-
return this._webSpeechAvailable;
79-
},
80-
81-
// Use browser TTS - instant but robotic
82-
speakFast(text, npcType, npcData = {}) {
83-
if (!this.checkWebSpeech()) return false;
84-
const clean = this._clean(text);
85-
if (!clean) return false;
86-
87-
// Stop any current speech
88-
speechSynthesis.cancel();
89-
90-
const utterance = new SpeechSynthesisUtterance(clean);
91-
utterance.rate = this.settings.speed;
92-
utterance.volume = this.settings.volume;
93-
94-
// Try to pick appropriate voice
95-
const voices = speechSynthesis.getVoices();
96-
const isFemale = this._isFemaleNPC(npcType, npcData);
97-
const preferredVoice = voices.find(v =>
98-
(isFemale ? v.name.toLowerCase().includes('female') || v.name.includes('Zira') || v.name.includes('Samantha') :
99-
v.name.toLowerCase().includes('male') || v.name.includes('David') || v.name.includes('Daniel'))
100-
) || voices[0];
101-
102-
if (preferredVoice) utterance.voice = preferredVoice;
103-
speechSynthesis.speak(utterance);
104-
return true;
105-
},
106-
107-
_isFemaleNPC(npcType, npcData) {
108-
if (npcData.gender === 'female' || npcData.isFemale) return true;
109-
if (!npcType) return false;
110-
const n = npcType.toLowerCase();
111-
return ['woman','lady','girl','maiden','wife','mother','queen','princess','witch',
112-
'healer','barmaid','priestess','sorceress','herbalist','seamstress','fortune_teller'].some(k => n.includes(k));
65+
speed: 1.0
11366
},
11467

11568
// ═══════════════════════════════════════════════════════════
@@ -345,57 +298,38 @@ const KokoroTTS = {
345298
// SPEECH - NON-BLOCKING via Worker
346299
// ═══════════════════════════════════════════════════════════
347300

348-
// Maximum characters for fast response - longer text gets chunked
349-
MAX_CHUNK_LENGTH: 150,
350-
351-
// Generation timeout - fall back to browser TTS if Kokoro takes too long
352-
GENERATION_TIMEOUT: 8000, // 8 seconds max per chunk
301+
// Maximum characters per chunk - smaller = faster first response
302+
MAX_CHUNK_LENGTH: 100,
353303

354304
async speak(text, npcType, npcData = {}) {
355305
if (!this.settings.enabled || !text?.trim()) return false;
356-
357-
const clean = this._clean(text);
358-
if (!clean) return false;
359-
360-
// FAST MODE: Use browser TTS for instant response
361-
if (this.settings.useFastMode) {
362-
console.log('🎙️ TTS Fast Mode: Using browser speech');
363-
return this.speakFast(text, npcType, npcData);
364-
}
365-
366-
// If Kokoro not ready, use browser TTS as fallback
367306
if (!this._initialized || !this._worker) {
368-
console.log('🎙️ KokoroTTS: Not initialized, using browser TTS');
369-
return this.speakFast(text, npcType, npcData);
307+
console.log('🎙️ KokoroTTS: Not initialized');
308+
return false;
370309
}
371310

311+
const clean = this._clean(text);
312+
if (!clean) return false;
372313
const voice = npcData.voice || this.getVoiceForNPC(npcType, npcData);
373314

374315
try {
375-
// Split into sentences for faster first response
316+
// Split into small chunks for faster first response
376317
const chunks = this._splitIntoChunks(clean);
377-
console.log(`🎙️ KokoroTTS: "${voice}": ${chunks.length} chunk(s), first: "${chunks[0]?.substring(0, 40)}..."`);
318+
console.log(`🎙️ KokoroTTS: "${voice}": ${chunks.length} chunk(s)`);
378319

379320
this._showIndicator(true);
380321

381-
// Generate and play each chunk with timeout
322+
// Generate and play each chunk
382323
for (let i = 0; i < chunks.length; i++) {
383324
const chunk = chunks[i];
384325
if (!chunk.trim()) continue;
385326

386-
// Check if we were told to stop
387327
if (this._stopRequested) {
388328
this._stopRequested = false;
389329
break;
390330
}
391331

392-
// Race between generation and timeout
393-
const result = await Promise.race([
394-
this._send('generate', { text: chunk, voice, speed: this.settings.speed }),
395-
new Promise((_, reject) =>
396-
setTimeout(() => reject(new Error('Generation timeout')), this.GENERATION_TIMEOUT)
397-
)
398-
]);
332+
const result = await this._send('generate', { text: chunk, voice, speed: this.settings.speed });
399333

400334
if (result?.audio) {
401335
await this._play(result.audio, result.rate);
@@ -406,10 +340,9 @@ const KokoroTTS = {
406340
return true;
407341

408342
} catch (error) {
409-
console.warn('🎙️ KokoroTTS slow/failed, falling back to browser TTS:', error.message);
343+
console.error('🎙️ KokoroTTS failed:', error);
410344
this._showIndicator(false);
411-
// Fall back to browser TTS
412-
return this.speakFast(text, npcType, npcData);
345+
return false;
413346
}
414347
},
415348

@@ -503,25 +436,12 @@ const KokoroTTS = {
503436
},
504437

505438
stop() {
506-
this._stopRequested = true; // Stop any chunked playback in progress
439+
this._stopRequested = true;
507440
if (this._currentAudio) { try { this._currentAudio.stop(); } catch {} this._currentAudio = null; }
508-
// Also stop browser TTS if it's speaking
509-
if (this.checkWebSpeech()) { try { speechSynthesis.cancel(); } catch {} }
510441
this._showIndicator(false);
511442
},
512443

513-
isPlaying() {
514-
// Check both Kokoro and browser TTS
515-
if (this._currentAudio) return true;
516-
if (this.checkWebSpeech() && speechSynthesis.speaking) return true;
517-
return false;
518-
},
519-
520-
// Toggle between fast (browser) and quality (Kokoro) mode
521-
setFastMode(enabled) {
522-
this.settings.useFastMode = enabled;
523-
console.log(`🎙️ TTS Mode: ${enabled ? 'Fast (Browser)' : 'Quality (Kokoro AI)'}`);
524-
},
444+
isPlaying() { return this._currentAudio !== null; },
525445
isInitialized() { return this._initialized; },
526446
isLoading() { return this._loading; },
527447

0 commit comments

Comments
 (0)