Update TTS providers and story markup

This commit is contained in:
2026-05-20 22:13:31 +02:00
parent b911c40d89
commit 8258ea2321
36 changed files with 1482 additions and 197 deletions
+37 -19
View File
@@ -27,7 +27,7 @@ export class BrowserTTSModule extends TTSHandlerModule {
this.currentUtterance = null;
// Bind additional methods
this.bindMethods(['handleVoicePreferenceChanged']);
this.bindMethods(['handleVoicePreferenceChanged', 'estimateSpeechDuration']);
}
/**
@@ -368,26 +368,29 @@ export class BrowserTTSModule extends TTSHandlerModule {
// Set up event handlers
utterance.onstart = this.utteranceHandlers.start;
utterance.onend = () => {
this.utteranceHandlers.end();
if (callback) {
callback({ success: true });
}
};
utterance.onerror = (event) => {
this.utteranceHandlers.error(event);
if (callback) {
callback({ success: false, reason: 'synthesis_error', error: event });
}
};
utterance.onpause = this.utteranceHandlers.pause;
utterance.onresume = this.utteranceHandlers.resume;
// Start speaking
this.currentUtterance = utterance;
speechSynthesis.speak(utterance);
return true;
return new Promise(resolve => {
utterance.onend = () => {
this.utteranceHandlers.end();
if (callback) {
callback({ success: true });
}
resolve(true);
};
utterance.onerror = (event) => {
this.utteranceHandlers.error(event);
if (callback) {
callback({ success: false, reason: 'synthesis_error', error: event });
}
resolve(false);
};
speechSynthesis.speak(utterance);
});
} catch (error) {
console.error('Browser TTS: Failed to speak:', error);
if (callback) {
@@ -469,7 +472,7 @@ export class BrowserTTSModule extends TTSHandlerModule {
if (typeof options.speed === 'number') {
// Web Speech rate uses 1.0 as normal, matching the app-wide slider.
this.voiceOptions.speed = Math.max(0.1, Math.min(10.0, options.speed));
this.voiceOptions.speed = Math.max(0.5, Math.min(2.0, options.speed));
}
if (typeof options.pitch === 'number') {
@@ -494,8 +497,23 @@ export class BrowserTTSModule extends TTSHandlerModule {
* @returns {Promise<Object>} - Promise that resolves to null
*/
async preloadSpeech(text) {
// Browser TTS can't preload speech
return { success: false, reason: 'not_supported' };
if (!this.isReady || !text) {
return { success: false, reason: 'not_ready_or_empty_text' };
}
return {
success: true,
text,
duration: this.estimateSpeechDuration(text),
directPlayback: true
};
}
estimateSpeechDuration(text) {
const processedText = this.preprocessText(text);
const charactersPerSecond = 12;
const speed = Math.max(0.5, Math.min(2.0, Number(this.voiceOptions.speed) || 1.0));
return Math.max((processedText.length / (charactersPerSecond * speed)) * 1000, 800);
}
/**