| | import { useCallback, useMemo } from 'react'; |
| | import { ContentTypes } from 'librechat-data-provider'; |
| | import { useQueryClient } from '@tanstack/react-query'; |
| |
|
| | import type { |
| | Text, |
| | TMessage, |
| | ImageFile, |
| | ContentPart, |
| | PartMetadata, |
| | TContentData, |
| | EventSubmission, |
| | TMessageContentParts, |
| | } from 'librechat-data-provider'; |
| | import { addFileToCache } from '~/utils'; |
| |
|
| | type TUseContentHandler = { |
| | setMessages: (messages: TMessage[]) => void; |
| | getMessages: () => TMessage[] | undefined; |
| | }; |
| |
|
| | type TContentHandler = { |
| | data: TContentData; |
| | submission: EventSubmission; |
| | }; |
| |
|
| | export default function useContentHandler({ setMessages, getMessages }: TUseContentHandler) { |
| | const queryClient = useQueryClient(); |
| | const messageMap = useMemo(() => new Map<string, TMessage>(), []); |
| | return useCallback( |
| | ({ data, submission }: TContentHandler) => { |
| | const { type, messageId, thread_id, conversationId, index } = data; |
| |
|
| | const _messages = getMessages(); |
| | const messages = |
| | _messages?.filter((m) => m.messageId !== messageId).map((msg) => ({ ...msg, thread_id })) ?? |
| | []; |
| | const userMessage = messages[messages.length - 1] as TMessage | undefined; |
| |
|
| | const { initialResponse } = submission; |
| |
|
| | let response = messageMap.get(messageId); |
| | if (!response) { |
| | response = { |
| | ...(initialResponse as TMessage), |
| | parentMessageId: userMessage?.messageId ?? '', |
| | conversationId, |
| | messageId, |
| | thread_id, |
| | }; |
| | messageMap.set(messageId, response); |
| | } |
| |
|
| | |
| | const textPart: Text | string | undefined = data[ContentTypes.TEXT]; |
| | const part: ContentPart = |
| | textPart != null && typeof textPart === 'string' ? { value: textPart } : data[type]; |
| |
|
| | if (type === ContentTypes.IMAGE_FILE) { |
| | addFileToCache(queryClient, part as ImageFile & PartMetadata); |
| | } |
| |
|
| | |
| | response.content = [...(response.content ?? [])]; |
| |
|
| | response.content[index] = { type, [type]: part } as TMessageContentParts; |
| |
|
| | const lastContentPart = response.content[response.content.length - 1]; |
| | const initialContentPart = initialResponse.content?.[0]; |
| | if ( |
| | type !== ContentTypes.TEXT && |
| | initialContentPart != null && |
| | lastContentPart != null && |
| | ((lastContentPart.type === ContentTypes.TOOL_CALL && |
| | lastContentPart[ContentTypes.TOOL_CALL]?.progress === 1) || |
| | lastContentPart.type === ContentTypes.IMAGE_FILE) |
| | ) { |
| | response.content.push(initialContentPart); |
| | } |
| |
|
| | setMessages([...messages, response]); |
| | }, |
| | [queryClient, getMessages, messageMap, setMessages], |
| | ); |
| | } |
| |
|