mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-04 03:25:30 +08:00
### What problem does this PR solve? ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: jinhai <haijin.chn@gmail.com> Signed-off-by: Jin Hai <haijin.chn@gmail.com> Co-authored-by: Lynn <lynn_inf@hotmail.com> Co-authored-by: chanx <1243304602@qq.com> Co-authored-by: balibabu <cike8899@users.noreply.github.com> Co-authored-by: 纷繁下的无奈 <zhileihuang@126.com> Co-authored-by: huangzl <huangzl@shinemo.com> Co-authored-by: writinwaters <93570324+writinwaters@users.noreply.github.com> Co-authored-by: Wilmer <33392318@qq.com> Co-authored-by: Adrian Weidig <adrianweidig@gmx.net> Co-authored-by: Zhichang Yu <yuzhichang@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Yongteng Lei <yongtengrey@outlook.com> Co-authored-by: Liu An <asiro@qq.com> Co-authored-by: buua436 <66937541+buua436@users.noreply.github.com> Co-authored-by: BadwomanCraZY <511528396@qq.com> Co-authored-by: cucusenok <31804608+cucusenok@users.noreply.github.com> Co-authored-by: Russell Valentine <russ@coldstonelabs.org> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Billy Bao <newyorkupperbay@gmail.com> Co-authored-by: Zhedong Cen <cenzhedong2@126.com> Co-authored-by: TensorNull <129579691+TensorNull@users.noreply.github.com> Co-authored-by: TensorNull <tensor.null@gmail.com> Co-authored-by: Ajay <160579663+aybanda@users.noreply.github.com> Co-authored-by: AB <aj@Ajays-MacBook-Air.local> Co-authored-by: 天海蒼灆 <huangaoqin@tecpie.com> Co-authored-by: He Wang <wanghechn@qq.com> Co-authored-by: Atsushi Hatakeyama <atu729@icloud.com> Co-authored-by: Jin Hai <haijin.chn@gmail.com> Co-authored-by: Mohamed Mathari <155896313+melmathari@users.noreply.github.com> Co-authored-by: Mohamed Mathari <nocodeventure@Mac-mini-van-Mohamed.fritz.box> Co-authored-by: Stephen Hu <stephenhu@seismic.com> Co-authored-by: Shaun Zhang <zhangwfjh@users.noreply.github.com> Co-authored-by: zhimeng123 <60221886+zhimeng123@users.noreply.github.com> Co-authored-by: mxc <mxc@example.com> Co-authored-by: Dominik Novotný <50611433+SgtMarmite@users.noreply.github.com> Co-authored-by: EVGENY M <168018528+rjohny55@users.noreply.github.com> Co-authored-by: mcoder6425 <mcoder64@gmail.com> Co-authored-by: TeslaZY <TeslaZY@outlook.com> Co-authored-by: lemsn <lemsn@msn.com> Co-authored-by: lemsn <lemsn@126.com> Co-authored-by: Adrian Gora <47756404+adagora@users.noreply.github.com> Co-authored-by: Womsxd <45663319+Womsxd@users.noreply.github.com> Co-authored-by: FatMii <39074672+FatMii@users.noreply.github.com>
385 lines
11 KiB
TypeScript
385 lines
11 KiB
TypeScript
import { useIsDarkTheme, useTheme } from '@/components/theme-provider';
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipTrigger,
|
|
} from '@/components/ui/tooltip';
|
|
import { useSetModalState } from '@/hooks/common-hooks';
|
|
import { cn } from '@/lib/utils';
|
|
import {
|
|
ConnectionMode,
|
|
ControlButton,
|
|
Controls,
|
|
NodeTypes,
|
|
Position,
|
|
ReactFlow,
|
|
} from '@xyflow/react';
|
|
import '@xyflow/react/dist/style.css';
|
|
import { NotebookPen } from 'lucide-react';
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { ChatSheet } from '../chat/chat-sheet';
|
|
import { AgentBackground } from '../components/background';
|
|
import {
|
|
AgentChatContext,
|
|
AgentChatLogContext,
|
|
AgentInstanceContext,
|
|
HandleContext,
|
|
} from '../context';
|
|
|
|
import FormSheet from '../form-sheet/next';
|
|
import {
|
|
useHandleDrop,
|
|
useSelectCanvasData,
|
|
useValidateConnection,
|
|
} from '../hooks';
|
|
import { useAddNode } from '../hooks/use-add-node';
|
|
import { useBeforeDelete } from '../hooks/use-before-delete';
|
|
import { useCacheChatLog } from '../hooks/use-cache-chat-log';
|
|
import { useConnectionDrag } from '../hooks/use-connection-drag';
|
|
import { useDropdownPosition } from '../hooks/use-dropdown-position';
|
|
import { useMoveNote } from '../hooks/use-move-note';
|
|
import { usePlaceholderManager } from '../hooks/use-placeholder-manager';
|
|
import { useDropdownManager } from './context';
|
|
|
|
import Spotlight from '@/components/spotlight';
|
|
import {
|
|
useHideFormSheetOnNodeDeletion,
|
|
useShowDrawer,
|
|
useShowLogSheet,
|
|
} from '../hooks/use-show-drawer';
|
|
import { LogSheet } from '../log-sheet';
|
|
import RunSheet from '../run-sheet';
|
|
import { ButtonEdge } from './edge';
|
|
import styles from './index.less';
|
|
import { RagNode } from './node';
|
|
import { AgentNode } from './node/agent-node';
|
|
import { BeginNode } from './node/begin-node';
|
|
import { CategorizeNode } from './node/categorize-node';
|
|
import { InnerNextStepDropdown } from './node/dropdown/next-step-dropdown';
|
|
import { GenerateNode } from './node/generate-node';
|
|
import { InvokeNode } from './node/invoke-node';
|
|
import { IterationNode, IterationStartNode } from './node/iteration-node';
|
|
import { KeywordNode } from './node/keyword-node';
|
|
import { LogicNode } from './node/logic-node';
|
|
import { MessageNode } from './node/message-node';
|
|
import NoteNode from './node/note-node';
|
|
import { PlaceholderNode } from './node/placeholder-node';
|
|
import { RelevantNode } from './node/relevant-node';
|
|
import { RetrievalNode } from './node/retrieval-node';
|
|
import { RewriteNode } from './node/rewrite-node';
|
|
import { SwitchNode } from './node/switch-node';
|
|
import { TemplateNode } from './node/template-node';
|
|
import { ToolNode } from './node/tool-node';
|
|
|
|
export const nodeTypes: NodeTypes = {
|
|
ragNode: RagNode,
|
|
categorizeNode: CategorizeNode,
|
|
beginNode: BeginNode,
|
|
placeholderNode: PlaceholderNode,
|
|
relevantNode: RelevantNode,
|
|
logicNode: LogicNode,
|
|
noteNode: NoteNode,
|
|
switchNode: SwitchNode,
|
|
generateNode: GenerateNode,
|
|
retrievalNode: RetrievalNode,
|
|
messageNode: MessageNode,
|
|
rewriteNode: RewriteNode,
|
|
keywordNode: KeywordNode,
|
|
invokeNode: InvokeNode,
|
|
templateNode: TemplateNode,
|
|
// emailNode: EmailNode,
|
|
group: IterationNode,
|
|
iterationStartNode: IterationStartNode,
|
|
agentNode: AgentNode,
|
|
toolNode: ToolNode,
|
|
};
|
|
|
|
const edgeTypes = {
|
|
buttonEdge: ButtonEdge,
|
|
};
|
|
|
|
interface IProps {
|
|
drawerVisible: boolean;
|
|
hideDrawer(): void;
|
|
}
|
|
|
|
function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
|
|
const { t } = useTranslation();
|
|
const {
|
|
nodes,
|
|
edges,
|
|
onConnect: originalOnConnect,
|
|
onEdgesChange,
|
|
onNodesChange,
|
|
onSelectionChange,
|
|
onEdgeMouseEnter,
|
|
onEdgeMouseLeave,
|
|
} = useSelectCanvasData();
|
|
const isValidConnection = useValidateConnection();
|
|
|
|
const { onDrop, onDragOver, setReactFlowInstance, reactFlowInstance } =
|
|
useHandleDrop();
|
|
|
|
const {
|
|
onNodeClick,
|
|
clickedNode,
|
|
formDrawerVisible,
|
|
hideFormDrawer,
|
|
singleDebugDrawerVisible,
|
|
hideSingleDebugDrawer,
|
|
showSingleDebugDrawer,
|
|
chatVisible,
|
|
runVisible,
|
|
hideRunOrChatDrawer,
|
|
showChatModal,
|
|
showFormDrawer,
|
|
} = useShowDrawer({
|
|
drawerVisible,
|
|
hideDrawer,
|
|
});
|
|
|
|
const {
|
|
addEventList,
|
|
setCurrentMessageId,
|
|
currentEventListWithoutMessageById,
|
|
clearEventList,
|
|
currentMessageId,
|
|
} = useCacheChatLog();
|
|
|
|
const { showLogSheet, logSheetVisible, hideLogSheet } = useShowLogSheet({
|
|
setCurrentMessageId,
|
|
});
|
|
const [lastSendLoading, setLastSendLoading] = useState(false);
|
|
|
|
const { handleBeforeDelete } = useBeforeDelete();
|
|
|
|
const { addCanvasNode, addNoteNode } = useAddNode(reactFlowInstance);
|
|
|
|
const { ref, showImage, hideImage, imgVisible, mouse } = useMoveNote();
|
|
|
|
const { theme } = useTheme();
|
|
|
|
useEffect(() => {
|
|
if (!chatVisible) {
|
|
clearEventList();
|
|
}
|
|
}, [chatVisible, clearEventList]);
|
|
const setLastSendLoadingFunc = (loading: boolean, messageId: string) => {
|
|
if (messageId === currentMessageId) {
|
|
setLastSendLoading(loading);
|
|
} else {
|
|
setLastSendLoading(false);
|
|
}
|
|
};
|
|
|
|
const isDarkTheme = useIsDarkTheme();
|
|
|
|
useHideFormSheetOnNodeDeletion({ hideFormDrawer });
|
|
|
|
const { visible, hideModal, showModal } = useSetModalState();
|
|
const [dropdownPosition, setDropdownPosition] = useState({ x: 0, y: 0 });
|
|
|
|
const { clearActiveDropdown } = useDropdownManager();
|
|
|
|
const { removePlaceholderNode, onNodeCreated, setCreatedPlaceholderRef } =
|
|
usePlaceholderManager(reactFlowInstance);
|
|
|
|
const { calculateDropdownPosition } = useDropdownPosition(reactFlowInstance);
|
|
|
|
const {
|
|
onConnectStart,
|
|
onConnectEnd,
|
|
handleConnect,
|
|
getConnectionStartContext,
|
|
shouldPreventClose,
|
|
onMove,
|
|
} = useConnectionDrag(
|
|
reactFlowInstance,
|
|
originalOnConnect,
|
|
showModal,
|
|
hideModal,
|
|
setDropdownPosition,
|
|
setCreatedPlaceholderRef,
|
|
calculateDropdownPosition,
|
|
removePlaceholderNode,
|
|
clearActiveDropdown,
|
|
);
|
|
|
|
const onPaneClick = useCallback(() => {
|
|
hideFormDrawer();
|
|
if (visible && !shouldPreventClose()) {
|
|
removePlaceholderNode();
|
|
hideModal();
|
|
clearActiveDropdown();
|
|
}
|
|
if (imgVisible) {
|
|
addNoteNode(mouse);
|
|
hideImage();
|
|
}
|
|
}, [
|
|
hideFormDrawer,
|
|
visible,
|
|
shouldPreventClose,
|
|
hideModal,
|
|
imgVisible,
|
|
addNoteNode,
|
|
mouse,
|
|
hideImage,
|
|
clearActiveDropdown,
|
|
removePlaceholderNode,
|
|
]);
|
|
|
|
return (
|
|
<div className={styles.canvasWrapper}>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
style={{ position: 'absolute', top: 10, left: 0 }}
|
|
>
|
|
<defs>
|
|
<marker
|
|
fill="rgb(157 149 225)"
|
|
id="logo"
|
|
viewBox="0 0 40 40"
|
|
refX="8"
|
|
refY="5"
|
|
markerUnits="strokeWidth"
|
|
markerWidth="20"
|
|
markerHeight="20"
|
|
orient="auto-start-reverse"
|
|
>
|
|
<path d="M 0 0 L 10 5 L 0 10 z" />
|
|
</marker>
|
|
</defs>
|
|
</svg>
|
|
<AgentInstanceContext.Provider value={{ addCanvasNode, showFormDrawer }}>
|
|
<ReactFlow
|
|
connectionMode={ConnectionMode.Loose}
|
|
nodes={nodes}
|
|
onNodesChange={onNodesChange}
|
|
edges={edges}
|
|
onEdgesChange={onEdgesChange}
|
|
fitView
|
|
onConnect={handleConnect}
|
|
nodeTypes={nodeTypes}
|
|
edgeTypes={edgeTypes}
|
|
onDrop={onDrop}
|
|
onConnectStart={onConnectStart}
|
|
onConnectEnd={onConnectEnd}
|
|
onMove={onMove}
|
|
onDragOver={onDragOver}
|
|
onNodeClick={onNodeClick}
|
|
onPaneClick={onPaneClick}
|
|
onInit={setReactFlowInstance}
|
|
onSelectionChange={onSelectionChange}
|
|
nodeOrigin={[0.5, 0]}
|
|
isValidConnection={isValidConnection}
|
|
onEdgeMouseEnter={onEdgeMouseEnter}
|
|
onEdgeMouseLeave={onEdgeMouseLeave}
|
|
className="h-full"
|
|
colorMode={theme}
|
|
defaultEdgeOptions={{
|
|
type: 'buttonEdge',
|
|
markerEnd: 'logo',
|
|
style: {
|
|
strokeWidth: 1,
|
|
stroke: isDarkTheme
|
|
? 'rgba(91, 93, 106, 1)'
|
|
: 'rgba(151, 154, 171, 1)',
|
|
},
|
|
zIndex: 1001, // https://github.com/xyflow/xyflow/discussions/3498
|
|
}}
|
|
deleteKeyCode={['Delete', 'Backspace']}
|
|
onBeforeDelete={handleBeforeDelete}
|
|
>
|
|
<AgentBackground></AgentBackground>
|
|
<Spotlight className="z-0" opcity={0.7} coverage={70} />
|
|
<Controls position={'bottom-center'} orientation="horizontal">
|
|
<ControlButton>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<NotebookPen className="!fill-none" onClick={showImage} />
|
|
</TooltipTrigger>
|
|
<TooltipContent>{t('flow.note')}</TooltipContent>
|
|
</Tooltip>
|
|
</ControlButton>
|
|
</Controls>
|
|
</ReactFlow>
|
|
{visible && (
|
|
<HandleContext.Provider
|
|
value={
|
|
getConnectionStartContext() || {
|
|
nodeId: '',
|
|
id: '',
|
|
type: 'source',
|
|
position: Position.Right,
|
|
isFromConnectionDrag: true,
|
|
}
|
|
}
|
|
>
|
|
<InnerNextStepDropdown
|
|
hideModal={() => {
|
|
removePlaceholderNode();
|
|
hideModal();
|
|
clearActiveDropdown();
|
|
}}
|
|
position={dropdownPosition}
|
|
onNodeCreated={onNodeCreated}
|
|
>
|
|
<span></span>
|
|
</InnerNextStepDropdown>
|
|
</HandleContext.Provider>
|
|
)}
|
|
</AgentInstanceContext.Provider>
|
|
<NotebookPen
|
|
className={cn('hidden absolute size-6', { block: imgVisible })}
|
|
ref={ref}
|
|
></NotebookPen>
|
|
{formDrawerVisible && (
|
|
<AgentInstanceContext.Provider
|
|
value={{ addCanvasNode, showFormDrawer }}
|
|
>
|
|
<FormSheet
|
|
node={clickedNode}
|
|
visible={formDrawerVisible}
|
|
hideModal={hideFormDrawer}
|
|
chatVisible={chatVisible}
|
|
singleDebugDrawerVisible={singleDebugDrawerVisible}
|
|
hideSingleDebugDrawer={hideSingleDebugDrawer}
|
|
showSingleDebugDrawer={showSingleDebugDrawer}
|
|
></FormSheet>
|
|
</AgentInstanceContext.Provider>
|
|
)}
|
|
{chatVisible && (
|
|
<AgentChatContext.Provider
|
|
value={{ showLogSheet, setLastSendLoadingFunc }}
|
|
>
|
|
<AgentChatLogContext.Provider
|
|
value={{ addEventList, setCurrentMessageId }}
|
|
>
|
|
<ChatSheet hideModal={hideRunOrChatDrawer}></ChatSheet>
|
|
</AgentChatLogContext.Provider>
|
|
</AgentChatContext.Provider>
|
|
)}
|
|
{runVisible && (
|
|
<RunSheet
|
|
hideModal={hideRunOrChatDrawer}
|
|
showModal={showChatModal}
|
|
></RunSheet>
|
|
)}
|
|
{logSheetVisible && (
|
|
<LogSheet
|
|
hideModal={hideLogSheet}
|
|
currentEventListWithoutMessageById={
|
|
currentEventListWithoutMessageById
|
|
}
|
|
currentMessageId={currentMessageId}
|
|
sendLoading={lastSendLoading}
|
|
></LogSheet>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default AgentCanvas;
|