feat: Send message with uuid #2088 (#2149)

### What problem does this PR solve?

feat: Send message with uuid #2088

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu 2024-08-29 11:24:27 +08:00 committed by GitHub
parent 4bd6c3145c
commit 1eb6286339
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 122 additions and 70 deletions

View File

@ -77,11 +77,16 @@ export const AssistantGroupButton = ({
); );
}; };
export const UserGroupButton = () => { interface UserGroupButtonProps {
messageId: string;
content: string;
}
export const UserGroupButton = ({ content }: UserGroupButtonProps) => {
return ( return (
<Radio.Group size="small"> <Radio.Group size="small">
<Radio.Button value="a"> <Radio.Button value="a">
<CopyToClipboard text="xxx"></CopyToClipboard> <CopyToClipboard text={content}></CopyToClipboard>
</Radio.Button> </Radio.Button>
<Radio.Button value="b"> <Radio.Button value="b">
<SyncOutlined /> <SyncOutlined />

View File

@ -30,6 +30,7 @@ interface IProps {
nickname?: string; nickname?: string;
avatar?: string; avatar?: string;
clickDocumentButton?: (documentId: string, chunk: IChunk) => void; clickDocumentButton?: (documentId: string, chunk: IChunk) => void;
index: number;
} }
const MessageItem = ({ const MessageItem = ({
@ -38,6 +39,7 @@ const MessageItem = ({
loading = false, loading = false,
avatar = '', avatar = '',
clickDocumentButton, clickDocumentButton,
index,
}: IProps) => { }: IProps) => {
const isAssistant = item.role === MessageType.Assistant; const isAssistant = item.role === MessageType.Assistant;
const isUser = item.role === MessageType.User; const isUser = item.role === MessageType.User;
@ -112,13 +114,18 @@ const MessageItem = ({
<Flex vertical gap={8} flex={1}> <Flex vertical gap={8} flex={1}>
<Space> <Space>
{isAssistant ? ( {isAssistant ? (
<AssistantGroupButton index !== 0 && (
messageId={item.id} <AssistantGroupButton
content={item.content} messageId={item.id}
prompt={item.prompt} content={item.content}
></AssistantGroupButton> prompt={item.prompt}
></AssistantGroupButton>
)
) : ( ) : (
<UserGroupButton></UserGroupButton> <UserGroupButton
content={item.content}
messageId={item.id}
></UserGroupButton>
)} )}
{/* <b>{isAssistant ? '' : nickname}</b> */} {/* <b>{isAssistant ? '' : nickname}</b> */}

View File

@ -14,9 +14,19 @@ import { buildMessageUuid, isConversationIdExist } from '@/utils/chat';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { message } from 'antd'; import { message } from 'antd';
import dayjs, { Dayjs } from 'dayjs'; import dayjs, { Dayjs } from 'dayjs';
import { set } from 'lodash';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useSearchParams } from 'umi'; import { useSearchParams } from 'umi';
const buildMessageListWithUuid = (messages?: Message[]) => {
return (
messages?.map((x: Message | IMessage) => ({
...x,
id: buildMessageUuid(x),
})) ?? []
);
};
//#region logic //#region logic
export const useClickDialogCard = () => { export const useClickDialogCard = () => {
@ -215,11 +225,7 @@ export const useFetchNextConversation = () => {
// } // }
const conversation = data?.data ?? {}; const conversation = data?.data ?? {};
const messageList = const messageList = buildMessageListWithUuid(conversation?.message);
conversation?.message?.map((x: Message | IMessage) => ({
...x,
id: buildMessageUuid(x),
})) ?? [];
return { ...conversation, message: messageList }; return { ...conversation, message: messageList };
} }
@ -294,7 +300,6 @@ export const useRemoveNextConversation = () => {
}; };
export const useDeleteMessage = () => { export const useDeleteMessage = () => {
// const queryClient = useQueryClient();
const { conversationId } = useGetChatSearchParams(); const { conversationId } = useGetChatSearchParams();
const { const {
@ -308,9 +313,7 @@ export const useDeleteMessage = () => {
messageId, messageId,
conversationId, conversationId,
}); });
if (data.retcode === 0) {
// queryClient.invalidateQueries({ queryKey: ['fetchConversationList'] });
}
return data.retcode; return data.retcode;
}, },
}); });
@ -471,6 +474,10 @@ export const useFetchNextSharedConversation = () => {
conversationId, conversationId,
); );
const messageList = buildMessageListWithUuid(data?.data?.message);
set(data, 'data.message', messageList);
return data; return data;
}, },
}); });

View File

@ -68,6 +68,7 @@ const ChatContainer = () => {
avatar={userInfo.avatar} avatar={userInfo.avatar}
reference={buildMessageItemReference(conversation, message)} reference={buildMessageItemReference(conversation, message)}
clickDocumentButton={clickDocumentButton} clickDocumentButton={clickDocumentButton}
index={i}
></MessageItem> ></MessageItem>
); );
})} })}

