mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 17:30:16 +01:00
🎯 fix: Prevent UI De-sync By Removing Redundant States (#5333)
* fix: remove local state from Dropdown causing de-sync * refactor: cleanup STT code, avoid redundant states to prevent de-sync and side effects * fix: reset transcript after sending final text to prevent data loss * fix: clear timeout on component unmount to prevent memory leaks
This commit is contained in:
parent
b55e695541
commit
e309c6abef
8 changed files with 149 additions and 145 deletions
|
|
@ -1,83 +1,48 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import useSpeechToTextBrowser from './useSpeechToTextBrowser';
|
||||
import useSpeechToTextExternal from './useSpeechToTextExternal';
|
||||
import useGetAudioSettings from './useGetAudioSettings';
|
||||
|
||||
const useSpeechToText = (handleTranscriptionComplete: (text: string) => void) => {
|
||||
const useSpeechToText = (
|
||||
setText: (text: string) => void,
|
||||
onTranscriptionComplete: (text: string) => void,
|
||||
): {
|
||||
isLoading?: boolean;
|
||||
isListening?: boolean;
|
||||
stopRecording: () => void | (() => Promise<void>);
|
||||
startRecording: () => void | (() => Promise<void>);
|
||||
} => {
|
||||
const { speechToTextEndpoint } = useGetAudioSettings();
|
||||
const [animatedText, setAnimatedText] = useState('');
|
||||
const externalSpeechToText = speechToTextEndpoint === 'external';
|
||||
|
||||
const {
|
||||
isListening: speechIsListeningBrowser,
|
||||
isLoading: speechIsLoadingBrowser,
|
||||
interimTranscript: interimTranscriptBrowser,
|
||||
text: speechTextBrowser,
|
||||
startRecording: startSpeechRecordingBrowser,
|
||||
stopRecording: stopSpeechRecordingBrowser,
|
||||
} = useSpeechToTextBrowser();
|
||||
} = useSpeechToTextBrowser(setText, onTranscriptionComplete);
|
||||
|
||||
const {
|
||||
isListening: speechIsListeningExternal,
|
||||
isLoading: speechIsLoadingExternal,
|
||||
text: speechTextExternal,
|
||||
externalStartRecording: startSpeechRecordingExternal,
|
||||
externalStopRecording: stopSpeechRecordingExternal,
|
||||
clearText,
|
||||
} = useSpeechToTextExternal(handleTranscriptionComplete);
|
||||
} = useSpeechToTextExternal(setText, onTranscriptionComplete);
|
||||
|
||||
const isListening = externalSpeechToText ? speechIsListeningExternal : speechIsListeningBrowser;
|
||||
const isLoading = externalSpeechToText ? speechIsLoadingExternal : speechIsLoadingBrowser;
|
||||
const speechTextForm = externalSpeechToText ? speechTextExternal : speechTextBrowser;
|
||||
|
||||
const startRecording = externalSpeechToText
|
||||
? startSpeechRecordingExternal
|
||||
: startSpeechRecordingBrowser;
|
||||
const stopRecording = externalSpeechToText
|
||||
? stopSpeechRecordingExternal
|
||||
: stopSpeechRecordingBrowser;
|
||||
const speechText =
|
||||
isListening || (speechTextExternal && speechTextExternal.length > 0)
|
||||
? speechTextExternal
|
||||
: speechTextForm || '';
|
||||
// for a future real-time STT external
|
||||
const interimTranscript = externalSpeechToText ? '' : interimTranscriptBrowser;
|
||||
|
||||
const animateTextTyping = (text: string) => {
|
||||
const totalDuration = 2000;
|
||||
const frameRate = 60;
|
||||
const totalFrames = totalDuration / (1000 / frameRate);
|
||||
const charsPerFrame = Math.ceil(text.length / totalFrames);
|
||||
let currentIndex = 0;
|
||||
|
||||
const animate = () => {
|
||||
currentIndex += charsPerFrame;
|
||||
const currentText = text.substring(0, currentIndex);
|
||||
setAnimatedText(currentText);
|
||||
|
||||
if (currentIndex < text.length) {
|
||||
requestAnimationFrame(animate);
|
||||
} else {
|
||||
setAnimatedText(text);
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (speechText && externalSpeechToText) {
|
||||
animateTextTyping(speechText);
|
||||
}
|
||||
}, [speechText, externalSpeechToText]);
|
||||
|
||||
return {
|
||||
isListening,
|
||||
isLoading,
|
||||
startRecording,
|
||||
isListening,
|
||||
stopRecording,
|
||||
interimTranscript,
|
||||
speechText: externalSpeechToText ? animatedText : speechText,
|
||||
clearText,
|
||||
startRecording,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue