### What problem does this PR solve? Fix: In order to distinguish the keys of a pair of messages, add a prefix to the id when rendering the message. #4409 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)tags/v0.16.0
| @@ -2,7 +2,6 @@ import { useDeleteMessage, useFeedback } from '@/hooks/chat-hooks'; | |||
| import { useSetModalState } from '@/hooks/common-hooks'; | |||
| import { IRemoveMessageById, useSpeechWithSse } from '@/hooks/logic-hooks'; | |||
| import { IFeedbackRequestBody } from '@/interfaces/request/chat'; | |||
| import { getMessagePureId } from '@/utils/chat'; | |||
| import { hexStringToUint8Array } from '@/utils/common-util'; | |||
| import { SpeechPlayer } from 'openai-speech-stream-player'; | |||
| import { useCallback, useEffect, useRef, useState } from 'react'; | |||
| @@ -15,7 +14,7 @@ export const useSendFeedback = (messageId: string) => { | |||
| async (params: IFeedbackRequestBody) => { | |||
| const ret = await feedback({ | |||
| ...params, | |||
| messageId: getMessagePureId(messageId), | |||
| messageId: messageId, | |||
| }); | |||
| if (ret === 0) { | |||
| @@ -41,9 +40,8 @@ export const useRemoveMessage = ( | |||
| const { deleteMessage, loading } = useDeleteMessage(); | |||
| const onRemoveMessage = useCallback(async () => { | |||
| const pureId = getMessagePureId(messageId); | |||
| if (pureId) { | |||
| const code = await deleteMessage(pureId); | |||
| if (messageId) { | |||
| const code = await deleteMessage(messageId); | |||
| if (code === 0) { | |||
| removeMessageById?.(messageId); | |||
| } | |||
| @@ -7,7 +7,7 @@ import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||
| import { IClientConversation, IMessage } from '@/pages/chat/interface'; | |||
| import api from '@/utils/api'; | |||
| import { getAuthorization } from '@/utils/authorization-util'; | |||
| import { buildMessageUuid, getMessagePureId } from '@/utils/chat'; | |||
| import { buildMessageUuid } from '@/utils/chat'; | |||
| import { PaginationProps, message } from 'antd'; | |||
| import { FormInstance } from 'antd/lib'; | |||
| import axios from 'axios'; | |||
| @@ -309,7 +309,9 @@ export const useSelectDerivedMessages = () => { | |||
| ...pre, | |||
| { | |||
| ...message, | |||
| id: buildMessageUuid(message), | |||
| id: buildMessageUuid(message), // The message id is generated on the front end, | |||
| // and the message id returned by the back end is the same as the question id, | |||
| // so that the pair of messages can be deleted together when deleting the message | |||
| }, | |||
| { | |||
| role: MessageType.Assistant, | |||
| @@ -353,10 +355,7 @@ export const useSelectDerivedMessages = () => { | |||
| const removeMessageById = useCallback( | |||
| (messageId: string) => { | |||
| setDerivedMessages((pre) => { | |||
| const nextMessages = | |||
| pre?.filter( | |||
| (x) => getMessagePureId(x.id) !== getMessagePureId(messageId), | |||
| ) ?? []; | |||
| const nextMessages = pre?.filter((x) => x.id !== messageId) ?? []; | |||
| return nextMessages; | |||
| }); | |||
| }, | |||
| @@ -18,6 +18,7 @@ import { | |||
| useGetChatSearchParams, | |||
| } from '@/hooks/chat-hooks'; | |||
| import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; | |||
| import { buildMessageUuidWithRole } from '@/utils/chat'; | |||
| import { memo } from 'react'; | |||
| import styles from './index.less'; | |||
| @@ -64,7 +65,7 @@ const ChatContainer = ({ controller }: IProps) => { | |||
| sendLoading && | |||
| derivedMessages.length - 1 === i | |||
| } | |||
| key={message.id} | |||
| key={buildMessageUuidWithRole(message)} | |||
| item={message} | |||
| nickname={userInfo.nickname} | |||
| avatar={userInfo.avatar} | |||
| @@ -14,6 +14,7 @@ import { buildMessageItemReference } from '../utils'; | |||
| import PdfDrawer from '@/components/pdf-drawer'; | |||
| import { useFetchNextConversationSSE } from '@/hooks/chat-hooks'; | |||
| import { useFetchFlowSSE } from '@/hooks/flow-hooks'; | |||
| import { buildMessageUuidWithRole } from '@/utils/chat'; | |||
| import styles from './index.less'; | |||
| const ChatContainer = () => { | |||
| @@ -54,7 +55,7 @@ const ChatContainer = () => { | |||
| {derivedMessages?.map((message, i) => { | |||
| return ( | |||
| <MessageItem | |||
| key={message.id} | |||
| key={buildMessageUuidWithRole(message)} | |||
| avatardialog={avatarData?.avatar} | |||
| item={message} | |||
| nickname="You" | |||
| @@ -11,6 +11,7 @@ import PdfDrawer from '@/components/pdf-drawer'; | |||
| import { useClickDrawer } from '@/components/pdf-drawer/hooks'; | |||
| import { useFetchFlow } from '@/hooks/flow-hooks'; | |||
| import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; | |||
| import { buildMessageUuidWithRole } from '@/utils/chat'; | |||
| import styles from './index.less'; | |||
| const FlowChatBox = () => { | |||
| @@ -46,7 +47,7 @@ const FlowChatBox = () => { | |||
| sendLoading && | |||
| derivedMessages.length - 1 === i | |||
| } | |||
| key={message.id} | |||
| key={buildMessageUuidWithRole(message)} | |||
| nickname={userInfo.nickname} | |||
| avatar={userInfo.avatar} | |||
| avatardialog={cavasInfo.avatar} | |||
| @@ -1,4 +1,4 @@ | |||
| import { EmptyConversationId, MessageType } from '@/constants/chat'; | |||
| import { EmptyConversationId } from '@/constants/chat'; | |||
| import { Message } from '@/interfaces/database/chat'; | |||
| import { IMessage } from '@/pages/chat/interface'; | |||
| import { omit } from 'lodash'; | |||
| @@ -10,21 +10,11 @@ export const isConversationIdExist = (conversationId: string) => { | |||
| export const buildMessageUuid = (message: Partial<Message | IMessage>) => { | |||
| if ('id' in message && message.id) { | |||
| return message.role === MessageType.User | |||
| ? `${MessageType.User}_${message.id}` | |||
| : `${MessageType.Assistant}_${message.id}`; | |||
| return message.id; | |||
| } | |||
| return uuid(); | |||
| }; | |||
| export const getMessagePureId = (id?: string) => { | |||
| const strings = id?.split('_') ?? []; | |||
| if (strings.length > 0) { | |||
| return strings.at(-1); | |||
| } | |||
| return id; | |||
| }; | |||
| export const buildMessageListWithUuid = (messages?: Message[]) => { | |||
| return ( | |||
| messages?.map((x: Message | IMessage) => ({ | |||
| @@ -37,3 +27,10 @@ export const buildMessageListWithUuid = (messages?: Message[]) => { | |||
| export const getConversationId = () => { | |||
| return uuid().replace(/-/g, ''); | |||
| }; | |||
| // When rendering each message, add a prefix to the id to ensure uniqueness. | |||
| export const buildMessageUuidWithRole = ( | |||
| message: Partial<Message | IMessage>, | |||
| ) => { | |||
| return `${message.role}_${message.id}`; | |||
| }; | |||