mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-06 02:28:51 +01:00
✨ feat: Add WebSocket functionality and integrate call features in the chat component
This commit is contained in:
parent
6b90817ae0
commit
d5bc8d3869
21 changed files with 460 additions and 20 deletions
52
client/src/components/Chat/Input/Call.tsx
Normal file
52
client/src/components/Chat/Input/Call.tsx
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import { useRecoilState } from 'recoil';
|
||||
import { Mic, Phone, PhoneOff } from 'lucide-react';
|
||||
import { OGDialog, OGDialogContent, Button } from '~/components';
|
||||
import { useWebRTC, useWebSocket, useCall } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
||||
export const Call: React.FC = () => {
|
||||
const { isConnected } = useWebSocket();
|
||||
const { isCalling, startCall, hangUp } = useCall();
|
||||
|
||||
const [open, setOpen] = useRecoilState(store.callDialogOpen(0));
|
||||
|
||||
return (
|
||||
<OGDialog open={open} onOpenChange={setOpen}>
|
||||
<OGDialogContent className="w-96 p-8">
|
||||
<div className="flex flex-col items-center gap-6">
|
||||
<div
|
||||
className={`flex items-center gap-2 rounded-full px-4 py-2 ${
|
||||
isConnected ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${isConnected ? 'bg-green-500' : 'bg-red-500'}`}
|
||||
/>
|
||||
<span className="text-sm font-medium">
|
||||
{isConnected ? 'Connected' : 'Disconnected'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{!isCalling ? (
|
||||
<Button
|
||||
onClick={startCall}
|
||||
disabled={!isConnected}
|
||||
className="flex items-center gap-2 rounded-full bg-green-500 px-6 py-3 text-white hover:bg-green-600 disabled:opacity-50"
|
||||
>
|
||||
<Phone size={20} />
|
||||
<span>Start Call</span>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={hangUp}
|
||||
className="flex items-center gap-2 rounded-full bg-red-500 px-6 py-3 text-white hover:bg-red-600"
|
||||
>
|
||||
<PhoneOff size={20} />
|
||||
<span>End Call</span>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</OGDialogContent>
|
||||
</OGDialog>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import { useWatch } from 'react-hook-form';
|
||||
import { memo, useRef, useMemo, useEffect, useState } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import {
|
||||
|
|
@ -32,10 +31,10 @@ import AudioRecorder from './AudioRecorder';
|
|||
import { mainTextareaId } from '~/common';
|
||||
import CollapseChat from './CollapseChat';
|
||||
import StreamAudio from './StreamAudio';
|
||||
import CallButton from './CallButton';
|
||||
import StopButton from './StopButton';
|
||||
import SendButton from './SendButton';
|
||||
import Mention from './Mention';
|
||||
import { Call } from './Call';
|
||||
import store from '~/store';
|
||||
|
||||
const ChatForm = ({ index = 0 }) => {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import React, { forwardRef } from 'react';
|
||||
import { useWatch } from 'react-hook-form';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import type { TRealtimeEphemeralTokenResponse } from 'librechat-data-provider';
|
||||
import type { Control } from 'react-hook-form';
|
||||
import { useRealtimeEphemeralTokenMutation } from '~/data-provider';
|
||||
import { TooltipAnchor, SendIcon, CallIcon } from '~/components';
|
||||
import { useToastContext } from '~/Providers/ToastContext';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import store from '~/store';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
type ButtonProps = {
|
||||
|
|
@ -56,25 +58,27 @@ const SendButton = forwardRef((props: ButtonProps, ref: React.ForwardedRef<HTMLB
|
|||
const localize = useLocalize();
|
||||
const { showToast } = useToastContext();
|
||||
const { text = '' } = useWatch({ control: props.control });
|
||||
const setCallOpen = useSetRecoilState(store.callDialogOpen(0));
|
||||
|
||||
const { mutate: startCall, isLoading: isProcessing } = useRealtimeEphemeralTokenMutation({
|
||||
onSuccess: async (data: TRealtimeEphemeralTokenResponse) => {
|
||||
showToast({
|
||||
message: 'IT WORKS!!',
|
||||
status: 'success',
|
||||
});
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
showToast({
|
||||
message: localize('com_nav_audio_process_error', (error as Error).message),
|
||||
status: 'error',
|
||||
});
|
||||
},
|
||||
});
|
||||
// const { mutate: startCall, isLoading: isProcessing } = useRealtimeEphemeralTokenMutation({
|
||||
// onSuccess: async (data: TRealtimeEphemeralTokenResponse) => {
|
||||
// showToast({
|
||||
// message: 'IT WORKS!!',
|
||||
// status: 'success',
|
||||
// });
|
||||
// },
|
||||
// onError: (error: unknown) => {
|
||||
// showToast({
|
||||
// message: localize('com_nav_audio_process_error', (error as Error).message),
|
||||
// status: 'error',
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
|
||||
const handleClick = () => {
|
||||
if (text.trim() === '') {
|
||||
startCall({ voice: 'verse' });
|
||||
setCallOpen(true);
|
||||
// startCall({ voice: 'verse' });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue