mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-13 00:58:58 +08:00
### What problem does this PR solve? feat: Select derived messages from backend #2088 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
2c771fb0b4
commit
5400467da1
@ -91,7 +91,7 @@ export const AssistantGroupButton = ({
|
|||||||
interface UserGroupButtonProps extends Partial<IRemoveMessageById> {
|
interface UserGroupButtonProps extends Partial<IRemoveMessageById> {
|
||||||
messageId: string;
|
messageId: string;
|
||||||
content: string;
|
content: string;
|
||||||
regenerateMessage(): void;
|
regenerateMessage?: () => void;
|
||||||
sendLoading: boolean;
|
sendLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,15 +113,17 @@ export const UserGroupButton = ({
|
|||||||
<Radio.Button value="a">
|
<Radio.Button value="a">
|
||||||
<CopyToClipboard text={content}></CopyToClipboard>
|
<CopyToClipboard text={content}></CopyToClipboard>
|
||||||
</Radio.Button>
|
</Radio.Button>
|
||||||
<Radio.Button
|
{regenerateMessage && (
|
||||||
value="b"
|
<Radio.Button
|
||||||
onClick={regenerateMessage}
|
value="b"
|
||||||
disabled={sendLoading}
|
onClick={regenerateMessage}
|
||||||
>
|
disabled={sendLoading}
|
||||||
<Tooltip title={t('chat.regenerate')}>
|
>
|
||||||
<SyncOutlined spin={sendLoading} />
|
<Tooltip title={t('chat.regenerate')}>
|
||||||
</Tooltip>
|
<SyncOutlined spin={sendLoading} />
|
||||||
</Radio.Button>
|
</Tooltip>
|
||||||
|
</Radio.Button>
|
||||||
|
)}
|
||||||
{removeMessageById && (
|
{removeMessageById && (
|
||||||
<Radio.Button value="c" onClick={onRemoveMessage} disabled={loading}>
|
<Radio.Button value="c" onClick={onRemoveMessage} disabled={loading}>
|
||||||
<Tooltip title={t('common.delete')}>
|
<Tooltip title={t('common.delete')}>
|
||||||
|
@ -79,7 +79,7 @@ const MessageItem = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleRegenerateMessage = useCallback(() => {
|
const handleRegenerateMessage = useCallback(() => {
|
||||||
regenerateMessage(item);
|
regenerateMessage?.(item);
|
||||||
}, [regenerateMessage, item]);
|
}, [regenerateMessage, item]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -138,7 +138,9 @@ const MessageItem = ({
|
|||||||
content={item.content}
|
content={item.content}
|
||||||
messageId={item.id}
|
messageId={item.id}
|
||||||
removeMessageById={removeMessageById}
|
removeMessageById={removeMessageById}
|
||||||
regenerateMessage={handleRegenerateMessage}
|
regenerateMessage={
|
||||||
|
regenerateMessage && handleRegenerateMessage
|
||||||
|
}
|
||||||
sendLoading={sendLoading}
|
sendLoading={sendLoading}
|
||||||
></UserGroupButton>
|
></UserGroupButton>
|
||||||
)}
|
)}
|
||||||
|
@ -4,13 +4,12 @@ import {
|
|||||||
IDialog,
|
IDialog,
|
||||||
IStats,
|
IStats,
|
||||||
IToken,
|
IToken,
|
||||||
Message,
|
|
||||||
} from '@/interfaces/database/chat';
|
} from '@/interfaces/database/chat';
|
||||||
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
|
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
|
||||||
import i18n from '@/locales/config';
|
import i18n from '@/locales/config';
|
||||||
import { IClientConversation, IMessage } from '@/pages/chat/interface';
|
import { IClientConversation } from '@/pages/chat/interface';
|
||||||
import chatService from '@/services/chat-service';
|
import chatService from '@/services/chat-service';
|
||||||
import { buildMessageUuid, isConversationIdExist } from '@/utils/chat';
|
import { buildMessageListWithUuid, 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';
|
||||||
@ -18,15 +17,6 @@ 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 = () => {
|
||||||
@ -465,14 +455,11 @@ export const useCreateNextSharedConversation = () => {
|
|||||||
return { data, loading, createSharedConversation: mutateAsync };
|
return { data, loading, createSharedConversation: mutateAsync };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useFetchNextSharedConversation = () => {
|
export const useFetchNextSharedConversation = (conversationId: string) => {
|
||||||
const {
|
const { data, isPending: loading } = useQuery({
|
||||||
data,
|
queryKey: ['fetchSharedConversation'],
|
||||||
isPending: loading,
|
enabled: !!conversationId,
|
||||||
mutateAsync,
|
queryFn: async () => {
|
||||||
} = useMutation({
|
|
||||||
mutationKey: ['fetchSharedConversation'],
|
|
||||||
mutationFn: async (conversationId: string) => {
|
|
||||||
const { data } = await chatService.getExternalConversation(
|
const { data } = await chatService.getExternalConversation(
|
||||||
null,
|
null,
|
||||||
conversationId,
|
conversationId,
|
||||||
@ -486,7 +473,7 @@ export const useFetchNextSharedConversation = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return { data, loading, fetchConversation: mutateAsync };
|
return { data, loading };
|
||||||
};
|
};
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@ -2,8 +2,11 @@ import { ResponseType } from '@/interfaces/database/base';
|
|||||||
import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow';
|
import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow';
|
||||||
import i18n from '@/locales/config';
|
import i18n from '@/locales/config';
|
||||||
import flowService from '@/services/flow-service';
|
import flowService from '@/services/flow-service';
|
||||||
|
import { buildMessageListWithUuid } 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 { set } from 'lodash';
|
||||||
|
import get from 'lodash/get';
|
||||||
import { useParams } from 'umi';
|
import { useParams } from 'umi';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
@ -101,6 +104,11 @@ export const useFetchFlow = (): {
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await flowService.getCanvas({}, id);
|
const { data } = await flowService.getCanvas({}, id);
|
||||||
|
|
||||||
|
const messageList = buildMessageListWithUuid(
|
||||||
|
get(data, 'data.dsl.messages', []),
|
||||||
|
);
|
||||||
|
set(data, 'data.dsl.messages', messageList);
|
||||||
|
|
||||||
return data?.data ?? {};
|
return data?.data ?? {};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { Authorization } from '@/constants/authorization';
|
import { Authorization } from '@/constants/authorization';
|
||||||
|
import { MessageType } from '@/constants/chat';
|
||||||
import { LanguageTranslationMap } from '@/constants/common';
|
import { LanguageTranslationMap } from '@/constants/common';
|
||||||
import { Pagination } from '@/interfaces/common';
|
import { Pagination } from '@/interfaces/common';
|
||||||
import { ResponseType } from '@/interfaces/database/base';
|
import { ResponseType } from '@/interfaces/database/base';
|
||||||
import { IAnswer, Message } from '@/interfaces/database/chat';
|
import { IAnswer, Message } from '@/interfaces/database/chat';
|
||||||
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||||
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
||||||
import { IClientConversation } from '@/pages/chat/interface';
|
import { IClientConversation, IMessage } from '@/pages/chat/interface';
|
||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
import { getAuthorization } from '@/utils/authorization-util';
|
import { getAuthorization } from '@/utils/authorization-util';
|
||||||
import { getMessagePureId } from '@/utils/chat';
|
import { buildMessageUuid, getMessagePureId } from '@/utils/chat';
|
||||||
import { PaginationProps } from 'antd';
|
import { PaginationProps } from 'antd';
|
||||||
import { FormInstance } from 'antd/lib';
|
import { FormInstance } from 'antd/lib';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
@ -309,6 +310,108 @@ export const useHandleMessageInputChange = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSelectDerivedMessages = () => {
|
||||||
|
const [derivedMessages, setDerivedMessages] = useState<IMessage[]>([]);
|
||||||
|
|
||||||
|
const ref = useScrollToBottom(derivedMessages);
|
||||||
|
|
||||||
|
const addNewestQuestion = useCallback(
|
||||||
|
(message: Message, answer: string = '') => {
|
||||||
|
setDerivedMessages((pre) => {
|
||||||
|
return [
|
||||||
|
...pre,
|
||||||
|
{
|
||||||
|
...message,
|
||||||
|
id: buildMessageUuid(message),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: MessageType.Assistant,
|
||||||
|
content: answer,
|
||||||
|
id: buildMessageUuid({ ...message, role: MessageType.Assistant }),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add the streaming message to the last item in the message list
|
||||||
|
const addNewestAnswer = useCallback((answer: IAnswer) => {
|
||||||
|
setDerivedMessages((pre) => {
|
||||||
|
return [
|
||||||
|
...(pre?.slice(0, -1) ?? []),
|
||||||
|
{
|
||||||
|
role: MessageType.Assistant,
|
||||||
|
content: answer.answer,
|
||||||
|
reference: answer.reference,
|
||||||
|
id: buildMessageUuid({
|
||||||
|
id: answer.id,
|
||||||
|
role: MessageType.Assistant,
|
||||||
|
}),
|
||||||
|
prompt: answer.prompt,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const removeLatestMessage = useCallback(() => {
|
||||||
|
setDerivedMessages((pre) => {
|
||||||
|
const nextMessages = pre?.slice(0, -2) ?? [];
|
||||||
|
return nextMessages;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const removeMessageById = useCallback(
|
||||||
|
(messageId: string) => {
|
||||||
|
setDerivedMessages((pre) => {
|
||||||
|
const nextMessages =
|
||||||
|
pre?.filter(
|
||||||
|
(x) => getMessagePureId(x.id) !== getMessagePureId(messageId),
|
||||||
|
) ?? [];
|
||||||
|
return nextMessages;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setDerivedMessages],
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeMessagesAfterCurrentMessage = useCallback(
|
||||||
|
(messageId: string) => {
|
||||||
|
setDerivedMessages((pre) => {
|
||||||
|
const index = pre.findIndex((x) => x.id === messageId);
|
||||||
|
if (index !== -1) {
|
||||||
|
let nextMessages = pre.slice(0, index + 2) ?? [];
|
||||||
|
const latestMessage = nextMessages.at(-1);
|
||||||
|
nextMessages = latestMessage
|
||||||
|
? [
|
||||||
|
...nextMessages.slice(0, -1),
|
||||||
|
{
|
||||||
|
...latestMessage,
|
||||||
|
content: '',
|
||||||
|
reference: undefined,
|
||||||
|
prompt: undefined,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: nextMessages;
|
||||||
|
return nextMessages;
|
||||||
|
}
|
||||||
|
return pre;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setDerivedMessages],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
ref,
|
||||||
|
derivedMessages,
|
||||||
|
setDerivedMessages,
|
||||||
|
addNewestQuestion,
|
||||||
|
addNewestAnswer,
|
||||||
|
removeLatestMessage,
|
||||||
|
removeMessageById,
|
||||||
|
removeMessagesAfterCurrentMessage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export interface IRemoveMessageById {
|
export interface IRemoveMessageById {
|
||||||
removeMessageById(messageId: string): void;
|
removeMessageById(messageId: string): void;
|
||||||
}
|
}
|
||||||
@ -375,7 +478,7 @@ export const useRemoveMessagesAfterCurrentMessage = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface IRegenerateMessage {
|
export interface IRegenerateMessage {
|
||||||
regenerateMessage(message: Message): void;
|
regenerateMessage?: (message: Message) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useRegenerateMessage = ({
|
export const useRegenerateMessage = ({
|
||||||
@ -384,7 +487,12 @@ export const useRegenerateMessage = ({
|
|||||||
messages,
|
messages,
|
||||||
}: {
|
}: {
|
||||||
removeMessagesAfterCurrentMessage(messageId: string): void;
|
removeMessagesAfterCurrentMessage(messageId: string): void;
|
||||||
sendMessage({ message }: { message: Message; messages?: Message[] }): void;
|
sendMessage({
|
||||||
|
message,
|
||||||
|
}: {
|
||||||
|
message: Message;
|
||||||
|
messages?: Message[];
|
||||||
|
}): void | Promise<any>;
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
}) => {
|
}) => {
|
||||||
const regenerateMessage = useCallback(
|
const regenerateMessage = useCallback(
|
||||||
|
@ -5,44 +5,38 @@ import { Drawer, Flex, Spin } from 'antd';
|
|||||||
import {
|
import {
|
||||||
useClickDrawer,
|
useClickDrawer,
|
||||||
useCreateConversationBeforeUploadDocument,
|
useCreateConversationBeforeUploadDocument,
|
||||||
useFetchConversationOnMount,
|
|
||||||
useGetFileIcon,
|
useGetFileIcon,
|
||||||
useGetSendButtonDisabled,
|
useGetSendButtonDisabled,
|
||||||
useSendButtonDisabled,
|
useSendButtonDisabled,
|
||||||
useSendMessage,
|
useSendNextMessage,
|
||||||
} from '../hooks';
|
} from '../hooks';
|
||||||
import { buildMessageItemReference } from '../utils';
|
import { buildMessageItemReference } from '../utils';
|
||||||
|
|
||||||
import MessageInput from '@/components/message-input';
|
import MessageInput from '@/components/message-input';
|
||||||
|
import {
|
||||||
|
useFetchNextConversation,
|
||||||
|
useGetChatSearchParams,
|
||||||
|
} from '@/hooks/chat-hooks';
|
||||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const ChatContainer = () => {
|
const ChatContainer = () => {
|
||||||
|
const { conversationId } = useGetChatSearchParams();
|
||||||
|
const { data: conversation } = useFetchNextConversation();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ref,
|
ref,
|
||||||
currentConversation: conversation,
|
|
||||||
addNewestConversation,
|
|
||||||
removeLatestMessage,
|
|
||||||
addNewestAnswer,
|
|
||||||
conversationId,
|
|
||||||
loading,
|
loading,
|
||||||
removeMessageById,
|
sendLoading,
|
||||||
removeMessagesAfterCurrentMessage,
|
derivedMessages,
|
||||||
} = useFetchConversationOnMount();
|
|
||||||
const {
|
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
handlePressEnter,
|
handlePressEnter,
|
||||||
value,
|
value,
|
||||||
loading: sendLoading,
|
|
||||||
regenerateMessage,
|
regenerateMessage,
|
||||||
} = useSendMessage(
|
removeMessageById,
|
||||||
conversation,
|
} = useSendNextMessage();
|
||||||
addNewestConversation,
|
|
||||||
removeLatestMessage,
|
|
||||||
addNewestAnswer,
|
|
||||||
removeMessagesAfterCurrentMessage,
|
|
||||||
);
|
|
||||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||||
useClickDrawer();
|
useClickDrawer();
|
||||||
const disabled = useGetSendButtonDisabled();
|
const disabled = useGetSendButtonDisabled();
|
||||||
@ -58,19 +52,25 @@ const ChatContainer = () => {
|
|||||||
<Flex flex={1} vertical className={styles.messageContainer}>
|
<Flex flex={1} vertical className={styles.messageContainer}>
|
||||||
<div>
|
<div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
{conversation?.message?.map((message, i) => {
|
{derivedMessages?.map((message, i) => {
|
||||||
return (
|
return (
|
||||||
<MessageItem
|
<MessageItem
|
||||||
loading={
|
loading={
|
||||||
message.role === MessageType.Assistant &&
|
message.role === MessageType.Assistant &&
|
||||||
sendLoading &&
|
sendLoading &&
|
||||||
conversation?.message.length - 1 === i
|
derivedMessages.length - 1 === i
|
||||||
}
|
}
|
||||||
key={message.id}
|
key={message.id}
|
||||||
item={message}
|
item={message}
|
||||||
nickname={userInfo.nickname}
|
nickname={userInfo.nickname}
|
||||||
avatar={userInfo.avatar}
|
avatar={userInfo.avatar}
|
||||||
reference={buildMessageItemReference(conversation, message)}
|
reference={buildMessageItemReference(
|
||||||
|
{
|
||||||
|
message: derivedMessages,
|
||||||
|
reference: conversation.reference,
|
||||||
|
},
|
||||||
|
message,
|
||||||
|
)}
|
||||||
clickDocumentButton={clickDocumentButton}
|
clickDocumentButton={clickDocumentButton}
|
||||||
index={i}
|
index={i}
|
||||||
removeMessageById={removeMessageById}
|
removeMessageById={removeMessageById}
|
||||||
|
@ -21,6 +21,8 @@ import {
|
|||||||
useRegenerateMessage,
|
useRegenerateMessage,
|
||||||
useRemoveMessageById,
|
useRemoveMessageById,
|
||||||
useRemoveMessagesAfterCurrentMessage,
|
useRemoveMessagesAfterCurrentMessage,
|
||||||
|
useScrollToBottom,
|
||||||
|
useSelectDerivedMessages,
|
||||||
useSendMessageWithSse,
|
useSendMessageWithSse,
|
||||||
} from '@/hooks/logic-hooks';
|
} from '@/hooks/logic-hooks';
|
||||||
import {
|
import {
|
||||||
@ -40,7 +42,6 @@ import {
|
|||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useSearchParams } from 'umi';
|
import { useSearchParams } from 'umi';
|
||||||
@ -362,20 +363,71 @@ export const useSelectCurrentConversation = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useScrollToBottom = (currentConversation: IClientConversation) => {
|
// export const useScrollToBottom = (currentConversation: IClientConversation) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
// const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const scrollToBottom = useCallback(() => {
|
// const scrollToBottom = useCallback(() => {
|
||||||
if (currentConversation.id) {
|
// if (currentConversation.id) {
|
||||||
ref.current?.scrollIntoView({ behavior: 'instant' });
|
// ref.current?.scrollIntoView({ behavior: 'instant' });
|
||||||
|
// }
|
||||||
|
// }, [currentConversation]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// scrollToBottom();
|
||||||
|
// }, [scrollToBottom]);
|
||||||
|
|
||||||
|
// return ref;
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const useSelectNextMessages = () => {
|
||||||
|
const {
|
||||||
|
ref,
|
||||||
|
setDerivedMessages,
|
||||||
|
derivedMessages,
|
||||||
|
addNewestAnswer,
|
||||||
|
addNewestQuestion,
|
||||||
|
removeLatestMessage,
|
||||||
|
removeMessageById,
|
||||||
|
removeMessagesAfterCurrentMessage,
|
||||||
|
} = useSelectDerivedMessages();
|
||||||
|
const { data: conversation, loading } = useFetchNextConversation();
|
||||||
|
const { data: dialog } = useFetchNextDialog();
|
||||||
|
const { conversationId, dialogId } = useGetChatSearchParams();
|
||||||
|
|
||||||
|
const addPrologue = useCallback(() => {
|
||||||
|
if (dialogId !== '' && conversationId === '') {
|
||||||
|
const prologue = dialog.prompt_config?.prologue;
|
||||||
|
|
||||||
|
const nextMessage = {
|
||||||
|
role: MessageType.Assistant,
|
||||||
|
content: prologue,
|
||||||
|
id: uuid(),
|
||||||
|
} as IMessage;
|
||||||
|
|
||||||
|
setDerivedMessages([nextMessage]);
|
||||||
}
|
}
|
||||||
}, [currentConversation]);
|
}, [conversationId, dialog, dialogId, setDerivedMessages]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
scrollToBottom();
|
addPrologue();
|
||||||
}, [scrollToBottom]);
|
}, [addPrologue]);
|
||||||
|
|
||||||
return ref;
|
useEffect(() => {
|
||||||
|
if (conversationId) {
|
||||||
|
setDerivedMessages(conversation.message);
|
||||||
|
}
|
||||||
|
}, [conversation.message, conversationId, setDerivedMessages]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
ref,
|
||||||
|
derivedMessages,
|
||||||
|
loading,
|
||||||
|
addNewestAnswer,
|
||||||
|
addNewestQuestion,
|
||||||
|
removeLatestMessage,
|
||||||
|
removeMessageById,
|
||||||
|
removeMessagesAfterCurrentMessage,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useFetchConversationOnMount = () => {
|
export const useFetchConversationOnMount = () => {
|
||||||
@ -544,6 +596,137 @@ export const useSendMessage = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSendNextMessage = () => {
|
||||||
|
const { setConversation } = useSetConversation();
|
||||||
|
const { conversationId } = useGetChatSearchParams();
|
||||||
|
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||||
|
const { handleClickConversation } = useClickConversationCard();
|
||||||
|
const { send, answer, done, setDone } = useSendMessageWithSse();
|
||||||
|
const {
|
||||||
|
ref,
|
||||||
|
derivedMessages,
|
||||||
|
loading,
|
||||||
|
addNewestAnswer,
|
||||||
|
addNewestQuestion,
|
||||||
|
removeLatestMessage,
|
||||||
|
removeMessageById,
|
||||||
|
removeMessagesAfterCurrentMessage,
|
||||||
|
} = useSelectNextMessages();
|
||||||
|
|
||||||
|
const sendMessage = useCallback(
|
||||||
|
async ({
|
||||||
|
message,
|
||||||
|
currentConversationId,
|
||||||
|
messages,
|
||||||
|
}: {
|
||||||
|
message: Message;
|
||||||
|
currentConversationId?: string;
|
||||||
|
messages?: Message[];
|
||||||
|
}) => {
|
||||||
|
const res = await send({
|
||||||
|
conversation_id: currentConversationId ?? conversationId,
|
||||||
|
messages: [...(messages ?? derivedMessages ?? []), message],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
|
||||||
|
// cancel loading
|
||||||
|
setValue(message.content);
|
||||||
|
console.info('removeLatestMessage111');
|
||||||
|
removeLatestMessage();
|
||||||
|
} else {
|
||||||
|
if (currentConversationId) {
|
||||||
|
console.info('111');
|
||||||
|
// new conversation
|
||||||
|
handleClickConversation(currentConversationId);
|
||||||
|
} else {
|
||||||
|
console.info('222');
|
||||||
|
// fetchConversation(conversationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
derivedMessages,
|
||||||
|
conversationId,
|
||||||
|
handleClickConversation,
|
||||||
|
removeLatestMessage,
|
||||||
|
setValue,
|
||||||
|
send,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSendMessage = useCallback(
|
||||||
|
async (message: Message) => {
|
||||||
|
if (conversationId !== '') {
|
||||||
|
sendMessage({ message });
|
||||||
|
} else {
|
||||||
|
const data = await setConversation(message.content);
|
||||||
|
if (data.retcode === 0) {
|
||||||
|
const id = data.data.id;
|
||||||
|
sendMessage({ message, currentConversationId: id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[conversationId, setConversation, sendMessage],
|
||||||
|
);
|
||||||
|
|
||||||
|
const { regenerateMessage } = useRegenerateMessage({
|
||||||
|
removeMessagesAfterCurrentMessage,
|
||||||
|
sendMessage,
|
||||||
|
messages: derivedMessages,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// #1289
|
||||||
|
if (answer.answer && answer?.conversationId === conversationId) {
|
||||||
|
addNewestAnswer(answer);
|
||||||
|
}
|
||||||
|
}, [answer, addNewestAnswer, conversationId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// #1289 switch to another conversion window when the last conversion answer doesn't finish.
|
||||||
|
if (conversationId) {
|
||||||
|
setDone(true);
|
||||||
|
}
|
||||||
|
}, [setDone, conversationId]);
|
||||||
|
|
||||||
|
const handlePressEnter = useCallback(
|
||||||
|
(documentIds: string[]) => {
|
||||||
|
if (trim(value) === '') return;
|
||||||
|
const id = uuid();
|
||||||
|
|
||||||
|
addNewestQuestion({
|
||||||
|
content: value,
|
||||||
|
doc_ids: documentIds,
|
||||||
|
id,
|
||||||
|
role: MessageType.User,
|
||||||
|
});
|
||||||
|
if (done) {
|
||||||
|
setValue('');
|
||||||
|
handleSendMessage({
|
||||||
|
id,
|
||||||
|
content: value.trim(),
|
||||||
|
role: MessageType.User,
|
||||||
|
doc_ids: documentIds,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[addNewestQuestion, handleSendMessage, done, setValue, value],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handlePressEnter,
|
||||||
|
handleInputChange,
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
regenerateMessage,
|
||||||
|
sendLoading: !done,
|
||||||
|
loading,
|
||||||
|
ref,
|
||||||
|
derivedMessages,
|
||||||
|
removeMessageById,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetFileIcon = () => {
|
export const useGetFileIcon = () => {
|
||||||
const getFileIcon = (filename: string) => {
|
const getFileIcon = (filename: string) => {
|
||||||
const ext: string = getFileExtension(filename);
|
const ext: string = getFileExtension(filename);
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import MessageInput from '@/components/message-input';
|
import MessageInput from '@/components/message-input';
|
||||||
import MessageItem from '@/components/message-item';
|
import MessageItem from '@/components/message-item';
|
||||||
import { MessageType, SharedFrom } from '@/constants/chat';
|
import { MessageType, SharedFrom } from '@/constants/chat';
|
||||||
|
import { useFetchNextSharedConversation } from '@/hooks/chat-hooks';
|
||||||
import { useSendButtonDisabled } from '@/pages/chat/hooks';
|
import { useSendButtonDisabled } from '@/pages/chat/hooks';
|
||||||
import { Flex, Spin } from 'antd';
|
import { Flex, Spin } from 'antd';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import {
|
import {
|
||||||
useCreateSharedConversationOnMount,
|
useCreateSharedConversationOnMount,
|
||||||
useGetSharedChatSearchParams,
|
useGetSharedChatSearchParams,
|
||||||
useSelectCurrentSharedConversation,
|
|
||||||
useSendSharedMessage,
|
useSendSharedMessage,
|
||||||
} from '../shared-hooks';
|
} from '../shared-hooks';
|
||||||
import { buildMessageItemReference } from '../utils';
|
import { buildMessageItemReference } from '../utils';
|
||||||
@ -15,28 +15,17 @@ import styles from './index.less';
|
|||||||
|
|
||||||
const ChatContainer = () => {
|
const ChatContainer = () => {
|
||||||
const { conversationId } = useCreateSharedConversationOnMount();
|
const { conversationId } = useCreateSharedConversationOnMount();
|
||||||
const {
|
const { data } = useFetchNextSharedConversation(conversationId);
|
||||||
currentConversation: conversation,
|
|
||||||
addNewestConversation,
|
|
||||||
removeLatestMessage,
|
|
||||||
ref,
|
|
||||||
loading,
|
|
||||||
setCurrentConversation,
|
|
||||||
addNewestAnswer,
|
|
||||||
} = useSelectCurrentSharedConversation(conversationId);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handlePressEnter,
|
handlePressEnter,
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
value,
|
value,
|
||||||
loading: sendLoading,
|
sendLoading,
|
||||||
} = useSendSharedMessage(
|
loading,
|
||||||
conversation,
|
ref,
|
||||||
addNewestConversation,
|
derivedMessages,
|
||||||
removeLatestMessage,
|
} = useSendSharedMessage(conversationId);
|
||||||
setCurrentConversation,
|
|
||||||
addNewestAnswer,
|
|
||||||
);
|
|
||||||
const sendDisabled = useSendButtonDisabled(value);
|
const sendDisabled = useSendButtonDisabled(value);
|
||||||
const { from } = useGetSharedChatSearchParams();
|
const { from } = useGetSharedChatSearchParams();
|
||||||
|
|
||||||
@ -46,17 +35,23 @@ const ChatContainer = () => {
|
|||||||
<Flex flex={1} vertical className={styles.messageContainer}>
|
<Flex flex={1} vertical className={styles.messageContainer}>
|
||||||
<div>
|
<div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
{conversation?.message?.map((message, i) => {
|
{derivedMessages?.map((message, i) => {
|
||||||
return (
|
return (
|
||||||
<MessageItem
|
<MessageItem
|
||||||
key={message.id}
|
key={message.id}
|
||||||
item={message}
|
item={message}
|
||||||
nickname="You"
|
nickname="You"
|
||||||
reference={buildMessageItemReference(conversation, message)}
|
reference={buildMessageItemReference(
|
||||||
|
{
|
||||||
|
message: derivedMessages,
|
||||||
|
reference: data?.data?.reference,
|
||||||
|
},
|
||||||
|
message,
|
||||||
|
)}
|
||||||
loading={
|
loading={
|
||||||
message.role === MessageType.Assistant &&
|
message.role === MessageType.Assistant &&
|
||||||
sendLoading &&
|
sendLoading &&
|
||||||
conversation?.message.length - 1 === i
|
derivedMessages?.length - 1 === i
|
||||||
}
|
}
|
||||||
index={i}
|
index={i}
|
||||||
></MessageItem>
|
></MessageItem>
|
||||||
|
@ -3,22 +3,17 @@ import {
|
|||||||
useCreateNextSharedConversation,
|
useCreateNextSharedConversation,
|
||||||
useFetchNextSharedConversation,
|
useFetchNextSharedConversation,
|
||||||
} from '@/hooks/chat-hooks';
|
} from '@/hooks/chat-hooks';
|
||||||
import { useSendMessageWithSse } from '@/hooks/logic-hooks';
|
|
||||||
import { IAnswer, Message } from '@/interfaces/database/chat';
|
|
||||||
import api from '@/utils/api';
|
|
||||||
import { buildMessageUuid } from '@/utils/chat';
|
|
||||||
import trim from 'lodash/trim';
|
|
||||||
import {
|
import {
|
||||||
Dispatch,
|
useSelectDerivedMessages,
|
||||||
SetStateAction,
|
useSendMessageWithSse,
|
||||||
useCallback,
|
} from '@/hooks/logic-hooks';
|
||||||
useEffect,
|
import { Message } from '@/interfaces/database/chat';
|
||||||
useState,
|
import api from '@/utils/api';
|
||||||
} from 'react';
|
import trim from 'lodash/trim';
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useSearchParams } from 'umi';
|
import { useSearchParams } from 'umi';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { useHandleMessageInputChange, useScrollToBottom } from './hooks';
|
import { useHandleMessageInputChange } from './hooks';
|
||||||
import { IClientConversation, IMessage } from './interface';
|
|
||||||
|
|
||||||
export const useCreateSharedConversationOnMount = () => {
|
export const useCreateSharedConversationOnMount = () => {
|
||||||
const [currentQueryParameters] = useSearchParams();
|
const [currentQueryParameters] = useSearchParams();
|
||||||
@ -46,91 +41,30 @@ export const useCreateSharedConversationOnMount = () => {
|
|||||||
return { conversationId };
|
return { conversationId };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSelectCurrentSharedConversation = (conversationId: string) => {
|
export const useSelectNextSharedMessages = (conversationId: string) => {
|
||||||
const [currentConversation, setCurrentConversation] =
|
const { data, loading } = useFetchNextSharedConversation(conversationId);
|
||||||
useState<IClientConversation>({} as IClientConversation);
|
|
||||||
const { fetchConversation, loading } = useFetchNextSharedConversation();
|
|
||||||
|
|
||||||
const ref = useScrollToBottom(currentConversation);
|
const {
|
||||||
|
derivedMessages,
|
||||||
const addNewestConversation = useCallback((message: Partial<Message>) => {
|
ref,
|
||||||
setCurrentConversation((pre) => {
|
setDerivedMessages,
|
||||||
return {
|
addNewestAnswer,
|
||||||
...pre,
|
addNewestQuestion,
|
||||||
message: [
|
removeLatestMessage,
|
||||||
...(pre.message ?? []),
|
} = useSelectDerivedMessages();
|
||||||
{
|
|
||||||
...message,
|
|
||||||
id: buildMessageUuid(message),
|
|
||||||
} as IMessage,
|
|
||||||
{
|
|
||||||
role: MessageType.Assistant,
|
|
||||||
content: '',
|
|
||||||
id: buildMessageUuid({ ...message, role: MessageType.Assistant }),
|
|
||||||
reference: {},
|
|
||||||
} as IMessage,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const addNewestAnswer = useCallback((answer: IAnswer) => {
|
|
||||||
setCurrentConversation((pre) => {
|
|
||||||
const latestMessage = pre.message?.at(-1);
|
|
||||||
|
|
||||||
if (latestMessage) {
|
|
||||||
return {
|
|
||||||
...pre,
|
|
||||||
message: [
|
|
||||||
...pre.message.slice(0, -1),
|
|
||||||
{
|
|
||||||
...latestMessage,
|
|
||||||
content: answer.answer,
|
|
||||||
reference: answer.reference,
|
|
||||||
id: buildMessageUuid({
|
|
||||||
id: answer.id,
|
|
||||||
role: MessageType.Assistant,
|
|
||||||
}),
|
|
||||||
prompt: answer.prompt,
|
|
||||||
} as IMessage,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return pre;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const removeLatestMessage = useCallback(() => {
|
|
||||||
setCurrentConversation((pre) => {
|
|
||||||
const nextMessages = pre.message.slice(0, -2);
|
|
||||||
return {
|
|
||||||
...pre,
|
|
||||||
message: nextMessages,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const fetchConversationOnMount = useCallback(async () => {
|
|
||||||
if (conversationId) {
|
|
||||||
const data = await fetchConversation(conversationId);
|
|
||||||
if (data.retcode === 0) {
|
|
||||||
setCurrentConversation(data.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [conversationId, fetchConversation]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConversationOnMount();
|
setDerivedMessages(data?.data?.message);
|
||||||
}, [fetchConversationOnMount]);
|
}, [setDerivedMessages, data]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentConversation,
|
derivedMessages,
|
||||||
addNewestConversation,
|
addNewestAnswer,
|
||||||
|
addNewestQuestion,
|
||||||
removeLatestMessage,
|
removeLatestMessage,
|
||||||
loading,
|
loading,
|
||||||
ref,
|
ref,
|
||||||
setCurrentConversation,
|
setDerivedMessages,
|
||||||
addNewestAnswer,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -138,28 +72,28 @@ export const useSendButtonDisabled = (value: string) => {
|
|||||||
return trim(value) === '';
|
return trim(value) === '';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSendSharedMessage = (
|
export const useSendSharedMessage = (conversationId: string) => {
|
||||||
conversation: IClientConversation,
|
|
||||||
addNewestConversation: (message: Partial<Message>, answer?: string) => void,
|
|
||||||
removeLatestMessage: () => void,
|
|
||||||
setCurrentConversation: Dispatch<SetStateAction<IClientConversation>>,
|
|
||||||
addNewestAnswer: (answer: IAnswer) => void,
|
|
||||||
) => {
|
|
||||||
const conversationId = conversation.id;
|
|
||||||
const { createSharedConversation: setConversation } =
|
const { createSharedConversation: setConversation } =
|
||||||
useCreateNextSharedConversation();
|
useCreateNextSharedConversation();
|
||||||
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||||
|
|
||||||
const { send, answer, done } = useSendMessageWithSse(
|
const { send, answer, done } = useSendMessageWithSse(
|
||||||
api.completeExternalConversation,
|
api.completeExternalConversation,
|
||||||
);
|
);
|
||||||
|
const {
|
||||||
|
derivedMessages,
|
||||||
|
ref,
|
||||||
|
removeLatestMessage,
|
||||||
|
addNewestAnswer,
|
||||||
|
addNewestQuestion,
|
||||||
|
loading,
|
||||||
|
} = useSelectNextSharedMessages(conversationId);
|
||||||
|
|
||||||
const sendMessage = useCallback(
|
const sendMessage = useCallback(
|
||||||
async (message: Message, 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: [...(conversation?.message ?? []), message],
|
messages: [...(derivedMessages ?? []), message],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
|
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
|
||||||
@ -168,15 +102,7 @@ export const useSendSharedMessage = (
|
|||||||
removeLatestMessage();
|
removeLatestMessage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[conversationId, derivedMessages, removeLatestMessage, setValue, send],
|
||||||
conversationId,
|
|
||||||
conversation?.message,
|
|
||||||
// fetchConversation,
|
|
||||||
removeLatestMessage,
|
|
||||||
setValue,
|
|
||||||
send,
|
|
||||||
// setCurrentConversation,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSendMessage = useCallback(
|
const handleSendMessage = useCallback(
|
||||||
@ -206,7 +132,7 @@ export const useSendSharedMessage = (
|
|||||||
const id = uuid();
|
const id = uuid();
|
||||||
if (done) {
|
if (done) {
|
||||||
setValue('');
|
setValue('');
|
||||||
addNewestConversation({
|
addNewestQuestion({
|
||||||
content: value,
|
content: value,
|
||||||
doc_ids: documentIds,
|
doc_ids: documentIds,
|
||||||
id,
|
id,
|
||||||
@ -219,14 +145,17 @@ export const useSendSharedMessage = (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[addNewestConversation, done, handleSendMessage, setValue, value],
|
[addNewestQuestion, done, handleSendMessage, setValue, value],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handlePressEnter,
|
handlePressEnter,
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
value,
|
value,
|
||||||
loading: !done,
|
sendLoading: !done,
|
||||||
|
ref,
|
||||||
|
loading,
|
||||||
|
derivedMessages,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ export const buildMessageItemReference = (
|
|||||||
);
|
);
|
||||||
const reference = message?.reference
|
const reference = message?.reference
|
||||||
? message?.reference
|
? message?.reference
|
||||||
: conversation.reference[referenceIndex];
|
: (conversation?.reference ?? {})[referenceIndex];
|
||||||
|
|
||||||
return reference;
|
return reference;
|
||||||
};
|
};
|
||||||
|
@ -6,28 +6,23 @@ import { useClickDrawer, useGetFileIcon } from '@/pages/chat/hooks';
|
|||||||
import { buildMessageItemReference } from '@/pages/chat/utils';
|
import { buildMessageItemReference } from '@/pages/chat/utils';
|
||||||
import { Button, Drawer, Flex, Input, Spin } from 'antd';
|
import { Button, Drawer, Flex, Input, Spin } from 'antd';
|
||||||
|
|
||||||
import { useSelectCurrentMessages, useSendMessage } from './hooks';
|
import { useSendNextMessage } from './hooks';
|
||||||
|
|
||||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const FlowChatBox = () => {
|
const FlowChatBox = () => {
|
||||||
const {
|
const {
|
||||||
ref,
|
sendLoading,
|
||||||
currentMessages,
|
|
||||||
reference,
|
|
||||||
addNewestAnswer,
|
|
||||||
addNewestQuestion,
|
|
||||||
removeLatestMessage,
|
|
||||||
loading,
|
|
||||||
} = useSelectCurrentMessages();
|
|
||||||
|
|
||||||
const {
|
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
handlePressEnter,
|
handlePressEnter,
|
||||||
value,
|
value,
|
||||||
loading: sendLoading,
|
loading,
|
||||||
} = useSendMessage(addNewestQuestion, removeLatestMessage, addNewestAnswer);
|
ref,
|
||||||
|
derivedMessages,
|
||||||
|
reference,
|
||||||
|
} = useSendNextMessage();
|
||||||
|
|
||||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||||
useClickDrawer();
|
useClickDrawer();
|
||||||
useGetFileIcon();
|
useGetFileIcon();
|
||||||
@ -40,26 +35,26 @@ const FlowChatBox = () => {
|
|||||||
<Flex flex={1} vertical className={styles.messageContainer}>
|
<Flex flex={1} vertical className={styles.messageContainer}>
|
||||||
<div>
|
<div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
{currentMessages?.map((message, i) => {
|
{derivedMessages?.map((message, i) => {
|
||||||
return (
|
return (
|
||||||
<MessageItem
|
<MessageItem
|
||||||
loading={
|
loading={
|
||||||
message.role === MessageType.Assistant &&
|
message.role === MessageType.Assistant &&
|
||||||
sendLoading &&
|
sendLoading &&
|
||||||
currentMessages.length - 1 === i
|
derivedMessages.length - 1 === i
|
||||||
}
|
}
|
||||||
key={message.id}
|
key={message.id}
|
||||||
nickname={userInfo.nickname}
|
nickname={userInfo.nickname}
|
||||||
avatar={userInfo.avatar}
|
avatar={userInfo.avatar}
|
||||||
item={message}
|
item={message}
|
||||||
reference={buildMessageItemReference(
|
reference={buildMessageItemReference(
|
||||||
{ message: currentMessages, reference },
|
{ message: derivedMessages, reference },
|
||||||
message,
|
message,
|
||||||
)}
|
)}
|
||||||
clickDocumentButton={clickDocumentButton}
|
clickDocumentButton={clickDocumentButton}
|
||||||
index={i}
|
index={i}
|
||||||
regenerateMessage={() => {}}
|
|
||||||
showLikeButton={false}
|
showLikeButton={false}
|
||||||
|
sendLoading={sendLoading}
|
||||||
></MessageItem>
|
></MessageItem>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -3,6 +3,7 @@ import { useFetchFlow } from '@/hooks/flow-hooks';
|
|||||||
import {
|
import {
|
||||||
useHandleMessageInputChange,
|
useHandleMessageInputChange,
|
||||||
useScrollToBottom,
|
useScrollToBottom,
|
||||||
|
useSelectDerivedMessages,
|
||||||
useSendMessageWithSse,
|
useSendMessageWithSse,
|
||||||
} from '@/hooks/logic-hooks';
|
} from '@/hooks/logic-hooks';
|
||||||
import { IAnswer, Message } from '@/interfaces/database/chat';
|
import { IAnswer, Message } from '@/interfaces/database/chat';
|
||||||
@ -91,6 +92,42 @@ export const useSelectCurrentMessages = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSelectNextMessages = () => {
|
||||||
|
const { id: id } = useParams();
|
||||||
|
const { data: flowDetail, loading } = useFetchFlow();
|
||||||
|
const messages = flowDetail.dsl.messages;
|
||||||
|
const reference = flowDetail.dsl.reference;
|
||||||
|
const {
|
||||||
|
derivedMessages,
|
||||||
|
setDerivedMessages,
|
||||||
|
ref,
|
||||||
|
addNewestQuestion,
|
||||||
|
addNewestAnswer,
|
||||||
|
removeLatestMessage,
|
||||||
|
removeMessageById,
|
||||||
|
removeMessagesAfterCurrentMessage,
|
||||||
|
} = useSelectDerivedMessages();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (id) {
|
||||||
|
const nextMessages = messages.map((x) => ({ ...x, id: uuid() }));
|
||||||
|
setDerivedMessages(nextMessages);
|
||||||
|
}
|
||||||
|
}, [messages, id, setDerivedMessages]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
reference,
|
||||||
|
loading,
|
||||||
|
derivedMessages,
|
||||||
|
ref,
|
||||||
|
addNewestQuestion,
|
||||||
|
addNewestAnswer,
|
||||||
|
removeLatestMessage,
|
||||||
|
removeMessageById,
|
||||||
|
removeMessagesAfterCurrentMessage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const useSendMessage = (
|
export const useSendMessage = (
|
||||||
addNewestQuestion: (message: Message, answer?: string) => void,
|
addNewestQuestion: (message: Message, answer?: string) => void,
|
||||||
removeLatestMessage: () => void,
|
removeLatestMessage: () => void,
|
||||||
@ -160,3 +197,84 @@ export const useSendMessage = (
|
|||||||
loading: !done,
|
loading: !done,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSendNextMessage = () => {
|
||||||
|
const {
|
||||||
|
reference,
|
||||||
|
loading,
|
||||||
|
derivedMessages,
|
||||||
|
ref,
|
||||||
|
addNewestQuestion,
|
||||||
|
addNewestAnswer,
|
||||||
|
removeLatestMessage,
|
||||||
|
removeMessageById,
|
||||||
|
} = useSelectNextMessages();
|
||||||
|
const { id: flowId } = useParams();
|
||||||
|
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||||
|
const { refetch } = useFetchFlow();
|
||||||
|
|
||||||
|
const { send, answer, done } = useSendMessageWithSse(api.runCanvas);
|
||||||
|
|
||||||
|
const sendMessage = useCallback(
|
||||||
|
async ({ message }: { message: Message; messages?: Message[] }) => {
|
||||||
|
const params: Record<string, unknown> = {
|
||||||
|
id: flowId,
|
||||||
|
};
|
||||||
|
if (message.content) {
|
||||||
|
params.message = message.content;
|
||||||
|
params.message_id = message.id;
|
||||||
|
}
|
||||||
|
const res = await send(params);
|
||||||
|
|
||||||
|
if (receiveMessageError(res)) {
|
||||||
|
antMessage.error(res?.data?.retmsg);
|
||||||
|
|
||||||
|
// cancel loading
|
||||||
|
setValue(message.content);
|
||||||
|
removeLatestMessage();
|
||||||
|
} else {
|
||||||
|
refetch(); // pull the message list after sending the message successfully
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[flowId, removeLatestMessage, setValue, send, refetch],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSendMessage = useCallback(
|
||||||
|
async (message: Message) => {
|
||||||
|
sendMessage({ message });
|
||||||
|
},
|
||||||
|
[sendMessage],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (answer.answer) {
|
||||||
|
addNewestAnswer(answer);
|
||||||
|
}
|
||||||
|
}, [answer, addNewestAnswer]);
|
||||||
|
|
||||||
|
const handlePressEnter = useCallback(() => {
|
||||||
|
if (trim(value) === '') return;
|
||||||
|
const id = uuid();
|
||||||
|
if (done) {
|
||||||
|
setValue('');
|
||||||
|
handleSendMessage({ id, content: value.trim(), role: MessageType.User });
|
||||||
|
}
|
||||||
|
addNewestQuestion({
|
||||||
|
content: value,
|
||||||
|
id,
|
||||||
|
role: MessageType.User,
|
||||||
|
});
|
||||||
|
}, [addNewestQuestion, handleSendMessage, done, setValue, value]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handlePressEnter,
|
||||||
|
handleInputChange,
|
||||||
|
value,
|
||||||
|
sendLoading: !done,
|
||||||
|
reference,
|
||||||
|
loading,
|
||||||
|
derivedMessages,
|
||||||
|
ref,
|
||||||
|
removeMessageById,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -23,3 +23,12 @@ export const getMessagePureId = (id?: string) => {
|
|||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const buildMessageListWithUuid = (messages?: Message[]) => {
|
||||||
|
return (
|
||||||
|
messages?.map((x: Message | IMessage) => ({
|
||||||
|
...x,
|
||||||
|
id: buildMessageUuid(x),
|
||||||
|
})) ?? []
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user