mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-26 00:46:52 +08:00
### What problem does this PR solve? Feat: Share agent dialog box externally #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,8 +1,7 @@
|
||||
import { MessageType } from '@/constants/chat';
|
||||
import { useGetFileIcon } from '@/pages/chat/hooks';
|
||||
import { Spin } from 'antd';
|
||||
|
||||
import { useSendNextMessage } from './hooks';
|
||||
import { useSendAgentMessage } from './use-send-agent-message';
|
||||
|
||||
import MessageInput from '@/components/message-input';
|
||||
import MessageItem from '@/components/next-message-item';
|
||||
@ -25,13 +24,12 @@ const AgentChatBox = () => {
|
||||
handleInputChange,
|
||||
handlePressEnter,
|
||||
value,
|
||||
loading,
|
||||
ref,
|
||||
derivedMessages,
|
||||
stopOutputMessage,
|
||||
sendFormMessage,
|
||||
findReferenceByMessageId,
|
||||
} = useSendNextMessage();
|
||||
} = useSendAgentMessage();
|
||||
|
||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||
useClickDrawer();
|
||||
@ -73,36 +71,36 @@ const AgentChatBox = () => {
|
||||
<section className="flex flex-1 flex-col px-5 h-[90vh]">
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div>
|
||||
<Spin spinning={loading}>
|
||||
{derivedMessages?.map((message, i) => {
|
||||
return (
|
||||
<MessageItem
|
||||
loading={
|
||||
message.role === MessageType.Assistant &&
|
||||
sendLoading &&
|
||||
derivedMessages.length - 1 === i
|
||||
}
|
||||
key={buildMessageUuidWithRole(message)}
|
||||
nickname={userInfo.nickname}
|
||||
avatar={userInfo.avatar}
|
||||
avatarDialog={canvasInfo.avatar}
|
||||
item={message}
|
||||
reference={findReferenceByMessageId(message.id)}
|
||||
clickDocumentButton={clickDocumentButton}
|
||||
index={i}
|
||||
showLikeButton={false}
|
||||
sendLoading={sendLoading}
|
||||
>
|
||||
<DebugContent
|
||||
parameters={buildInputList(message)}
|
||||
ok={handleOk(message)}
|
||||
isNext={false}
|
||||
btnText={'Submit'}
|
||||
></DebugContent>
|
||||
</MessageItem>
|
||||
);
|
||||
})}
|
||||
</Spin>
|
||||
{/* <Spin spinning={sendLoading}> */}
|
||||
{derivedMessages?.map((message, i) => {
|
||||
return (
|
||||
<MessageItem
|
||||
loading={
|
||||
message.role === MessageType.Assistant &&
|
||||
sendLoading &&
|
||||
derivedMessages.length - 1 === i
|
||||
}
|
||||
key={buildMessageUuidWithRole(message)}
|
||||
nickname={userInfo.nickname}
|
||||
avatar={userInfo.avatar}
|
||||
avatarDialog={canvasInfo.avatar}
|
||||
item={message}
|
||||
reference={findReferenceByMessageId(message.id)}
|
||||
clickDocumentButton={clickDocumentButton}
|
||||
index={i}
|
||||
showLikeButton={false}
|
||||
sendLoading={sendLoading}
|
||||
>
|
||||
<DebugContent
|
||||
parameters={buildInputList(message)}
|
||||
ok={handleOk(message)}
|
||||
isNext={false}
|
||||
btnText={'Submit'}
|
||||
></DebugContent>
|
||||
</MessageItem>
|
||||
);
|
||||
})}
|
||||
{/* </Spin> */}
|
||||
</div>
|
||||
<div ref={ref} />
|
||||
</div>
|
||||
|
||||
@ -4,7 +4,6 @@ import {
|
||||
useHandleMessageInputChange,
|
||||
useSelectDerivedMessages,
|
||||
} from '@/hooks/logic-hooks';
|
||||
import { useFetchAgent } from '@/hooks/use-agent-request';
|
||||
import {
|
||||
IEventList,
|
||||
IInputEvent,
|
||||
@ -30,37 +29,7 @@ import { BeginQuery } from '../interface';
|
||||
import useGraphStore from '../store';
|
||||
import { receiveMessageError } from '../utils';
|
||||
|
||||
export const useSelectNextMessages = () => {
|
||||
const { data: flowDetail, loading } = useFetchAgent();
|
||||
const reference = flowDetail.dsl.retrieval;
|
||||
const {
|
||||
derivedMessages,
|
||||
ref,
|
||||
addNewestQuestion,
|
||||
addNewestAnswer,
|
||||
removeLatestMessage,
|
||||
removeMessageById,
|
||||
removeMessagesAfterCurrentMessage,
|
||||
addNewestOneQuestion,
|
||||
addNewestOneAnswer,
|
||||
} = useSelectDerivedMessages();
|
||||
|
||||
return {
|
||||
reference,
|
||||
loading,
|
||||
derivedMessages,
|
||||
ref,
|
||||
addNewestQuestion,
|
||||
addNewestAnswer,
|
||||
removeLatestMessage,
|
||||
removeMessageById,
|
||||
addNewestOneQuestion,
|
||||
addNewestOneAnswer,
|
||||
removeMessagesAfterCurrentMessage,
|
||||
};
|
||||
};
|
||||
|
||||
function findMessageFromList(eventList: IEventList) {
|
||||
export function findMessageFromList(eventList: IEventList) {
|
||||
const messageEventList = eventList.filter(
|
||||
(x) => x.event === MessageEventType.Message,
|
||||
) as IMessageEvent[];
|
||||
@ -101,7 +70,7 @@ function findMessageFromList(eventList: IEventList) {
|
||||
};
|
||||
}
|
||||
|
||||
function findInputFromList(eventList: IEventList) {
|
||||
export function findInputFromList(eventList: IEventList) {
|
||||
const inputEvent = eventList.find(
|
||||
(x) => x.event === MessageEventType.UserInputs,
|
||||
) as IInputEvent;
|
||||
@ -120,7 +89,7 @@ export function getLatestError(eventList: IEventList) {
|
||||
return get(eventList.at(-1), 'data.outputs._ERROR');
|
||||
}
|
||||
|
||||
const useGetBeginNodePrologue = () => {
|
||||
export const useGetBeginNodePrologue = () => {
|
||||
const getNode = useGraphStore((state) => state.getNode);
|
||||
|
||||
return useMemo(() => {
|
||||
@ -131,31 +100,61 @@ const useGetBeginNodePrologue = () => {
|
||||
}, [getNode]);
|
||||
};
|
||||
|
||||
export const useSendNextMessage = () => {
|
||||
export function useFindMessageReference(answerList: IEventList) {
|
||||
const [messageEndEventList, setMessageEndEventList] = useState<
|
||||
IMessageEndEvent[]
|
||||
>([]);
|
||||
|
||||
const findReferenceByMessageId = useCallback(
|
||||
(messageId: string) => {
|
||||
const event = messageEndEventList.find(
|
||||
(item) => item.message_id === messageId,
|
||||
);
|
||||
if (event) {
|
||||
return (event?.data as IMessageEndData)?.reference;
|
||||
}
|
||||
},
|
||||
[messageEndEventList],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const messageEndEvent = answerList.find(
|
||||
(x) => x.event === MessageEventType.MessageEnd,
|
||||
);
|
||||
if (messageEndEvent) {
|
||||
setMessageEndEventList((list) => {
|
||||
const nextList = [...list];
|
||||
if (
|
||||
nextList.every((x) => x.message_id !== messageEndEvent.message_id)
|
||||
) {
|
||||
nextList.push(messageEndEvent as IMessageEndEvent);
|
||||
}
|
||||
return nextList;
|
||||
});
|
||||
}
|
||||
}, [answerList]);
|
||||
|
||||
return { findReferenceByMessageId };
|
||||
}
|
||||
|
||||
export const useSendAgentMessage = (url?: string) => {
|
||||
const { id: agentId } = useParams();
|
||||
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||
const inputs = useSelectBeginNodeDataInputs();
|
||||
const { send, answerList, done, stopOutputMessage } = useSendMessageBySSE(
|
||||
url || api.runCanvas,
|
||||
);
|
||||
const { findReferenceByMessageId } = useFindMessageReference(answerList);
|
||||
const prologue = useGetBeginNodePrologue();
|
||||
const {
|
||||
reference,
|
||||
loading,
|
||||
derivedMessages,
|
||||
ref,
|
||||
removeLatestMessage,
|
||||
removeMessageById,
|
||||
addNewestOneQuestion,
|
||||
addNewestOneAnswer,
|
||||
} = useSelectNextMessages();
|
||||
const { id: agentId } = useParams();
|
||||
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||
const { refetch } = useFetchAgent();
|
||||
} = useSelectDerivedMessages();
|
||||
const { addEventList } = useContext(AgentChatLogContext);
|
||||
const inputs = useSelectBeginNodeDataInputs();
|
||||
const [messageEndEventList, setMessageEndEventList] = useState<
|
||||
IMessageEndEvent[]
|
||||
>([]);
|
||||
|
||||
const { send, answerList, done, stopOutputMessage } = useSendMessageBySSE(
|
||||
api.runCanvas,
|
||||
);
|
||||
|
||||
const prologue = useGetBeginNodePrologue();
|
||||
|
||||
const sendMessage = useCallback(
|
||||
async ({ message }: { message: Message; messages?: Message[] }) => {
|
||||
@ -182,62 +181,12 @@ export const useSendNextMessage = () => {
|
||||
setValue(message.content);
|
||||
removeLatestMessage();
|
||||
} else {
|
||||
refetch(); // pull the message list after sending the message successfully
|
||||
// refetch(); // pull the message list after sending the message successfully
|
||||
}
|
||||
},
|
||||
[agentId, send, inputs, setValue, removeLatestMessage, refetch],
|
||||
[agentId, send, inputs, setValue, removeLatestMessage],
|
||||
);
|
||||
|
||||
const handleSendMessage = useCallback(
|
||||
async (message: Message) => {
|
||||
sendMessage({ message });
|
||||
},
|
||||
[sendMessage],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const messageEndEvent = answerList.find(
|
||||
(x) => x.event === MessageEventType.MessageEnd,
|
||||
);
|
||||
if (messageEndEvent) {
|
||||
setMessageEndEventList((list) => {
|
||||
const nextList = [...list];
|
||||
if (
|
||||
nextList.every((x) => x.message_id !== messageEndEvent.message_id)
|
||||
) {
|
||||
nextList.push(messageEndEvent as IMessageEndEvent);
|
||||
}
|
||||
return nextList;
|
||||
});
|
||||
}
|
||||
}, [addEventList.length, answerList]);
|
||||
|
||||
useEffect(() => {
|
||||
const { content, id } = findMessageFromList(answerList);
|
||||
const inputAnswer = findInputFromList(answerList);
|
||||
if (answerList.length > 0) {
|
||||
addNewestOneAnswer({
|
||||
answer: content || getLatestError(answerList),
|
||||
id: id,
|
||||
...inputAnswer,
|
||||
});
|
||||
}
|
||||
}, [answerList, addNewestOneAnswer]);
|
||||
|
||||
const handlePressEnter = useCallback(() => {
|
||||
if (trim(value) === '') return;
|
||||
const id = uuid();
|
||||
if (done) {
|
||||
setValue('');
|
||||
handleSendMessage({ id, content: value.trim(), role: MessageType.User });
|
||||
}
|
||||
addNewestOneQuestion({
|
||||
content: value,
|
||||
id,
|
||||
role: MessageType.User,
|
||||
});
|
||||
}, [value, done, addNewestOneQuestion, setValue, handleSendMessage]);
|
||||
|
||||
const sendFormMessage = useCallback(
|
||||
(body: { id?: string; inputs: Record<string, BeginQuery> }) => {
|
||||
send(body);
|
||||
@ -251,17 +200,33 @@ export const useSendNextMessage = () => {
|
||||
[addNewestOneQuestion, send],
|
||||
);
|
||||
|
||||
const findReferenceByMessageId = useCallback(
|
||||
(messageId: string) => {
|
||||
const event = messageEndEventList.find(
|
||||
(item) => item.message_id === messageId,
|
||||
);
|
||||
if (event) {
|
||||
return (event?.data as IMessageEndData)?.reference;
|
||||
}
|
||||
},
|
||||
[messageEndEventList],
|
||||
);
|
||||
const handlePressEnter = useCallback(() => {
|
||||
if (trim(value) === '') return;
|
||||
const id = uuid();
|
||||
if (done) {
|
||||
setValue('');
|
||||
sendMessage({
|
||||
message: { id, content: value.trim(), role: MessageType.User },
|
||||
});
|
||||
}
|
||||
addNewestOneQuestion({
|
||||
content: value,
|
||||
id,
|
||||
role: MessageType.User,
|
||||
});
|
||||
}, [value, done, addNewestOneQuestion, setValue, sendMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
const { content, id } = findMessageFromList(answerList);
|
||||
const inputAnswer = findInputFromList(answerList);
|
||||
if (answerList.length > 0) {
|
||||
addNewestOneAnswer({
|
||||
answer: content || getLatestError(answerList),
|
||||
id: id,
|
||||
...inputAnswer,
|
||||
});
|
||||
}
|
||||
}, [answerList, addNewestOneAnswer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (prologue) {
|
||||
@ -272,7 +237,9 @@ export const useSendNextMessage = () => {
|
||||
}, [addNewestOneAnswer, agentId, prologue, send, sendFormMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
addEventList(answerList);
|
||||
if (typeof addEventList === 'function') {
|
||||
addEventList(answerList);
|
||||
}
|
||||
}, [addEventList, answerList]);
|
||||
|
||||
return {
|
||||
@ -280,8 +247,6 @@ export const useSendNextMessage = () => {
|
||||
handleInputChange,
|
||||
value,
|
||||
sendLoading: !done,
|
||||
reference,
|
||||
loading,
|
||||
derivedMessages,
|
||||
ref,
|
||||
removeMessageById,
|
||||
@ -68,7 +68,7 @@ function EmbedDialog({
|
||||
|
||||
const generateIframeSrc = useCallback(() => {
|
||||
const { visibleAvatar, locale } = values;
|
||||
let src = `${location.origin}/chat/share?shared_id=${token}&from=${from}&auth=${beta}`;
|
||||
let src = `${location.origin}/next-chat/share?shared_id=${token}&from=${from}&auth=${beta}`;
|
||||
if (visibleAvatar) {
|
||||
src += '&visible_avatar=1';
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
import { SharedFrom } from '@/constants/chat';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||
import { ReactFlowProvider } from '@xyflow/react';
|
||||
import {
|
||||
ChevronDown,
|
||||
@ -37,7 +38,10 @@ import AgentCanvas from './canvas';
|
||||
import EmbedDialog from './embed-dialog';
|
||||
import { useHandleExportOrImportJsonFile } from './hooks/use-export-json';
|
||||
import { useFetchDataOnMount } from './hooks/use-fetch-data';
|
||||
import { useGetBeginNodeDataInputs } from './hooks/use-get-begin-query';
|
||||
import {
|
||||
useGetBeginNodeDataInputs,
|
||||
useGetBeginNodeDataQueryIsSafe,
|
||||
} from './hooks/use-get-begin-query';
|
||||
import { useOpenDocument } from './hooks/use-open-document';
|
||||
import {
|
||||
useSaveGraph,
|
||||
@ -67,6 +71,8 @@ export default function Agent() {
|
||||
showModal: showChatDrawer,
|
||||
} = useSetModalState();
|
||||
const { t } = useTranslation();
|
||||
const { data: userInfo } = useFetchUserInfo();
|
||||
|
||||
const openDocument = useOpenDocument();
|
||||
const {
|
||||
handleExportJson,
|
||||
@ -76,7 +82,7 @@ export default function Agent() {
|
||||
hideFileUploadModal,
|
||||
} = useHandleExportOrImportJsonFile();
|
||||
const { saveGraph, loading } = useSaveGraph();
|
||||
const { flowDetail } = useFetchDataOnMount();
|
||||
const { flowDetail: agentDetail } = useFetchDataOnMount();
|
||||
const inputs = useGetBeginNodeDataInputs();
|
||||
const { handleRun } = useSaveGraphBeforeOpeningDebugDrawer(showChatDrawer);
|
||||
const handleRunAgent = useCallback(() => {
|
||||
@ -95,6 +101,8 @@ export default function Agent() {
|
||||
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
|
||||
useShowEmbedModal();
|
||||
|
||||
const isBeginNodeDataQuerySafe = useGetBeginNodeDataQueryIsSafe();
|
||||
|
||||
return (
|
||||
<section className="h-full">
|
||||
<PageHeader>
|
||||
@ -107,7 +115,7 @@ export default function Agent() {
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>{flowDetail.title}</BreadcrumbPage>
|
||||
<BreadcrumbPage>{agentDetail.title}</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
@ -154,7 +162,13 @@ export default function Agent() {
|
||||
{t('flow.export')}
|
||||
</AgentDropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<AgentDropdownMenuItem onClick={showEmbedModal}>
|
||||
<AgentDropdownMenuItem
|
||||
onClick={showEmbedModal}
|
||||
disabled={
|
||||
!isBeginNodeDataQuerySafe ||
|
||||
userInfo.nickname !== agentDetail.nickname
|
||||
}
|
||||
>
|
||||
<ScreenShare />
|
||||
{t('common.embedIntoSite')}
|
||||
</AgentDropdownMenuItem>
|
||||
|
||||
Reference in New Issue
Block a user