From bed77ee28fe23a78c7b3ea77f288563b3257d2f3 Mon Sep 17 00:00:00 2001 From: balibabu Date: Fri, 29 Aug 2025 18:36:40 +0800 Subject: [PATCH] Feat: Create a conversation before uploading files #3221 (#9832) ### What problem does this PR solve? Feat: Create a conversation before uploading files #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/hooks/use-chat-request.ts | 11 ++- .../hooks/use-create-conversation.ts | 10 +-- .../next-chats/hooks/use-send-chat-message.ts | 81 ++++++------------- .../next-chats/hooks/use-set-chat-route.ts | 25 ++++++ .../next-chats/hooks/use-set-conversation.ts | 35 ++++++++ .../pages/next-chats/hooks/use-upload-file.ts | 38 +++++---- 6 files changed, 118 insertions(+), 82 deletions(-) create mode 100644 web/src/pages/next-chats/hooks/use-set-chat-route.ts create mode 100644 web/src/pages/next-chats/hooks/use-set-conversation.ts diff --git a/web/src/hooks/use-chat-request.ts b/web/src/hooks/use-chat-request.ts index 6da7196d8..127b0e54b 100644 --- a/web/src/hooks/use-chat-request.ts +++ b/web/src/hooks/use-chat-request.ts @@ -398,10 +398,14 @@ export const useDeleteMessage = () => { type UploadParameters = Parameters>; -type X = { file: UploadParameters[0][0]; options: UploadParameters[1] }; +type X = { + file: UploadParameters[0][0]; + options: UploadParameters[1]; + conversationId?: string; +}; export function useUploadAndParseFile() { - const { conversationId } = useGetChatSearchParams(); + const { conversationId: id } = useGetChatSearchParams(); const { t } = useTranslation(); const controller = useRef(new AbortController()); @@ -414,11 +418,12 @@ export function useUploadAndParseFile() { mutationFn: async ({ file, options: { onProgress, onSuccess, onError }, + conversationId, }: X) => { try { const formData = new FormData(); formData.append('file', file); - formData.append('conversation_id', conversationId); + formData.append('conversation_id', conversationId || id); const { data } = await chatService.uploadAndParse( { diff --git a/web/src/pages/next-chats/hooks/use-create-conversation.ts b/web/src/pages/next-chats/hooks/use-create-conversation.ts index b27ec486d..3cf34cd01 100644 --- a/web/src/pages/next-chats/hooks/use-create-conversation.ts +++ b/web/src/pages/next-chats/hooks/use-create-conversation.ts @@ -1,13 +1,11 @@ -import { useGetChatSearchParams } from '@/hooks/use-chat-request'; import { useCallback } from 'react'; -import { - useSetChatRouteParams, - useSetConversation, -} from './use-send-chat-message'; +import { useParams } from 'umi'; +import { useSetChatRouteParams } from './use-set-chat-route'; +import { useSetConversation } from './use-set-conversation'; export const useCreateConversationBeforeUploadDocument = () => { const { setConversation } = useSetConversation(); - const { dialogId } = useGetChatSearchParams(); + const { id: dialogId } = useParams(); const { getConversationIsNew } = useSetChatRouteParams(); const createConversationBeforeUploadDocument = useCallback( diff --git a/web/src/pages/next-chats/hooks/use-send-chat-message.ts b/web/src/pages/next-chats/hooks/use-send-chat-message.ts index bb72d6ec7..94bc70cd4 100644 --- a/web/src/pages/next-chats/hooks/use-send-chat-message.ts +++ b/web/src/pages/next-chats/hooks/use-send-chat-message.ts @@ -1,4 +1,5 @@ -import { ChatSearchParams, MessageType } from '@/constants/chat'; +import { FileUploadProps } from '@/components/file-upload'; +import { MessageType } from '@/constants/chat'; import { useHandleMessageInputChange, useRegenerateMessage, @@ -8,40 +9,19 @@ import { import { useFetchConversation, useGetChatSearchParams, - useUpdateConversation, } from '@/hooks/use-chat-request'; import { Message } from '@/interfaces/database/chat'; import api from '@/utils/api'; import { trim } from 'lodash'; -import { useCallback, useEffect, useMemo } from 'react'; -import { useParams, useSearchParams } from 'umi'; +import { useCallback, useEffect } from 'react'; +import { useParams } from 'umi'; import { v4 as uuid } from 'uuid'; import { IMessage } from '../chat/interface'; import { useFindPrologueFromDialogList } from './use-select-conversation-list'; +import { useSetChatRouteParams } from './use-set-chat-route'; +import { useSetConversation } from './use-set-conversation'; import { useUploadFile } from './use-upload-file'; -export const useSetChatRouteParams = () => { - const [currentQueryParameters, setSearchParams] = useSearchParams(); - const newQueryParameters: URLSearchParams = useMemo( - () => new URLSearchParams(currentQueryParameters.toString()), - [currentQueryParameters], - ); - - const setConversationIsNew = useCallback( - (value: string) => { - newQueryParameters.set(ChatSearchParams.isNew, value); - setSearchParams(newQueryParameters); - }, - [newQueryParameters, setSearchParams], - ); - - const getConversationIsNew = useCallback(() => { - return newQueryParameters.get(ChatSearchParams.isNew); - }, [newQueryParameters]); - - return { setConversationIsNew, getConversationIsNew }; -}; - export const useSelectNextMessages = () => { const { scrollRef, @@ -102,37 +82,6 @@ export const useSelectNextMessages = () => { }; }; -export const useSetConversation = () => { - const { id: dialogId } = useParams(); - const { updateConversation } = useUpdateConversation(); - - const setConversation = useCallback( - async ( - message: string, - isNew: boolean = false, - conversationId?: string, - ) => { - const data = await updateConversation({ - dialog_id: dialogId, - name: message, - is_new: isNew, - conversation_id: conversationId, - message: [ - { - role: MessageType.Assistant, - content: message, - }, - ], - }); - - return data; - }, - [updateConversation, dialogId], - ); - - return { setConversation }; -}; - export const useSendMessage = (controller: AbortController) => { const { setConversation } = useSetConversation(); const { conversationId, isNew } = useGetChatSearchParams(); @@ -158,6 +107,22 @@ export const useSendMessage = (controller: AbortController) => { const { setConversationIsNew, getConversationIsNew } = useSetChatRouteParams(); + const onUploadFile: NonNullable = useCallback( + async (files, options) => { + const isNew = getConversationIsNew(); + + if (isNew === 'true' && Array.isArray(files) && files.length) { + const data = await setConversation(files[0].name, true); + if (data.code === 0) { + handleUploadFile(files, options, data.data?.id); + } + } else { + handleUploadFile(files, options); + } + }, + [getConversationIsNew, handleUploadFile, setConversation], + ); + const stopOutputMessage = useCallback(() => { controller.abort(); }, [controller]); @@ -285,7 +250,7 @@ export const useSendMessage = (controller: AbortController) => { derivedMessages, removeMessageById, stopOutputMessage, - handleUploadFile, + handleUploadFile: onUploadFile, isUploading, removeFile, }; diff --git a/web/src/pages/next-chats/hooks/use-set-chat-route.ts b/web/src/pages/next-chats/hooks/use-set-chat-route.ts new file mode 100644 index 000000000..2389e69a4 --- /dev/null +++ b/web/src/pages/next-chats/hooks/use-set-chat-route.ts @@ -0,0 +1,25 @@ +import { ChatSearchParams } from '@/constants/chat'; +import { useCallback, useMemo } from 'react'; +import { useSearchParams } from 'umi'; + +export const useSetChatRouteParams = () => { + const [currentQueryParameters, setSearchParams] = useSearchParams(); + const newQueryParameters: URLSearchParams = useMemo( + () => new URLSearchParams(currentQueryParameters.toString()), + [currentQueryParameters], + ); + + const setConversationIsNew = useCallback( + (value: string) => { + newQueryParameters.set(ChatSearchParams.isNew, value); + setSearchParams(newQueryParameters); + }, + [newQueryParameters, setSearchParams], + ); + + const getConversationIsNew = useCallback(() => { + return newQueryParameters.get(ChatSearchParams.isNew); + }, [newQueryParameters]); + + return { setConversationIsNew, getConversationIsNew }; +}; diff --git a/web/src/pages/next-chats/hooks/use-set-conversation.ts b/web/src/pages/next-chats/hooks/use-set-conversation.ts new file mode 100644 index 000000000..9f3ac2f81 --- /dev/null +++ b/web/src/pages/next-chats/hooks/use-set-conversation.ts @@ -0,0 +1,35 @@ +import { MessageType } from '@/constants/chat'; +import { useUpdateConversation } from '@/hooks/use-chat-request'; +import { useCallback } from 'react'; +import { useParams } from 'umi'; + +export const useSetConversation = () => { + const { id: dialogId } = useParams(); + const { updateConversation } = useUpdateConversation(); + + const setConversation = useCallback( + async ( + message: string, + isNew: boolean = false, + conversationId?: string, + ) => { + const data = await updateConversation({ + dialog_id: dialogId, + name: message, + is_new: isNew, + conversation_id: conversationId, + message: [ + { + role: MessageType.Assistant, + content: message, + }, + ], + }); + + return data; + }, + [updateConversation, dialogId], + ); + + return { setConversation }; +}; diff --git a/web/src/pages/next-chats/hooks/use-upload-file.ts b/web/src/pages/next-chats/hooks/use-upload-file.ts index 8f9e1e810..164366f0f 100644 --- a/web/src/pages/next-chats/hooks/use-upload-file.ts +++ b/web/src/pages/next-chats/hooks/use-upload-file.ts @@ -7,22 +7,30 @@ export function useUploadFile() { const [fileIds, setFileIds] = useState([]); const [fileMap, setFileMap] = useState>(new Map()); - const handleUploadFile: NonNullable = - useCallback( - async (files, options) => { - if (Array.isArray(files) && files.length) { - const ret = await uploadAndParseFile({ file: files[0], options }); - if (ret.code === 0 && Array.isArray(ret.data)) { - setFileIds((list) => [...list, ...ret.data]); - setFileMap((map) => { - map.set(files[0], ret.data[0]); - return map; - }); - } + type FileUploadParameters = Parameters< + NonNullable + >; + + const handleUploadFile = useCallback( + async ( + files: FileUploadParameters[0], + options: FileUploadParameters[1], + conversationId?: string, + ) => { + if (Array.isArray(files) && files.length) { + const file = files[0]; + const ret = await uploadAndParseFile({ file, options, conversationId }); + if (ret.code === 0 && Array.isArray(ret.data)) { + setFileIds((list) => [...list, ...ret.data]); + setFileMap((map) => { + map.set(files[0], ret.data[0]); + return map; + }); } - }, - [uploadAndParseFile], - ); + } + }, + [uploadAndParseFile], + ); const clearFileIds = useCallback(() => { setFileIds([]);