diff --git a/web/src/components/message-item/group-button.tsx b/web/src/components/message-item/group-button.tsx index 0742ceff763..4a253771c5a 100644 --- a/web/src/components/message-item/group-button.tsx +++ b/web/src/components/message-item/group-button.tsx @@ -77,11 +77,16 @@ export const AssistantGroupButton = ({ ); }; -export const UserGroupButton = () => { +interface UserGroupButtonProps { + messageId: string; + content: string; +} + +export const UserGroupButton = ({ content }: UserGroupButtonProps) => { return ( - + diff --git a/web/src/components/message-item/index.tsx b/web/src/components/message-item/index.tsx index 9e0fff79457..99dfa31d246 100644 --- a/web/src/components/message-item/index.tsx +++ b/web/src/components/message-item/index.tsx @@ -30,6 +30,7 @@ interface IProps { nickname?: string; avatar?: string; clickDocumentButton?: (documentId: string, chunk: IChunk) => void; + index: number; } const MessageItem = ({ @@ -38,6 +39,7 @@ const MessageItem = ({ loading = false, avatar = '', clickDocumentButton, + index, }: IProps) => { const isAssistant = item.role === MessageType.Assistant; const isUser = item.role === MessageType.User; @@ -112,13 +114,18 @@ const MessageItem = ({ {isAssistant ? ( - + index !== 0 && ( + + ) ) : ( - + )} {/* {isAssistant ? '' : nickname} */} diff --git a/web/src/hooks/chat-hooks.ts b/web/src/hooks/chat-hooks.ts index 2f2eb11f944..452c80a31a1 100644 --- a/web/src/hooks/chat-hooks.ts +++ b/web/src/hooks/chat-hooks.ts @@ -14,9 +14,19 @@ import { buildMessageUuid, isConversationIdExist } from '@/utils/chat'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { message } from 'antd'; import dayjs, { Dayjs } from 'dayjs'; +import { set } from 'lodash'; import { useCallback, useMemo, useState } from 'react'; import { useSearchParams } from 'umi'; +const buildMessageListWithUuid = (messages?: Message[]) => { + return ( + messages?.map((x: Message | IMessage) => ({ + ...x, + id: buildMessageUuid(x), + })) ?? [] + ); +}; + //#region logic export const useClickDialogCard = () => { @@ -215,11 +225,7 @@ export const useFetchNextConversation = () => { // } const conversation = data?.data ?? {}; - const messageList = - conversation?.message?.map((x: Message | IMessage) => ({ - ...x, - id: buildMessageUuid(x), - })) ?? []; + const messageList = buildMessageListWithUuid(conversation?.message); return { ...conversation, message: messageList }; } @@ -294,7 +300,6 @@ export const useRemoveNextConversation = () => { }; export const useDeleteMessage = () => { - // const queryClient = useQueryClient(); const { conversationId } = useGetChatSearchParams(); const { @@ -308,9 +313,7 @@ export const useDeleteMessage = () => { messageId, conversationId, }); - if (data.retcode === 0) { - // queryClient.invalidateQueries({ queryKey: ['fetchConversationList'] }); - } + return data.retcode; }, }); @@ -471,6 +474,10 @@ export const useFetchNextSharedConversation = () => { conversationId, ); + const messageList = buildMessageListWithUuid(data?.data?.message); + + set(data, 'data.message', messageList); + return data; }, }); diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index 06388e55c4a..a584bf06d3d 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -68,6 +68,7 @@ const ChatContainer = () => { avatar={userInfo.avatar} reference={buildMessageItemReference(conversation, message)} clickDocumentButton={clickDocumentButton} + index={i} > ); })} diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts index b0bb6862716..13702b744e8 100644 --- a/web/src/pages/chat/hooks.ts +++ b/web/src/pages/chat/hooks.ts @@ -26,9 +26,9 @@ import { } from '@/interfaces/database/chat'; import { IChunk } from '@/interfaces/database/knowledge'; import { getFileExtension } from '@/utils'; +import { buildMessageUuid } from '@/utils/chat'; import { useMutationState } from '@tanstack/react-query'; import { get } from 'lodash'; -import omit from 'lodash/omit'; import trim from 'lodash/trim'; import { ChangeEventHandler, @@ -252,23 +252,22 @@ export const useSelectCurrentConversation = () => { const { data: dialog } = useFetchNextDialog(); const { conversationId, dialogId } = useGetChatSearchParams(); + // Show the entered message in the conversation immediately after sending the message const addNewestConversation = useCallback( - (message: Partial, answer: string = '') => { + (message: Message, answer: string = '') => { setCurrentConversation((pre) => { return { ...pre, message: [ ...pre.message, { - role: MessageType.User, - content: message.content, - doc_ids: message.doc_ids, - id: uuid(), + ...message, + id: buildMessageUuid(message), } as IMessage, { role: MessageType.Assistant, content: answer, - id: uuid(), + id: buildMessageUuid({ ...message, role: MessageType.Assistant }), reference: {}, } as IMessage, ], @@ -278,6 +277,7 @@ export const useSelectCurrentConversation = () => { [], ); + // Add the streaming message to the last item in the message list const addNewestAnswer = useCallback((answer: IAnswer) => { setCurrentConversation((pre) => { const latestMessage = pre.message?.at(-1); @@ -291,6 +291,11 @@ export const useSelectCurrentConversation = () => { ...latestMessage, content: answer.answer, reference: answer.reference, + id: buildMessageUuid({ + id: answer.id, + role: MessageType.Assistant, + }), + prompt: answer.prompt, } as IMessage, ], }; @@ -415,15 +420,13 @@ export const useSendMessage = ( const { send, answer, done, setDone } = useSendMessageWithSse(); const sendMessage = useCallback( - async (message: string, documentIds: string[], id?: string) => { + async (message: Message, documentIds: string[], id?: string) => { const res = await send({ conversation_id: id ?? conversationId, messages: [ - ...(conversation?.message ?? []).map((x: IMessage) => omit(x, 'id')), + ...(conversation?.message ?? []), { - id: uuid(), - role: MessageType.User, - content: message, + ...message, doc_ids: documentIds, }, ], @@ -431,7 +434,7 @@ export const useSendMessage = ( if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) { // cancel loading - setValue(message); + setValue(message.content); console.info('removeLatestMessage111'); removeLatestMessage(); } else { @@ -456,11 +459,11 @@ export const useSendMessage = ( ); const handleSendMessage = useCallback( - async (message: string, documentIds: string[]) => { + async (message: Message, documentIds: string[]) => { if (conversationId !== '') { sendMessage(message, documentIds); } else { - const data = await setConversation(message); + const data = await setConversation(message.content); if (data.retcode === 0) { const id = data.data.id; sendMessage(message, documentIds, id); @@ -487,11 +490,20 @@ export const useSendMessage = ( const handlePressEnter = useCallback( (documentIds: string[]) => { if (trim(value) === '') return; + const id = uuid(); - addNewestConversation({ content: value, doc_ids: documentIds }); + addNewestConversation({ + content: value, + doc_ids: documentIds, + id, + role: MessageType.User, + }); if (done) { setValue(''); - handleSendMessage(value.trim(), documentIds); + handleSendMessage( + { id, content: value.trim(), role: MessageType.User }, + documentIds, + ); } }, [addNewestConversation, handleSendMessage, done, setValue, value], diff --git a/web/src/pages/chat/markdown-content/index.tsx b/web/src/pages/chat/markdown-content/index.tsx index 6a82fe4333c..57a2e4e5ccc 100644 --- a/web/src/pages/chat/markdown-content/index.tsx +++ b/web/src/pages/chat/markdown-content/index.tsx @@ -134,8 +134,8 @@ const MarkdownContent = ({ let replacedText = reactStringReplace(text, reg, (match, i) => { const chunkIndex = getChunkIndex(match); return ( - - + + ); }); diff --git a/web/src/pages/chat/share/large.tsx b/web/src/pages/chat/share/large.tsx index 36542eef46f..b28f00d989c 100644 --- a/web/src/pages/chat/share/large.tsx +++ b/web/src/pages/chat/share/large.tsx @@ -58,6 +58,7 @@ const ChatContainer = () => { sendLoading && conversation?.message.length - 1 === i } + index={i} > ); })} diff --git a/web/src/pages/chat/shared-hooks.ts b/web/src/pages/chat/shared-hooks.ts index 219728818c5..a8e52e602d1 100644 --- a/web/src/pages/chat/shared-hooks.ts +++ b/web/src/pages/chat/shared-hooks.ts @@ -6,7 +6,7 @@ import { import { useSendMessageWithSse } from '@/hooks/logic-hooks'; import { IAnswer, Message } from '@/interfaces/database/chat'; import api from '@/utils/api'; -import omit from 'lodash/omit'; +import { buildMessageUuid } from '@/utils/chat'; import trim from 'lodash/trim'; import { Dispatch, @@ -60,15 +60,13 @@ export const useSelectCurrentSharedConversation = (conversationId: string) => { message: [ ...(pre.message ?? []), { - role: MessageType.User, - content: message.content, - doc_ids: message.doc_ids, - id: uuid(), + ...message, + id: buildMessageUuid(message), } as IMessage, { role: MessageType.Assistant, content: '', - id: uuid(), + id: buildMessageUuid({ ...message, role: MessageType.Assistant }), reference: {}, } as IMessage, ], @@ -89,6 +87,11 @@ export const useSelectCurrentSharedConversation = (conversationId: string) => { ...latestMessage, content: answer.answer, reference: answer.reference, + id: buildMessageUuid({ + id: answer.id, + role: MessageType.Assistant, + }), + prompt: answer.prompt, } as IMessage, ], }; @@ -152,22 +155,16 @@ export const useSendSharedMessage = ( ); const sendMessage = useCallback( - async (message: string, id?: string) => { + async (message: Message, id?: string) => { const res = await send({ conversation_id: id ?? conversationId, quote: false, - messages: [ - ...(conversation?.message ?? []).map((x: IMessage) => omit(x, 'id')), - { - role: MessageType.User, - content: message, - }, - ], + messages: [...(conversation?.message ?? []), message], }); if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) { // cancel loading - setValue(message); + setValue(message.content); removeLatestMessage(); } }, @@ -183,7 +180,7 @@ export const useSendSharedMessage = ( ); const handleSendMessage = useCallback( - async (message: string) => { + async (message: Message) => { if (conversationId !== '') { sendMessage(message); } else { @@ -206,10 +203,20 @@ export const useSendSharedMessage = ( const handlePressEnter = useCallback( (documentIds: string[]) => { if (trim(value) === '') return; + const id = uuid(); if (done) { setValue(''); - addNewestConversation({ content: value, doc_ids: documentIds }); - handleSendMessage(value.trim()); + addNewestConversation({ + content: value, + doc_ids: documentIds, + id, + role: MessageType.User, + }); + handleSendMessage({ + content: value.trim(), + id, + role: MessageType.User, + }); } }, [addNewestConversation, done, handleSendMessage, setValue, value], diff --git a/web/src/pages/flow/chat/box.tsx b/web/src/pages/flow/chat/box.tsx index 6d072b9eee9..a88e3774a26 100644 --- a/web/src/pages/flow/chat/box.tsx +++ b/web/src/pages/flow/chat/box.tsx @@ -57,6 +57,7 @@ const FlowChatBox = () => { message, )} clickDocumentButton={clickDocumentButton} + index={i} > ); })} diff --git a/web/src/pages/flow/chat/hooks.ts b/web/src/pages/flow/chat/hooks.ts index 947fd22618b..478dd431cfd 100644 --- a/web/src/pages/flow/chat/hooks.ts +++ b/web/src/pages/flow/chat/hooks.ts @@ -5,10 +5,12 @@ import { useScrollToBottom, useSendMessageWithSse, } from '@/hooks/logic-hooks'; -import { IAnswer } from '@/interfaces/database/chat'; +import { IAnswer, Message } from '@/interfaces/database/chat'; import { IMessage } from '@/pages/chat/interface'; import api from '@/utils/api'; +import { buildMessageUuid } from '@/utils/chat'; import { message } from 'antd'; +import trim from 'lodash/trim'; import { useCallback, useEffect, useState } from 'react'; import { useParams } from 'umi'; import { v4 as uuid } from 'uuid'; @@ -27,19 +29,18 @@ export const useSelectCurrentMessages = () => { const ref = useScrollToBottom(currentMessages); const addNewestQuestion = useCallback( - (message: string, answer: string = '') => { + (message: Message, answer: string = '') => { setCurrentMessages((pre) => { return [ ...pre, { - role: MessageType.User, - content: message, - id: uuid(), + ...message, + id: buildMessageUuid(message), }, { role: MessageType.Assistant, content: answer, - id: uuid(), + id: buildMessageUuid({ ...message, role: MessageType.Assistant }), }, ]; }); @@ -52,10 +53,13 @@ export const useSelectCurrentMessages = () => { return [ ...pre.slice(0, -1), { - id: uuid(), role: MessageType.Assistant, content: answer.answer, reference: answer.reference, + id: buildMessageUuid({ + id: answer.id, + role: MessageType.Assistant, + }), }, ]; }); @@ -88,7 +92,7 @@ export const useSelectCurrentMessages = () => { }; export const useSendMessage = ( - addNewestQuestion: (message: string, answer?: string) => void, + addNewestQuestion: (message: Message, answer?: string) => void, removeLatestMessage: () => void, addNewestAnswer: (answer: IAnswer) => void, ) => { @@ -99,12 +103,13 @@ export const useSendMessage = ( const { send, answer, done } = useSendMessageWithSse(api.runCanvas); const sendMessage = useCallback( - async (message: string) => { + async (message: Message) => { const params: Record = { id: flowId, }; - if (message) { - params.message = message; + if (message.content) { + params.message = message.content; + params.message_id = message.id; } const res = await send(params); @@ -112,7 +117,7 @@ export const useSendMessage = ( antMessage.error(res?.data?.retmsg); // cancel loading - setValue(message); + setValue(message.content); removeLatestMessage(); } else { refetch(); // pull the message list after sending the message successfully @@ -122,7 +127,7 @@ export const useSendMessage = ( ); const handleSendMessage = useCallback( - async (message: string) => { + async (message: Message) => { sendMessage(message); }, [sendMessage], @@ -135,11 +140,17 @@ export const useSendMessage = ( }, [answer, addNewestAnswer]); const handlePressEnter = useCallback(() => { + if (trim(value) === '') return; + const id = uuid(); if (done) { setValue(''); - handleSendMessage(value.trim()); + handleSendMessage({ id, content: value.trim(), role: MessageType.User }); } - addNewestQuestion(value); + addNewestQuestion({ + content: value, + id, + role: MessageType.User, + }); }, [addNewestQuestion, handleSendMessage, done, setValue, value]); return { diff --git a/web/src/utils/chat.ts b/web/src/utils/chat.ts index 8d850845621..38312c3c34c 100644 --- a/web/src/utils/chat.ts +++ b/web/src/utils/chat.ts @@ -7,7 +7,7 @@ export const isConversationIdExist = (conversationId: string) => { return conversationId !== EmptyConversationId && conversationId !== ''; }; -export const buildMessageUuid = (message: Message | IMessage) => { +export const buildMessageUuid = (message: Partial) => { if ('id' in message && message.id) { return message.role === MessageType.User ? `${MessageType.User}_${message.id}`