mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 09:20:15 +01:00
fix(useTextToSpeechBrowser): handle undefined window.speechSynthesis on some android devices
This commit is contained in:
parent
dba704079c
commit
16e1f74a6c
1 changed files with 31 additions and 7 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import type { VoiceOption } from '~/common';
|
import type { VoiceOption } from '~/common';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
@ -8,13 +8,20 @@ function useTextToSpeechBrowser({
|
||||||
}: {
|
}: {
|
||||||
setIsSpeaking: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsSpeaking: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}) {
|
}) {
|
||||||
const [cloudBrowserVoices] = useRecoilState(store.cloudBrowserVoices);
|
const voiceName = useRecoilValue(store.voice);
|
||||||
const [voiceName] = useRecoilState(store.voice);
|
|
||||||
const [voices, setVoices] = useState<VoiceOption[]>([]);
|
const [voices, setVoices] = useState<VoiceOption[]>([]);
|
||||||
|
const cloudBrowserVoices = useRecoilValue(store.cloudBrowserVoices);
|
||||||
|
const [isSpeechSynthesisSupported, setIsSpeechSynthesisSupported] = useState(true);
|
||||||
|
|
||||||
const updateVoices = useCallback(() => {
|
const updateVoices = useCallback(() => {
|
||||||
|
const synth = window.speechSynthesis as SpeechSynthesis | undefined;
|
||||||
|
if (!synth) {
|
||||||
|
setIsSpeechSynthesisSupported(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const availableVoices = window.speechSynthesis.getVoices();
|
const availableVoices = synth.getVoices();
|
||||||
if (!Array.isArray(availableVoices)) {
|
if (!Array.isArray(availableVoices)) {
|
||||||
console.error('getVoices() did not return an array');
|
console.error('getVoices() did not return an array');
|
||||||
return;
|
return;
|
||||||
|
|
@ -31,11 +38,16 @@ function useTextToSpeechBrowser({
|
||||||
setVoices(voiceOptions);
|
setVoices(voiceOptions);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating voices:', error);
|
console.error('Error updating voices:', error);
|
||||||
|
setIsSpeechSynthesisSupported(false);
|
||||||
}
|
}
|
||||||
}, [cloudBrowserVoices]);
|
}, [cloudBrowserVoices]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const synth = window.speechSynthesis;
|
const synth = window.speechSynthesis as SpeechSynthesis | undefined;
|
||||||
|
if (!synth) {
|
||||||
|
setIsSpeechSynthesisSupported(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (synth.getVoices().length) {
|
if (synth.getVoices().length) {
|
||||||
|
|
@ -45,14 +57,22 @@ function useTextToSpeechBrowser({
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in useEffect:', error);
|
console.error('Error in useEffect:', error);
|
||||||
|
setIsSpeechSynthesisSupported(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
synth.onvoiceschanged = null;
|
if (synth.onvoiceschanged) {
|
||||||
|
synth.onvoiceschanged = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [updateVoices]);
|
}, [updateVoices]);
|
||||||
|
|
||||||
const generateSpeechLocal = (text: string) => {
|
const generateSpeechLocal = (text: string) => {
|
||||||
|
if (!isSpeechSynthesisSupported) {
|
||||||
|
console.warn('Speech synthesis is not supported');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const synth = window.speechSynthesis;
|
const synth = window.speechSynthesis;
|
||||||
const voice = voices.find((v) => v.value === voiceName);
|
const voice = voices.find((v) => v.value === voiceName);
|
||||||
|
|
||||||
|
|
@ -81,6 +101,10 @@ function useTextToSpeechBrowser({
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelSpeechLocal = () => {
|
const cancelSpeechLocal = () => {
|
||||||
|
if (!isSpeechSynthesisSupported) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
window.speechSynthesis.cancel();
|
window.speechSynthesis.cancel();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -90,7 +114,7 @@ function useTextToSpeechBrowser({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { generateSpeechLocal, cancelSpeechLocal, voices };
|
return { generateSpeechLocal, cancelSpeechLocal, voices, isSpeechSynthesisSupported };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useTextToSpeechBrowser;
|
export default useTextToSpeechBrowser;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue