LibreChat/client/src/components/Chat/Input/AudioRecorder.tsx
Marco Beretta 8f3de7d11f
🎨 refactor: UI stlye (#4438)
* feat: Refactor ChatForm and StopButton components for improved styling and localization

* feat: Refactor AudioRecorder, ChatForm, AttachFile, and SendButton components for improved styling and layout

* feat: Add RevokeAllKeys component and update styling for buttons and inputs

* feat: Refactor ClearChats component and update ClearConvos functionality for improved clarity and user experience

* feat: Remove ClearConvos component and update related imports and functionality in Avatar and DeleteCacheButton components

* feat: Rename DeleteCacheButton to DeleteCache and update related imports; enhance confirmation message in localization

* feat: Update ChatForm layout for RTL support and improve component structure

* feat: Adjust ChatForm layout for improved RTL support and alignment

* feat: Refactor Bookmark components to use new UI elements and improve styling

* feat: Update FileSearch and ShareAgent components for improved button styling and layout

* feat: Update ChatForm and TextareaHeader styles for improved UI consistency

* feat: Refactor Nav components for improved styling and layout adjustments

* feat: Update button sizes and padding for improved UI consistency across chat components

* feat: Remove ClearChatsButton test file as part of code cleanup
2024-10-19 08:30:52 -04:00

91 lines
2.5 KiB
TypeScript

import { useEffect } from 'react';
import { ListeningIcon, Spinner } from '~/components/svg';
import { useLocalize, useSpeechToText } from '~/hooks';
import { useChatFormContext } from '~/Providers';
import { TooltipAnchor } from '~/components/ui';
import { globalAudioId } from '~/common';
import { cn } from '~/utils';
export default function AudioRecorder({
textAreaRef,
methods,
ask,
isRTL,
disabled,
}: {
textAreaRef: React.RefObject<HTMLTextAreaElement>;
methods: ReturnType<typeof useChatFormContext>;
ask: (data: { text: string }) => void;
isRTL: boolean;
disabled: boolean;
}) {
const localize = useLocalize();
const handleTranscriptionComplete = (text: string) => {
if (text) {
const globalAudio = document.getElementById(globalAudioId) as HTMLAudioElement;
if (globalAudio) {
console.log('Unmuting global audio');
globalAudio.muted = false;
}
ask({ text });
methods.reset({ text: '' });
clearText();
}
};
const {
isListening,
isLoading,
startRecording,
stopRecording,
interimTranscript,
speechText,
clearText,
} = useSpeechToText(handleTranscriptionComplete);
useEffect(() => {
if (isListening && textAreaRef.current) {
methods.setValue('text', interimTranscript, {
shouldValidate: true,
});
} else if (textAreaRef.current) {
textAreaRef.current.value = speechText;
methods.setValue('text', speechText, { shouldValidate: true });
}
}, [interimTranscript, speechText, methods, textAreaRef]);
const handleStartRecording = async () => {
await startRecording();
};
const handleStopRecording = async () => {
await stopRecording();
};
const renderIcon = () => {
if (isListening) {
return <ListeningIcon className="stroke-red-500" />;
}
if (isLoading) {
return <Spinner className="stroke-gray-700 dark:stroke-gray-300" />;
}
return <ListeningIcon className="stroke-gray-700 dark:stroke-gray-300" />;
};
return (
<TooltipAnchor
id="audio-recorder"
aria-label={localize('com_ui_use_micrphone')}
onClick={isListening ? handleStopRecording : handleStartRecording}
disabled={disabled}
className={cn(
'absolute flex size-[35px] items-center justify-center rounded-full p-1 transition-colors hover:bg-surface-hover',
isRTL ? 'bottom-2 left-2' : 'bottom-2 right-2',
)}
description={localize('com_ui_use_micrphone')}
>
{renderIcon()}
</TooltipAnchor>
);
}