Merge pull request #3868 from YunZLu/staging

Fix Edge Browser TTS Compatibility
This commit is contained in:
Cohee
2025-04-19 01:15:14 +03:00
committed by GitHub

View File

@@ -79,6 +79,10 @@ class SystemTtsProvider {
// Config // // Config //
//########// //########//
// Static constants for the simulated default voice
static BROWSER_DEFAULT_VOICE_ID = '__browser_default__';
static BROWSER_DEFAULT_VOICE_NAME = 'System Default Voice';
settings; settings;
ready = false; ready = false;
voices = []; voices = [];
@@ -168,51 +172,97 @@ class SystemTtsProvider {
//#################// //#################//
fetchTtsVoiceObjects() { fetchTtsVoiceObjects() {
if (!('speechSynthesis' in window)) { if (!('speechSynthesis' in window)) {
return []; return Promise.resolve([]);
} }
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
const voices = speechSynthesis let voices = speechSynthesis.getVoices();
.getVoices()
if (voices.length === 0) {
// Edge compat: Provide default when voices empty
console.warn('SystemTTS: getVoices() returned empty list. Providing browser default option.');
const defaultVoice = {
name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME,
voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID,
preview_url: false,
lang: navigator.language || 'en-US',
};
resolve([defaultVoice]);
} else {
const mappedVoices = voices
.sort((a, b) => a.lang.localeCompare(b.lang) || a.name.localeCompare(b.name)) .sort((a, b) => a.lang.localeCompare(b.lang) || a.name.localeCompare(b.name))
.map(x => ({ name: x.name, voice_id: x.voiceURI, preview_url: false, lang: x.lang })); .map(x => ({ name: x.name, voice_id: x.voiceURI, preview_url: false, lang: x.lang }));
resolve(mappedVoices);
resolve(voices); }
}, 1); }, 50);
}); });
} }
previewTtsVoice(voiceId) { previewTtsVoice(voiceId) {
if (!('speechSynthesis' in window)) { if (!('speechSynthesis' in window)) {
throw 'Speech synthesis API is not supported'; throw new Error('Speech synthesis API is not supported');
} }
const voice = speechSynthesis.getVoices().find(x => x.voiceURI === voiceId); let voice = null;
if (voiceId !== SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID) {
const voices = speechSynthesis.getVoices();
voice = voices.find(x => x.voiceURI === voiceId);
if (!voice) { if (!voice && voices.length > 0) {
throw `TTS Voice id ${voiceId} not found`; console.warn(`SystemTTS Preview: Voice ID "${voiceId}" not found among available voices. Using browser default.`);
} else if (!voice && voices.length === 0) {
console.warn('SystemTTS Preview: Voice list is empty. Using browser default.');
}
} else {
console.log('SystemTTS Preview: Using browser default voice as requested.');
} }
speechSynthesis.cancel(); speechSynthesis.cancel();
const text = getPreviewString(voice.lang); const langForPreview = voice ? voice.lang : (navigator.language || 'en-US');
const text = getPreviewString(langForPreview);
const utterance = new SpeechSynthesisUtterance(text); const utterance = new SpeechSynthesisUtterance(text);
if (voice) {
utterance.voice = voice; utterance.voice = voice;
}
utterance.rate = this.settings.rate || 1; utterance.rate = this.settings.rate || 1;
utterance.pitch = this.settings.pitch || 1; utterance.pitch = this.settings.pitch || 1;
utterance.onerror = (event) => {
console.error(`SystemTTS Preview Error: ${event.error}`, event);
};
speechSynthesis.speak(utterance); speechSynthesis.speak(utterance);
} }
async getVoice(voiceName) { async getVoice(voiceName) {
if (!('speechSynthesis' in window)) { if (!('speechSynthesis' in window)) {
return { voice_id: null }; return { voice_id: null, name: 'API Not Supported' };
}
if (voiceName === SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME) {
return {
voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID,
name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME,
};
} }
const voices = speechSynthesis.getVoices(); const voices = speechSynthesis.getVoices();
if (voices.length === 0) {
console.warn('SystemTTS: Empty voice list, using default fallback');
return {
voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID,
name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME,
};
}
const match = voices.find(x => x.name == voiceName); const match = voices.find(x => x.name == voiceName);
if (!match) { if (!match) {
throw `TTS Voice name ${voiceName} not found`; throw new Error(`SystemTTS getVoice: TTS Voice name "${voiceName}" not found`);
} }
return { voice_id: match.voiceURI, name: match.name }; return { voice_id: match.voiceURI, name: match.name };
@@ -237,7 +287,6 @@ class SystemTtsProvider {
speechUtteranceChunker(utterance, { speechUtteranceChunker(utterance, {
chunkLength: 200, chunkLength: 200,
}, function () { }, function () {
//some code to execute when done
resolve(silence); resolve(silence);
console.log('System TTS done'); console.log('System TTS done');
}); });