View File

@ -26,9 +26,9 @@ import {
} from '@/interfaces/database/chat'; } from '@/interfaces/database/chat';
import { IChunk } from '@/interfaces/database/knowledge'; import { IChunk } from '@/interfaces/database/knowledge';
import { getFileExtension } from '@/utils'; import { getFileExtension } from '@/utils';
import { buildMessageUuid } from '@/utils/chat';
import { useMutationState } from '@tanstack/react-query'; import { useMutationState } from '@tanstack/react-query';
import { get } from 'lodash'; import { get } from 'lodash';
import omit from 'lodash/omit';
import trim from 'lodash/trim'; import trim from 'lodash/trim';
import { import {
ChangeEventHandler, ChangeEventHandler,
@ -252,23 +252,22 @@ export const useSelectCurrentConversation = () => {
const { data: dialog } = useFetchNextDialog(); const { data: dialog } = useFetchNextDialog();
const { conversationId, dialogId } = useGetChatSearchParams(); const { conversationId, dialogId } = useGetChatSearchParams();
// Show the entered message in the conversation immediately after sending the message
const addNewestConversation = useCallback( const addNewestConversation = useCallback(
(message: Partial<Message>, answer: string = '') => { (message: Message, answer: string = '') => {
setCurrentConversation((pre) => { setCurrentConversation((pre) => {
return { return {
...pre, ...pre,
message: [ message: [
...pre.message, ...pre.message,
{ {
role: MessageType.User, ...message,
content: message.content, id: buildMessageUuid(message),
doc_ids: message.doc_ids,
id: uuid(),
} as IMessage, } as IMessage,
{ {
role: MessageType.Assistant, role: MessageType.Assistant,
content: answer, content: answer,
id: uuid(), id: buildMessageUuid({ ...message, role: MessageType.Assistant }),
reference: {}, reference: {},
} as IMessage, } 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) => { const addNewestAnswer = useCallback((answer: IAnswer) => {
setCurrentConversation((pre) => { setCurrentConversation((pre) => {
const latestMessage = pre.message?.at(-1); const latestMessage = pre.message?.at(-1);
@ -291,6 +291,11 @@ export const useSelectCurrentConversation = () => {
...latestMessage, ...latestMessage,
content: answer.answer, content: answer.answer,
reference: answer.reference, reference: answer.reference,
id: buildMessageUuid({
id: answer.id,
role: MessageType.Assistant,
}),
prompt: answer.prompt,
} as IMessage, } as IMessage,
], ],
}; };
@ -415,15 +420,13 @@ export const useSendMessage = (
const { send, answer, done, setDone } = useSendMessageWithSse(); const { send, answer, done, setDone } = useSendMessageWithSse();
const sendMessage = useCallback( const sendMessage = useCallback(
async (message: string, documentIds: string[], id?: string) => { async (message: Message, documentIds: string[], id?: string) => {
const res = await send({ const res = await send({
conversation_id: id ?? conversationId, conversation_id: id ?? conversationId,
messages: [ messages: [
...(conversation?.message ?? []).map((x: IMessage) => omit(x, 'id')), ...(conversation?.message ?? []),
{ {
id: uuid(), ...message,
role: MessageType.User,
content: message,
doc_ids: documentIds, doc_ids: documentIds,
}, },
], ],
@ -431,7 +434,7 @@ export const useSendMessage = (
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) { if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
// cancel loading // cancel loading
setValue(message); setValue(message.content);
console.info('removeLatestMessage111'); console.info('removeLatestMessage111');
removeLatestMessage(); removeLatestMessage();
} else { } else {
@ -456,11 +459,11 @@ export const useSendMessage = (
); );
const handleSendMessage = useCallback( const handleSendMessage = useCallback(
async (message: string, documentIds: string[]) => { async (message: Message, documentIds: string[]) => {
if (conversationId !== '') { if (conversationId !== '') {
sendMessage(message, documentIds); sendMessage(message, documentIds);
} else { } else {
const data = await setConversation(message); const data = await setConversation(message.content);
if (data.retcode === 0) { if (data.retcode === 0) {
const id = data.data.id; const id = data.data.id;
sendMessage(message, documentIds, id); sendMessage(message, documentIds, id);
@ -487,11 +490,20 @@ export const useSendMessage = (
const handlePressEnter = useCallback( const handlePressEnter = useCallback(
(documentIds: string[]) => { (documentIds: string[]) => {
if (trim(value) === '') return; 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) { if (done) {
setValue(''); setValue('');
handleSendMessage(value.trim(), documentIds); handleSendMessage(
{ id, content: value.trim(), role: MessageType.User },
documentIds,
);
} }
}, },
[addNewestConversation, handleSendMessage, done, setValue, value], [addNewestConversation, handleSendMessage, done, setValue, value],

View File

@ -134,8 +134,8 @@ const MarkdownContent = ({
let replacedText = reactStringReplace(text, reg, (match, i) => { let replacedText = reactStringReplace(text, reg, (match, i) => {
const chunkIndex = getChunkIndex(match); const chunkIndex = getChunkIndex(match);
return ( return (
<Popover content={getPopoverContent(chunkIndex)}> <Popover content={getPopoverContent(chunkIndex)} key={i}>
<InfoCircleOutlined key={i} className={styles.referenceIcon} /> <InfoCircleOutlined className={styles.referenceIcon} />
</Popover> </Popover>
); );
}); });

View File

@ -58,6 +58,7 @@ const ChatContainer = () => {
sendLoading && sendLoading &&
conversation?.message.length - 1 === i conversation?.message.length - 1 === i
} }
index={i}
></MessageItem> ></MessageItem>
); );
})} })}

View File

@ -6,7 +6,7 @@ import {
import { useSendMessageWithSse } from '@/hooks/logic-hooks'; import { useSendMessageWithSse } from '@/hooks/logic-hooks';
import { IAnswer, Message } from '@/interfaces/database/chat'; import { IAnswer, Message } from '@/interfaces/database/chat';
import api from '@/utils/api'; import api from '@/utils/api';
import omit from 'lodash/omit'; import { buildMessageUuid } from '@/utils/chat';
import trim from 'lodash/trim'; import trim from 'lodash/trim';
import { import {
Dispatch, Dispatch,
@ -60,15 +60,13 @@ export const useSelectCurrentSharedConversation = (conversationId: string) => {
message: [ message: [
...(pre.message ?? []), ...(pre.message ?? []),
{ {
role: MessageType.User, ...message,
content: message.content, id: buildMessageUuid(message),
doc_ids: message.doc_ids,
id: uuid(),
} as IMessage, } as IMessage,
{ {
role: MessageType.Assistant, role: MessageType.Assistant,
content: '', content: '',
id: uuid(), id: buildMessageUuid({ ...message, role: MessageType.Assistant }),
reference: {}, reference: {},
} as IMessage, } as IMessage,
], ],
@ -89,6 +87,11 @@ export const useSelectCurrentSharedConversation = (conversationId: string) => {
...latestMessage, ...latestMessage,
content: answer.answer, content: answer.answer,
reference: answer.reference, reference: answer.reference,
id: buildMessageUuid({
id: answer.id,
role: MessageType.Assistant,
}),
prompt: answer.prompt,
} as IMessage, } as IMessage,
], ],
}; };
@ -152,22 +155,16 @@ export const useSendSharedMessage = (
); );
const sendMessage = useCallback( const sendMessage = useCallback(
async (message: string, id?: string) => { async (message: Message, id?: string) => {
const res = await send({ const res = await send({
conversation_id: id ?? conversationId, conversation_id: id ?? conversationId,
quote: false, quote: false,
messages: [ messages: [...(conversation?.message ?? []), message],
...(conversation?.message ?? []).map((x: IMessage) => omit(x, 'id')),
{
role: MessageType.User,
content: message,
},
],
}); });
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) { if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
// cancel loading // cancel loading
setValue(message); setValue(message.content);
removeLatestMessage(); removeLatestMessage();
} }
}, },
@ -183,7 +180,7 @@ export const useSendSharedMessage = (
); );
const handleSendMessage = useCallback( const handleSendMessage = useCallback(
async (message: string) => { async (message: Message) => {
if (conversationId !== '') { if (conversationId !== '') {
sendMessage(message); sendMessage(message);
} else { } else {
@ -206,10 +203,20 @@ export const useSendSharedMessage = (
const handlePressEnter = useCallback( const handlePressEnter = useCallback(
(documentIds: string[]) => { (documentIds: string[]) => {
if (trim(value) === '') return; if (trim(value) === '') return;
const id = uuid();
if (done) { if (done) {
setValue(''); setValue('');
addNewestConversation({ content: value, doc_ids: documentIds }); addNewestConversation({
handleSendMessage(value.trim()); content: value,
doc_ids: documentIds,
id,
role: MessageType.User,
});
handleSendMessage({
content: value.trim(),
id,
role: MessageType.User,
});
} }
}, },
[addNewestConversation, done, handleSendMessage, setValue, value], [addNewestConversation, done, handleSendMessage, setValue, value],

View File

@ -57,6 +57,7 @@ const FlowChatBox = () => {
message, message,
)} )}
clickDocumentButton={clickDocumentButton} clickDocumentButton={clickDocumentButton}
index={i}
></MessageItem> ></MessageItem>
); );
})} })}

View File

@ -5,10 +5,12 @@ import {
useScrollToBottom, useScrollToBottom,
useSendMessageWithSse, useSendMessageWithSse,
} from '@/hooks/logic-hooks'; } from '@/hooks/logic-hooks';
import { IAnswer } from '@/interfaces/database/chat'; import { IAnswer, Message } from '@/interfaces/database/chat';
import { IMessage } from '@/pages/chat/interface'; import { IMessage } from '@/pages/chat/interface';
import api from '@/utils/api'; import api from '@/utils/api';
import { buildMessageUuid } from '@/utils/chat';
import { message } from 'antd'; import { message } from 'antd';
import trim from 'lodash/trim';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'umi'; import { useParams } from 'umi';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
@ -27,19 +29,18 @@ export const useSelectCurrentMessages = () => {
const ref = useScrollToBottom(currentMessages); const ref = useScrollToBottom(currentMessages);
const addNewestQuestion = useCallback( const addNewestQuestion = useCallback(
(message: string, answer: string = '') => { (message: Message, answer: string = '') => {
setCurrentMessages((pre) => { setCurrentMessages((pre) => {
return [ return [
...pre, ...pre,
{ {
role: MessageType.User, ...message,
content: message, id: buildMessageUuid(message),
id: uuid(),
}, },
{ {
role: MessageType.Assistant, role: MessageType.Assistant,
content: answer, content: answer,
id: uuid(), id: buildMessageUuid({ ...message, role: MessageType.Assistant }),
}, },
]; ];
}); });
@ -52,10 +53,13 @@ export const useSelectCurrentMessages = () => {
return [ return [
...pre.slice(0, -1), ...pre.slice(0, -1),
{ {
id: uuid(),
role: MessageType.Assistant, role: MessageType.Assistant,
content: answer.answer, content: answer.answer,
reference: answer.reference, reference: answer.reference,
id: buildMessageUuid({
id: answer.id,
role: MessageType.Assistant,
}),
}, },
]; ];
}); });
@ -88,7 +92,7 @@ export const useSelectCurrentMessages = () => {
}; };
export const useSendMessage = ( export const useSendMessage = (
addNewestQuestion: (message: string, answer?: string) => void, addNewestQuestion: (message: Message, answer?: string) => void,
removeLatestMessage: () => void, removeLatestMessage: () => void,
addNewestAnswer: (answer: IAnswer) => void, addNewestAnswer: (answer: IAnswer) => void,
) => { ) => {
@ -99,12 +103,13 @@ export const useSendMessage = (
const { send, answer, done } = useSendMessageWithSse(api.runCanvas); const { send, answer, done } = useSendMessageWithSse(api.runCanvas);
const sendMessage = useCallback( const sendMessage = useCallback(
async (message: string) => { async (message: Message) => {
const params: Record<string, unknown> = { const params: Record<string, unknown> = {
id: flowId, id: flowId,
}; };
if (message) { if (message.content) {
params.message = message; params.message = message.content;
params.message_id = message.id;
} }
const res = await send(params); const res = await send(params);
@ -112,7 +117,7 @@ export const useSendMessage = (
antMessage.error(res?.data?.retmsg); antMessage.error(res?.data?.retmsg);
// cancel loading // cancel loading
setValue(message); setValue(message.content);
removeLatestMessage(); removeLatestMessage();
} else { } else {
refetch(); // pull the message list after sending the message successfully refetch(); // pull the message list after sending the message successfully
@ -122,7 +127,7 @@ export const useSendMessage = (
); );
const handleSendMessage = useCallback( const handleSendMessage = useCallback(
async (message: string) => { async (message: Message) => {
sendMessage(message); sendMessage(message);
}, },
[sendMessage], [sendMessage],
@ -135,11 +140,17 @@ export const useSendMessage = (
}, [answer, addNewestAnswer]); }, [answer, addNewestAnswer]);
const handlePressEnter = useCallback(() => { const handlePressEnter = useCallback(() => {
if (trim(value) === '') return;
const id = uuid();
if (done) { if (done) {
setValue(''); 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]); }, [addNewestQuestion, handleSendMessage, done, setValue, value]);
return { return {

View File

@ -7,7 +7,7 @@ export const isConversationIdExist = (conversationId: string) => {
return conversationId !== EmptyConversationId && conversationId !== ''; return conversationId !== EmptyConversationId && conversationId !== '';
}; };
export const buildMessageUuid = (message: Message | IMessage) => { export const buildMessageUuid = (message: Partial<Message | IMessage>) => {
if ('id' in message && message.id) { if ('id' in message && message.id) {
return message.role === MessageType.User return message.role === MessageType.User
? `${MessageType.User}_${message.id}` ? `${MessageType.User}_${message.id}`