mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-23 23:16: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:
@ -5,44 +5,38 @@ import { Drawer, Flex, Spin } from 'antd';
|
||||
import {
|
||||
useClickDrawer,
|
||||
useCreateConversationBeforeUploadDocument,
|
||||
useFetchConversationOnMount,
|
||||
useGetFileIcon,
|
||||
useGetSendButtonDisabled,
|
||||
useSendButtonDisabled,
|
||||
useSendMessage,
|
||||
useSendNextMessage,
|
||||
} from '../hooks';
|
||||
import { buildMessageItemReference } from '../utils';
|
||||
|
||||
import MessageInput from '@/components/message-input';
|
||||
import {
|
||||
useFetchNextConversation,
|
||||
useGetChatSearchParams,
|
||||
} from '@/hooks/chat-hooks';
|
||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||
import { memo } from 'react';
|
||||
import styles from './index.less';
|
||||
|
||||
const ChatContainer = () => {
|
||||
const { conversationId } = useGetChatSearchParams();
|
||||
const { data: conversation } = useFetchNextConversation();
|
||||
|
||||
const {
|
||||
ref,
|
||||
currentConversation: conversation,
|
||||
addNewestConversation,
|
||||
removeLatestMessage,
|
||||
addNewestAnswer,
|
||||
conversationId,
|
||||
loading,
|
||||
removeMessageById,
|
||||
removeMessagesAfterCurrentMessage,
|
||||
} = useFetchConversationOnMount();
|
||||
const {
|
||||
sendLoading,
|
||||
derivedMessages,
|
||||
handleInputChange,
|
||||
handlePressEnter,
|
||||
value,
|
||||
loading: sendLoading,
|
||||
regenerateMessage,
|
||||
} = useSendMessage(
|
||||
conversation,
|
||||
addNewestConversation,
|
||||
removeLatestMessage,
|
||||
addNewestAnswer,
|
||||
removeMessagesAfterCurrentMessage,
|
||||
);
|
||||
removeMessageById,
|
||||
} = useSendNextMessage();
|
||||
|
||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||
useClickDrawer();
|
||||
const disabled = useGetSendButtonDisabled();
|
||||
@ -58,19 +52,25 @@ const ChatContainer = () => {
|
||||
<Flex flex={1} vertical className={styles.messageContainer}>
|
||||
<div>
|
||||
<Spin spinning={loading}>
|
||||
{conversation?.message?.map((message, i) => {
|
||||
{derivedMessages?.map((message, i) => {
|
||||
return (
|
||||
<MessageItem
|
||||
loading={
|
||||
message.role === MessageType.Assistant &&
|
||||
sendLoading &&
|
||||
conversation?.message.length - 1 === i
|
||||
derivedMessages.length - 1 === i
|
||||
}
|
||||
key={message.id}
|
||||
item={message}
|
||||
nickname={userInfo.nickname}
|
||||
avatar={userInfo.avatar}
|
||||
reference={buildMessageItemReference(conversation, message)}
|
||||
reference={buildMessageItemReference(
|
||||
{
|
||||
message: derivedMessages,
|
||||
reference: conversation.reference,
|
||||
},
|
||||
message,
|
||||
)}
|
||||
clickDocumentButton={clickDocumentButton}
|
||||
index={i}
|
||||
removeMessageById={removeMessageById}
|
||||
|
||||
@ -21,6 +21,8 @@ import {
|
||||
useRegenerateMessage,
|
||||
useRemoveMessageById,
|
||||
useRemoveMessagesAfterCurrentMessage,
|
||||
useScrollToBottom,
|
||||
useSelectDerivedMessages,
|
||||
useSendMessageWithSse,
|
||||
} from '@/hooks/logic-hooks';
|
||||
import {
|
||||
@ -40,7 +42,6 @@ import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useSearchParams } from 'umi';
|
||||
@ -362,20 +363,71 @@ export const useSelectCurrentConversation = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const useScrollToBottom = (currentConversation: IClientConversation) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
// export const useScrollToBottom = (currentConversation: IClientConversation) => {
|
||||
// const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
const scrollToBottom = useCallback(() => {
|
||||
if (currentConversation.id) {
|
||||
ref.current?.scrollIntoView({ behavior: 'instant' });
|
||||
// const scrollToBottom = useCallback(() => {
|
||||
// if (currentConversation.id) {
|
||||
// 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(() => {
|
||||
scrollToBottom();
|
||||
}, [scrollToBottom]);
|
||||
addPrologue();
|
||||
}, [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 = () => {
|
||||
@ -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 = () => {
|
||||
const getFileIcon = (filename: string) => {
|
||||
const ext: string = getFileExtension(filename);
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import MessageInput from '@/components/message-input';
|
||||
import MessageItem from '@/components/message-item';
|
||||
import { MessageType, SharedFrom } from '@/constants/chat';
|
||||
import { useFetchNextSharedConversation } from '@/hooks/chat-hooks';
|
||||
import { useSendButtonDisabled } from '@/pages/chat/hooks';
|
||||
import { Flex, Spin } from 'antd';
|
||||
import { forwardRef } from 'react';
|
||||
import {
|
||||
useCreateSharedConversationOnMount,
|
||||
useGetSharedChatSearchParams,
|
||||
useSelectCurrentSharedConversation,
|
||||
useSendSharedMessage,
|
||||
} from '../shared-hooks';
|
||||
import { buildMessageItemReference } from '../utils';
|
||||
@ -15,28 +15,17 @@ import styles from './index.less';
|
||||
|
||||
const ChatContainer = () => {
|
||||
const { conversationId } = useCreateSharedConversationOnMount();
|
||||
const {
|
||||
currentConversation: conversation,
|
||||
addNewestConversation,
|
||||
removeLatestMessage,
|
||||
ref,
|
||||
loading,
|
||||
setCurrentConversation,
|
||||
addNewestAnswer,
|
||||
} = useSelectCurrentSharedConversation(conversationId);
|
||||
const { data } = useFetchNextSharedConversation(conversationId);
|
||||
|
||||
const {
|
||||
handlePressEnter,
|
||||
handleInputChange,
|
||||
value,
|
||||
loading: sendLoading,
|
||||
} = useSendSharedMessage(
|
||||
conversation,
|
||||
addNewestConversation,
|
||||
removeLatestMessage,
|
||||
setCurrentConversation,
|
||||
addNewestAnswer,
|
||||
);
|
||||
sendLoading,
|
||||
loading,
|
||||
ref,
|
||||
derivedMessages,
|
||||
} = useSendSharedMessage(conversationId);
|
||||
const sendDisabled = useSendButtonDisabled(value);
|
||||
const { from } = useGetSharedChatSearchParams();
|
||||
|
||||
@ -46,17 +35,23 @@ const ChatContainer = () => {
|
||||
<Flex flex={1} vertical className={styles.messageContainer}>
|
||||
<div>
|
||||
<Spin spinning={loading}>
|
||||
{conversation?.message?.map((message, i) => {
|
||||
{derivedMessages?.map((message, i) => {
|
||||
return (
|
||||
<MessageItem
|
||||
key={message.id}
|
||||
item={message}
|
||||
nickname="You"
|
||||
reference={buildMessageItemReference(conversation, message)}
|
||||
reference={buildMessageItemReference(
|
||||
{
|
||||
message: derivedMessages,
|
||||
reference: data?.data?.reference,
|
||||
},
|
||||
message,
|
||||
)}
|
||||
loading={
|
||||
message.role === MessageType.Assistant &&
|
||||
sendLoading &&
|
||||
conversation?.message.length - 1 === i
|
||||
derivedMessages?.length - 1 === i
|
||||
}
|
||||
index={i}
|
||||
></MessageItem>
|
||||
|
||||
@ -3,22 +3,17 @@ import {
|
||||
useCreateNextSharedConversation,
|
||||
useFetchNextSharedConversation,
|
||||
} 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 {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
useSelectDerivedMessages,
|
||||
useSendMessageWithSse,
|
||||
} from '@/hooks/logic-hooks';
|
||||
import { Message } from '@/interfaces/database/chat';
|
||||
import api from '@/utils/api';
|
||||
import trim from 'lodash/trim';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'umi';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { useHandleMessageInputChange, useScrollToBottom } from './hooks';
|
||||
import { IClientConversation, IMessage } from './interface';
|
||||
import { useHandleMessageInputChange } from './hooks';
|
||||
|
||||
export const useCreateSharedConversationOnMount = () => {
|
||||
const [currentQueryParameters] = useSearchParams();
|
||||
@ -46,91 +41,30 @@ export const useCreateSharedConversationOnMount = () => {
|
||||
return { conversationId };
|
||||
};
|
||||
|
||||
export const useSelectCurrentSharedConversation = (conversationId: string) => {
|
||||
const [currentConversation, setCurrentConversation] =
|
||||
useState<IClientConversation>({} as IClientConversation);
|
||||
const { fetchConversation, loading } = useFetchNextSharedConversation();
|
||||
export const useSelectNextSharedMessages = (conversationId: string) => {
|
||||
const { data, loading } = useFetchNextSharedConversation(conversationId);
|
||||
|
||||
const ref = useScrollToBottom(currentConversation);
|
||||
|
||||
const addNewestConversation = useCallback((message: Partial<Message>) => {
|
||||
setCurrentConversation((pre) => {
|
||||
return {
|
||||
...pre,
|
||||
message: [
|
||||
...(pre.message ?? []),
|
||||
{
|
||||
...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]);
|
||||
const {
|
||||
derivedMessages,
|
||||
ref,
|
||||
setDerivedMessages,
|
||||
addNewestAnswer,
|
||||
addNewestQuestion,
|
||||
removeLatestMessage,
|
||||
} = useSelectDerivedMessages();
|
||||
|
||||
useEffect(() => {
|
||||
fetchConversationOnMount();
|
||||
}, [fetchConversationOnMount]);
|
||||
setDerivedMessages(data?.data?.message);
|
||||
}, [setDerivedMessages, data]);
|
||||
|
||||
return {
|
||||
currentConversation,
|
||||
addNewestConversation,
|
||||
derivedMessages,
|
||||
addNewestAnswer,
|
||||
addNewestQuestion,
|
||||
removeLatestMessage,
|
||||
loading,
|
||||
ref,
|
||||
setCurrentConversation,
|
||||
addNewestAnswer,
|
||||
setDerivedMessages,
|
||||
};
|
||||
};
|
||||
|
||||
@ -138,28 +72,28 @@ export const useSendButtonDisabled = (value: string) => {
|
||||
return trim(value) === '';
|
||||
};
|
||||
|
||||
export const useSendSharedMessage = (
|
||||
conversation: IClientConversation,
|
||||
addNewestConversation: (message: Partial<Message>, answer?: string) => void,
|
||||
removeLatestMessage: () => void,
|
||||
setCurrentConversation: Dispatch<SetStateAction<IClientConversation>>,
|
||||
addNewestAnswer: (answer: IAnswer) => void,
|
||||
) => {
|
||||
const conversationId = conversation.id;
|
||||
export const useSendSharedMessage = (conversationId: string) => {
|
||||
const { createSharedConversation: setConversation } =
|
||||
useCreateNextSharedConversation();
|
||||
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||
|
||||
const { send, answer, done } = useSendMessageWithSse(
|
||||
api.completeExternalConversation,
|
||||
);
|
||||
const {
|
||||
derivedMessages,
|
||||
ref,
|
||||
removeLatestMessage,
|
||||
addNewestAnswer,
|
||||
addNewestQuestion,
|
||||
loading,
|
||||
} = useSelectNextSharedMessages(conversationId);
|
||||
|
||||
const sendMessage = useCallback(
|
||||
async (message: Message, id?: string) => {
|
||||
const res = await send({
|
||||
conversation_id: id ?? conversationId,
|
||||
quote: false,
|
||||
messages: [...(conversation?.message ?? []), message],
|
||||
messages: [...(derivedMessages ?? []), message],
|
||||
});
|
||||
|
||||
if (res && (res?.response.status !== 200 || res?.data?.retcode !== 0)) {
|
||||
@ -168,15 +102,7 @@ export const useSendSharedMessage = (
|
||||
removeLatestMessage();
|
||||
}
|
||||
},
|
||||
[
|
||||
conversationId,
|
||||
conversation?.message,
|
||||
// fetchConversation,
|
||||
removeLatestMessage,
|
||||
setValue,
|
||||
send,
|
||||
// setCurrentConversation,
|
||||
],
|
||||
[conversationId, derivedMessages, removeLatestMessage, setValue, send],
|
||||
);
|
||||
|
||||
const handleSendMessage = useCallback(
|
||||
@ -206,7 +132,7 @@ export const useSendSharedMessage = (
|
||||
const id = uuid();
|
||||
if (done) {
|
||||
setValue('');
|
||||
addNewestConversation({
|
||||
addNewestQuestion({
|
||||
content: value,
|
||||
doc_ids: documentIds,
|
||||
id,
|
||||
@ -219,14 +145,17 @@ export const useSendSharedMessage = (
|
||||
});
|
||||
}
|
||||
},
|
||||
[addNewestConversation, done, handleSendMessage, setValue, value],
|
||||
[addNewestQuestion, done, handleSendMessage, setValue, value],
|
||||
);
|
||||
|
||||
return {
|
||||
handlePressEnter,
|
||||
handleInputChange,
|
||||
value,
|
||||
loading: !done,
|
||||
sendLoading: !done,
|
||||
ref,
|
||||
loading,
|
||||
derivedMessages,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ export const buildMessageItemReference = (
|
||||
);
|
||||
const reference = message?.reference
|
||||
? message?.reference
|
||||
: conversation.reference[referenceIndex];
|
||||
: (conversation?.reference ?? {})[referenceIndex];
|
||||
|
||||
return reference;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user