|
@@ -211,93 +211,98 @@
|
|
|
speaking = null;
|
|
|
speakingIdx = null;
|
|
|
} else {
|
|
|
- speaking = true;
|
|
|
-
|
|
|
- if ($config.audio.tts.engine === 'openai') {
|
|
|
- loadingSpeech = true;
|
|
|
-
|
|
|
- const sentences = extractSentences(message.content).reduce((mergedTexts, currentText) => {
|
|
|
- const lastIndex = mergedTexts.length - 1;
|
|
|
- if (lastIndex >= 0) {
|
|
|
- const previousText = mergedTexts[lastIndex];
|
|
|
- const wordCount = previousText.split(/\s+/).length;
|
|
|
- if (wordCount < 2) {
|
|
|
- mergedTexts[lastIndex] = previousText + ' ' + currentText;
|
|
|
+ if ((message?.content ?? '').trim() !== '') {
|
|
|
+ speaking = true;
|
|
|
+
|
|
|
+ if ($config.audio.tts.engine === 'openai') {
|
|
|
+ loadingSpeech = true;
|
|
|
+
|
|
|
+ const sentences = extractSentences(message.content).reduce((mergedTexts, currentText) => {
|
|
|
+ const lastIndex = mergedTexts.length - 1;
|
|
|
+ if (lastIndex >= 0) {
|
|
|
+ const previousText = mergedTexts[lastIndex];
|
|
|
+ const wordCount = previousText.split(/\s+/).length;
|
|
|
+ if (wordCount < 2) {
|
|
|
+ mergedTexts[lastIndex] = previousText + ' ' + currentText;
|
|
|
+ } else {
|
|
|
+ mergedTexts.push(currentText);
|
|
|
+ }
|
|
|
} else {
|
|
|
mergedTexts.push(currentText);
|
|
|
}
|
|
|
- } else {
|
|
|
- mergedTexts.push(currentText);
|
|
|
- }
|
|
|
- return mergedTexts;
|
|
|
- }, []);
|
|
|
-
|
|
|
- console.log(sentences);
|
|
|
-
|
|
|
- sentencesAudio = sentences.reduce((a, e, i, arr) => {
|
|
|
- a[i] = null;
|
|
|
- return a;
|
|
|
- }, {});
|
|
|
-
|
|
|
- let lastPlayedAudioPromise = Promise.resolve(); // Initialize a promise that resolves immediately
|
|
|
-
|
|
|
- for (const [idx, sentence] of sentences.entries()) {
|
|
|
- const res = await synthesizeOpenAISpeech(
|
|
|
- localStorage.token,
|
|
|
- $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice,
|
|
|
- sentence
|
|
|
- ).catch((error) => {
|
|
|
- toast.error(error);
|
|
|
-
|
|
|
- speaking = null;
|
|
|
- loadingSpeech = false;
|
|
|
-
|
|
|
- return null;
|
|
|
- });
|
|
|
-
|
|
|
- if (res) {
|
|
|
- const blob = await res.blob();
|
|
|
- const blobUrl = URL.createObjectURL(blob);
|
|
|
- const audio = new Audio(blobUrl);
|
|
|
- sentencesAudio[idx] = audio;
|
|
|
- loadingSpeech = false;
|
|
|
- lastPlayedAudioPromise = lastPlayedAudioPromise.then(() => playAudio(idx));
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- let voices = [];
|
|
|
- const getVoicesLoop = setInterval(async () => {
|
|
|
- voices = await speechSynthesis.getVoices();
|
|
|
- if (voices.length > 0) {
|
|
|
- clearInterval(getVoicesLoop);
|
|
|
+ return mergedTexts;
|
|
|
+ }, []);
|
|
|
|
|
|
- const voice =
|
|
|
- voices
|
|
|
- ?.filter(
|
|
|
- (v) => v.voiceURI === ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice)
|
|
|
- )
|
|
|
- ?.at(0) ?? undefined;
|
|
|
+ console.log(sentences);
|
|
|
|
|
|
- console.log(voice);
|
|
|
+ sentencesAudio = sentences.reduce((a, e, i, arr) => {
|
|
|
+ a[i] = null;
|
|
|
+ return a;
|
|
|
+ }, {});
|
|
|
|
|
|
- const speak = new SpeechSynthesisUtterance(message.content);
|
|
|
+ let lastPlayedAudioPromise = Promise.resolve(); // Initialize a promise that resolves immediately
|
|
|
|
|
|
- console.log(speak);
|
|
|
+ for (const [idx, sentence] of sentences.entries()) {
|
|
|
+ const res = await synthesizeOpenAISpeech(
|
|
|
+ localStorage.token,
|
|
|
+ $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice,
|
|
|
+ sentence
|
|
|
+ ).catch((error) => {
|
|
|
+ toast.error(error);
|
|
|
|
|
|
- speak.onend = () => {
|
|
|
speaking = null;
|
|
|
- if ($settings.conversationMode) {
|
|
|
- document.getElementById('voice-input-button')?.click();
|
|
|
+ loadingSpeech = false;
|
|
|
+
|
|
|
+ return null;
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res) {
|
|
|
+ const blob = await res.blob();
|
|
|
+ const blobUrl = URL.createObjectURL(blob);
|
|
|
+ const audio = new Audio(blobUrl);
|
|
|
+ sentencesAudio[idx] = audio;
|
|
|
+ loadingSpeech = false;
|
|
|
+ lastPlayedAudioPromise = lastPlayedAudioPromise.then(() => playAudio(idx));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ let voices = [];
|
|
|
+ const getVoicesLoop = setInterval(async () => {
|
|
|
+ voices = await speechSynthesis.getVoices();
|
|
|
+ if (voices.length > 0) {
|
|
|
+ clearInterval(getVoicesLoop);
|
|
|
+
|
|
|
+ const voice =
|
|
|
+ voices
|
|
|
+ ?.filter(
|
|
|
+ (v) =>
|
|
|
+ v.voiceURI === ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice)
|
|
|
+ )
|
|
|
+ ?.at(0) ?? undefined;
|
|
|
+
|
|
|
+ console.log(voice);
|
|
|
+
|
|
|
+ const speak = new SpeechSynthesisUtterance(message.content);
|
|
|
+
|
|
|
+ console.log(speak);
|
|
|
+
|
|
|
+ speak.onend = () => {
|
|
|
+ speaking = null;
|
|
|
+ if ($settings.conversationMode) {
|
|
|
+ document.getElementById('voice-input-button')?.click();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ if (voice) {
|
|
|
+ speak.voice = voice;
|
|
|
}
|
|
|
- };
|
|
|
|
|
|
- if (voice) {
|
|
|
- speak.voice = voice;
|
|
|
+ speechSynthesis.speak(speak);
|
|
|
}
|
|
|
-
|
|
|
- speechSynthesis.speak(speak);
|
|
|
- }
|
|
|
- }, 100);
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ toast.error('No content to speak');
|
|
|
}
|
|
|
}
|
|
|
};
|