From 2616f651c96e46cfed843fffa92b6a2cc6bdbcd9 Mon Sep 17 00:00:00 2001 From: balibabu Date: Mon, 8 Sep 2025 18:59:51 +0800 Subject: [PATCH] Feat: The agent's external page should be able to fill in the begin parameter after being reset in task mode #9745 (#9982) ### What problem does this PR solve? Feat: The agent's external page should be able to fill in the begin parameter after being reset in task mode #9745 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/locales/en.ts | 2 +- web/src/locales/zh.ts | 2 +- .../agent/hooks/use-send-shared-message.ts | 27 +- web/src/pages/agent/share/index.tsx | 30 +- web/src/pages/data-flow/canvas/index.tsx | 12 +- .../data-flow/canvas/node/chunker-node.tsx | 49 ++ .../data-flow/canvas/node/parser-node.tsx | 49 ++ .../data-flow/canvas/node/tokenizer-node.tsx | 49 ++ web/src/pages/data-flow/constant.tsx | 461 +----------------- web/src/pages/data-flow/hooks.tsx | 278 +---------- web/src/pages/data-flow/hooks/use-add-node.ts | 44 +- .../hooks/use-agent-tool-initial-values.ts | 70 --- web/src/pages/data-flow/index.tsx | 6 +- web/src/pages/data-flow/operator-icon.tsx | 35 +- 14 files changed, 234 insertions(+), 880 deletions(-) create mode 100644 web/src/pages/data-flow/canvas/node/chunker-node.tsx create mode 100644 web/src/pages/data-flow/canvas/node/parser-node.tsx create mode 100644 web/src/pages/data-flow/canvas/node/tokenizer-node.tsx delete mode 100644 web/src/pages/data-flow/hooks/use-agent-tool-initial-values.ts diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index fa62ce3c0..438698122 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1523,7 +1523,7 @@ This delimiter is used to split the input text into several text pieces echo of sqlStatement: 'SQL Statement', sqlStatementTip: 'Write your SQL query here. You can use variables, raw SQL, or mix both using variable syntax.', - frameworkPrompts: 'Framework Prompts', + frameworkPrompts: 'Framework', }, llmTools: { bad_calculator: { diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index b63805c7c..17fbedacf 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1436,7 +1436,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 sqlStatement: 'SQL 语句', sqlStatementTip: '在此处编写您的 SQL 查询。您可以使用变量、原始 SQL,或使用变量语法混合使用两者。', - frameworkPrompts: '框架提示词', + frameworkPrompts: '框架', }, footer: { profile: 'All rights reserved @ React', diff --git a/web/src/pages/agent/hooks/use-send-shared-message.ts b/web/src/pages/agent/hooks/use-send-shared-message.ts index 61570edc0..e379215fc 100644 --- a/web/src/pages/agent/hooks/use-send-shared-message.ts +++ b/web/src/pages/agent/hooks/use-send-shared-message.ts @@ -1,13 +1,16 @@ import { SharedFrom } from '@/constants/chat'; import { useSetModalState } from '@/hooks/common-hooks'; +import { useFetchExternalAgentInputs } from '@/hooks/use-agent-request'; import { IEventList } from '@/hooks/use-send-message'; import { buildRequestBody, useSendAgentMessage, } from '@/pages/agent/chat/use-send-agent-message'; +import { isEmpty } from 'lodash'; import trim from 'lodash/trim'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useSearchParams } from 'umi'; +import { AgentDialogueMode } from '../constant'; export const useSendButtonDisabled = (value: string) => { return trim(value) === ''; @@ -35,12 +38,15 @@ export const useGetSharedChatSearchParams = () => { export const useSendNextSharedMessage = ( addEventList: (data: IEventList, messageId: string) => void, - isTaskMode: boolean, ) => { const { from, sharedId: conversationId } = useGetSharedChatSearchParams(); const url = `/api/v1/${from === SharedFrom.Agent ? 'agentbots' : 'chatbots'}/${conversationId}/completions`; + const { data: inputsData } = useFetchExternalAgentInputs(); const [params, setParams] = useState([]); + const sendedTaskMessage = useRef(false); + + const isTaskMode = inputsData.mode === AgentDialogueMode.Task; const { visible: parameterDialogVisible, @@ -73,10 +79,27 @@ export const useSendNextSharedMessage = ( [hideParameterDialog, isTaskMode, ret], ); + const runTask = useCallback(() => { + if ( + isTaskMode && + isEmpty(inputsData?.inputs) && + !sendedTaskMessage.current + ) { + ok([]); + sendedTaskMessage.current = true; + } + }, [inputsData?.inputs, isTaskMode, ok]); + + useEffect(() => { + runTask(); + }, [runTask]); + return { ...ret, hasError: false, parameterDialogVisible, + inputsData, + isTaskMode, hideParameterDialog, showParameterDialog, ok, diff --git a/web/src/pages/agent/share/index.tsx b/web/src/pages/agent/share/index.tsx index 26cdb0248..9246d9bcf 100644 --- a/web/src/pages/agent/share/index.tsx +++ b/web/src/pages/agent/share/index.tsx @@ -5,10 +5,7 @@ import MessageItem from '@/components/next-message-item'; import PdfDrawer from '@/components/pdf-drawer'; import { useClickDrawer } from '@/components/pdf-drawer/hooks'; import { MessageType } from '@/constants/chat'; -import { - useFetchExternalAgentInputs, - useUploadCanvasFileWithProgress, -} from '@/hooks/use-agent-request'; +import { useUploadCanvasFileWithProgress } from '@/hooks/use-agent-request'; import { cn } from '@/lib/utils'; import i18n from '@/locales/config'; import DebugContent from '@/pages/agent/debug-content'; @@ -18,7 +15,6 @@ import { useSendButtonDisabled } from '@/pages/chat/hooks'; import { buildMessageUuidWithRole } from '@/utils/chat'; import { isEmpty } from 'lodash'; import React, { forwardRef, useCallback } from 'react'; -import { AgentDialogueMode } from '../constant'; import { useGetSharedChatSearchParams, useSendNextSharedMessage, @@ -43,9 +39,6 @@ const ChatContainer = () => { clearEventList, } = useCacheChatLog(); - const { data: inputsData } = useFetchExternalAgentInputs(); - const isTaskMode = inputsData.mode === AgentDialogueMode.Task; - const { handlePressEnter, handleInputChange, @@ -55,6 +48,8 @@ const ChatContainer = () => { messageContainerRef, derivedMessages, hasError, + inputsData, + isTaskMode, stopOutputMessage, findReferenceByMessageId, appendUploadResponseList, @@ -64,7 +59,8 @@ const ChatContainer = () => { addNewestOneAnswer, ok, resetSession, - } = useSendNextSharedMessage(addEventList, isTaskMode); + } = useSendNextSharedMessage(addEventList); + const { buildInputList, handleOk, isWaitting } = useAwaitCompentData({ derivedMessages, sendFormMessage, @@ -72,6 +68,12 @@ const ChatContainer = () => { }); const sendDisabled = useSendButtonDisabled(value); + const showBeginParameterDialog = useCallback(() => { + if (inputsData && inputsData.inputs && !isEmpty(inputsData.inputs)) { + showParameterDialog(); + } + }, [inputsData, showParameterDialog]); + const handleUploadFile: NonNullable = useCallback( async (files, options) => { @@ -96,10 +98,8 @@ const ChatContainer = () => { }, [inputsData.prologue, addNewestOneAnswer, isTaskMode]); React.useEffect(() => { - if (inputsData && inputsData.inputs && !isEmpty(inputsData.inputs)) { - showParameterDialog(); - } - }, [inputsData, showParameterDialog]); + showBeginParameterDialog(); + }, [showBeginParameterDialog]); const handleInputsModalOk = (params: any[]) => { ok(params); @@ -107,10 +107,14 @@ const ChatContainer = () => { const handleReset = () => { resetSession(); clearEventList(); + if (isTaskMode) { + showBeginParameterDialog(); + } }; if (!conversationId) { return
empty
; } + return ( <> ) { + return ( + + + + + + + + ); +} + +export default memo(ChunkerNode); diff --git a/web/src/pages/data-flow/canvas/node/parser-node.tsx b/web/src/pages/data-flow/canvas/node/parser-node.tsx new file mode 100644 index 000000000..4dceabce9 --- /dev/null +++ b/web/src/pages/data-flow/canvas/node/parser-node.tsx @@ -0,0 +1,49 @@ +import { IRagNode } from '@/interfaces/database/flow'; +import { NodeProps, Position } from '@xyflow/react'; +import { memo } from 'react'; +import { NodeHandleId } from '../../constant'; +import { needsSingleStepDebugging } from '../../utils'; +import { CommonHandle } from './handle'; +import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; +import NodeHeader from './node-header'; +import { NodeWrapper } from './node-wrapper'; +import { ToolBar } from './toolbar'; + +function ParserNode({ + id, + data, + isConnectable = true, + selected, +}: NodeProps) { + return ( + + + + + + + + ); +} + +export default memo(ParserNode); diff --git a/web/src/pages/data-flow/canvas/node/tokenizer-node.tsx b/web/src/pages/data-flow/canvas/node/tokenizer-node.tsx new file mode 100644 index 000000000..141399b14 --- /dev/null +++ b/web/src/pages/data-flow/canvas/node/tokenizer-node.tsx @@ -0,0 +1,49 @@ +import { IRagNode } from '@/interfaces/database/flow'; +import { NodeProps, Position } from '@xyflow/react'; +import { memo } from 'react'; +import { NodeHandleId } from '../../constant'; +import { needsSingleStepDebugging } from '../../utils'; +import { CommonHandle } from './handle'; +import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; +import NodeHeader from './node-header'; +import { NodeWrapper } from './node-wrapper'; +import { ToolBar } from './toolbar'; + +function TokenizerNode({ + id, + data, + isConnectable = true, + selected, +}: NodeProps) { + return ( + + + + + + + + ); +} + +export default memo(TokenizerNode); diff --git a/web/src/pages/data-flow/constant.tsx b/web/src/pages/data-flow/constant.tsx index bef95fb8d..ea158722f 100644 --- a/web/src/pages/data-flow/constant.tsx +++ b/web/src/pages/data-flow/constant.tsx @@ -8,11 +8,6 @@ import { ProgrammingLanguage, } from '@/constants/agent'; -export enum AgentDialogueMode { - Conversational = 'conversational', - Task = 'task', -} - import { ChatVariableEnabledField, variableEnabledFieldMap, @@ -22,17 +17,6 @@ import i18n from '@/locales/config'; import { setInitialChatVariableEnabledFieldValue } from '@/utils/chat'; import { t } from 'i18next'; -// DuckDuckGo's channel options -export enum Channel { - Text = 'text', - News = 'news', -} - -export enum PromptRole { - User = 'user', - Assistant = 'assistant', -} - import { Circle, CircleSlash2, @@ -44,6 +28,16 @@ import { WrapText, } from 'lucide-react'; +export enum PromptRole { + User = 'user', + Assistant = 'assistant', +} + +export enum AgentDialogueMode { + Conversational = 'conversational', + Task = 'task', +} + export const BeginId = 'begin'; export enum Operator { @@ -54,26 +48,9 @@ export enum Operator { Relevant = 'Relevant', RewriteQuestion = 'RewriteQuestion', KeywordExtract = 'KeywordExtract', - Baidu = 'Baidu', - DuckDuckGo = 'DuckDuckGo', - Wikipedia = 'Wikipedia', - PubMed = 'PubMed', - ArXiv = 'ArXiv', - Google = 'Google', - Bing = 'Bing', - GoogleScholar = 'GoogleScholar', - DeepL = 'DeepL', - GitHub = 'GitHub', - BaiduFanyi = 'BaiduFanyi', - QWeather = 'QWeather', ExeSQL = 'ExeSQL', Switch = 'Switch', - WenCai = 'WenCai', - AkShare = 'AkShare', - YahooFinance = 'YahooFinance', - Jin10 = 'Jin10', Concentrator = 'Concentrator', - TuShare = 'TuShare', Note = 'Note', Crawler = 'Crawler', Invoke = 'Invoke', @@ -84,11 +61,8 @@ export enum Operator { WaitingDialogue = 'WaitingDialogue', Agent = 'Agent', Tool = 'Tool', - TavilySearch = 'TavilySearch', - TavilyExtract = 'TavilyExtract', UserFillUp = 'UserFillUp', StringTransform = 'StringTransform', - SearXNG = 'SearXNG', Parser = 'Parser', Chunker = 'Chunker', Tokenizer = 'Tokenizer', @@ -114,112 +88,6 @@ export const AgentOperatorList = [ Operator.Agent, ]; -export const componentMenuList = [ - { - name: Operator.Retrieval, - }, - { - name: Operator.Categorize, - }, - { - name: Operator.Message, - }, - - { - name: Operator.RewriteQuestion, - }, - { - name: Operator.KeywordExtract, - }, - { - name: Operator.Switch, - }, - { - name: Operator.Concentrator, - }, - { - name: Operator.Iteration, - }, - { - name: Operator.Code, - }, - { - name: Operator.WaitingDialogue, - }, - { - name: Operator.Agent, - }, - { - name: Operator.Note, - }, - { - name: Operator.DuckDuckGo, - }, - { - name: Operator.Baidu, - }, - { - name: Operator.Wikipedia, - }, - { - name: Operator.PubMed, - }, - { - name: Operator.ArXiv, - }, - { - name: Operator.Google, - }, - { - name: Operator.Bing, - }, - { - name: Operator.GoogleScholar, - }, - { - name: Operator.DeepL, - }, - { - name: Operator.GitHub, - }, - { - name: Operator.BaiduFanyi, - }, - { - name: Operator.QWeather, - }, - { - name: Operator.ExeSQL, - }, - { - name: Operator.WenCai, - }, - { - name: Operator.AkShare, - }, - { - name: Operator.YahooFinance, - }, - { - name: Operator.Jin10, - }, - { - name: Operator.TuShare, - }, - { - name: Operator.Crawler, - }, - { - name: Operator.Invoke, - }, - { - name: Operator.Email, - }, - { - name: Operator.SearXNG, - }, -]; - export const SwitchOperatorOptions = [ { value: '=', label: 'equal', icon: 'equal' }, { value: '≠', label: 'notEqual', icon: 'not-equals' }, @@ -331,161 +199,6 @@ export const initialKeywordExtractValues = { top_n: 3, ...initialQueryBaseValues, }; -export const initialDuckValues = { - top_n: 10, - channel: Channel.Text, - query: AgentGlobals.SysQuery, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - json: { - value: [], - type: 'Array', - }, - }, -}; - -export const initialSearXNGValues = { - top_n: '10', - searxng_url: '', - query: AgentGlobals.SysQuery, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - json: { - value: [], - type: 'Array', - }, - }, -}; - -export const initialBaiduValues = { - top_n: 10, - ...initialQueryBaseValues, -}; - -export const initialWikipediaValues = { - top_n: 10, - language: 'en', - query: AgentGlobals.SysQuery, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - }, -}; - -export const initialPubMedValues = { - top_n: 12, - email: '', - query: AgentGlobals.SysQuery, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - }, -}; - -export const initialArXivValues = { - top_n: 12, - sort_by: 'relevance', - query: AgentGlobals.SysQuery, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - }, -}; - -export const initialGoogleValues = { - q: AgentGlobals.SysQuery, - start: 0, - num: 12, - api_key: '', - country: 'us', - language: 'en', - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - json: { - value: [], - type: 'Array', - }, - }, -}; - -export const initialBingValues = { - top_n: 10, - channel: 'Webpages', - api_key: - 'YOUR_API_KEY (obtained from https://www.microsoft.com/en-us/bing/apis/bing-web-search-api)', - country: 'CH', - language: 'en', - query: '', -}; - -export const initialGoogleScholarValues = { - top_n: 12, - sort_by: 'relevance', - patents: true, - query: AgentGlobals.SysQuery, - year_low: undefined, - year_high: undefined, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - json: { - value: [], - type: 'Array', - }, - }, -}; - -export const initialDeepLValues = { - top_n: 5, - auth_key: 'relevance', -}; - -export const initialGithubValues = { - top_n: 5, - query: AgentGlobals.SysQuery, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - json: { - value: [], - type: 'Array', - }, - }, -}; - -export const initialBaiduFanyiValues = { - appid: 'xxx', - secret_key: 'xxx', - trans_type: 'translate', - ...initialQueryBaseValues, -}; - -export const initialQWeatherValues = { - web_apikey: 'xxx', - type: 'weather', - user_type: 'free', - time_period: 'now', - ...initialQueryBaseValues, -}; export const initialExeSqlValues = { sql: '', @@ -523,54 +236,8 @@ export const initialSwitchValues = { [SwitchElseTo]: [], }; -export const initialWenCaiValues = { - top_n: 20, - query_type: 'stock', - query: AgentGlobals.SysQuery, - outputs: { - report: { - value: '', - type: 'string', - }, - }, -}; - -export const initialAkShareValues = { top_n: 10, ...initialQueryBaseValues }; - -export const initialYahooFinanceValues = { - stock_code: '', - info: true, - history: false, - financials: false, - balance_sheet: false, - cash_flow_statement: false, - news: true, - outputs: { - report: { - value: '', - type: 'string', - }, - }, -}; - -export const initialJin10Values = { - type: 'flash', - secret_key: 'xxx', - flash_type: '1', - contain: '', - filter: '', - ...initialQueryBaseValues, -}; - export const initialConcentratorValues = {}; -export const initialTuShareValues = { - token: 'xxx', - src: 'eastmoney', - start_date: '2024-01-01 09:00:00', - ...initialQueryBaseValues, -}; - export const initialNoteValues = { text: '', }; @@ -650,6 +317,10 @@ export const initialCodeValues = { export const initialWaitingDialogueValues = {}; +export const initialChunkerValues = {}; + +export const initialTokenizerValues = {}; + export const initialAgentValues = { ...initialLlmBaseValues, description: '', @@ -717,66 +388,7 @@ export const initialStringTransformValues = { }, }; -export enum TavilySearchDepth { - Basic = 'basic', - Advanced = 'advanced', -} - -export enum TavilyTopic { - News = 'news', - General = 'general', -} - -export const initialTavilyValues = { - api_key: '', - query: AgentGlobals.SysQuery, - search_depth: TavilySearchDepth.Basic, - topic: TavilyTopic.General, - max_results: 5, - days: 7, - include_answer: false, - include_raw_content: true, - include_images: false, - include_image_descriptions: false, - include_domains: [], - exclude_domains: [], - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - json: { - value: [], - type: 'Array', - }, - }, -}; - -export enum TavilyExtractDepth { - Basic = 'basic', - Advanced = 'advanced', -} - -export enum TavilyExtractFormat { - Text = 'text', - Markdown = 'markdown', -} - -export const initialTavilyExtractValues = { - urls: '', - extract_depth: TavilyExtractDepth.Basic, - format: TavilyExtractFormat.Markdown, - outputs: { - formalized_content: { - value: '', - type: 'string', - }, - json: { - value: [], - type: 'Array', - }, - }, -}; +export const initialParserValues = {}; export const CategorizeAnchorPointPositions = [ { top: 1, right: 34 }, @@ -818,27 +430,9 @@ export const RestrictedUpstreamMap = { Operator.Message, Operator.Relevant, ], - [Operator.Baidu]: [Operator.Begin, Operator.Retrieval], - [Operator.DuckDuckGo]: [Operator.Begin, Operator.Retrieval], - [Operator.Wikipedia]: [Operator.Begin, Operator.Retrieval], - [Operator.PubMed]: [Operator.Begin, Operator.Retrieval], - [Operator.ArXiv]: [Operator.Begin, Operator.Retrieval], - [Operator.Google]: [Operator.Begin, Operator.Retrieval], - [Operator.Bing]: [Operator.Begin, Operator.Retrieval], - [Operator.GoogleScholar]: [Operator.Begin, Operator.Retrieval], - [Operator.DeepL]: [Operator.Begin, Operator.Retrieval], - [Operator.GitHub]: [Operator.Begin, Operator.Retrieval], - [Operator.BaiduFanyi]: [Operator.Begin, Operator.Retrieval], - [Operator.QWeather]: [Operator.Begin, Operator.Retrieval], - [Operator.SearXNG]: [Operator.Begin, Operator.Retrieval], [Operator.ExeSQL]: [Operator.Begin], [Operator.Switch]: [Operator.Begin], - [Operator.WenCai]: [Operator.Begin], - [Operator.AkShare]: [Operator.Begin], - [Operator.YahooFinance]: [Operator.Begin], - [Operator.Jin10]: [Operator.Begin], [Operator.Concentrator]: [Operator.Begin], - [Operator.TuShare]: [Operator.Begin], [Operator.Crawler]: [Operator.Begin], [Operator.Note]: [], [Operator.Invoke]: [Operator.Begin], @@ -848,8 +442,6 @@ export const RestrictedUpstreamMap = { [Operator.Code]: [Operator.Begin], [Operator.WaitingDialogue]: [Operator.Begin], [Operator.Agent]: [Operator.Begin], - [Operator.TavilySearch]: [Operator.Begin], - [Operator.TavilyExtract]: [Operator.Begin], [Operator.StringTransform]: [Operator.Begin], [Operator.UserFillUp]: [Operator.Begin], [Operator.Tool]: [Operator.Begin], @@ -863,27 +455,9 @@ export const NodeMap = { [Operator.Relevant]: 'relevantNode', [Operator.RewriteQuestion]: 'rewriteNode', [Operator.KeywordExtract]: 'keywordNode', - [Operator.DuckDuckGo]: 'ragNode', - [Operator.Baidu]: 'ragNode', - [Operator.Wikipedia]: 'ragNode', - [Operator.PubMed]: 'ragNode', - [Operator.ArXiv]: 'ragNode', - [Operator.Google]: 'ragNode', - [Operator.Bing]: 'ragNode', - [Operator.GoogleScholar]: 'ragNode', - [Operator.DeepL]: 'ragNode', - [Operator.GitHub]: 'ragNode', - [Operator.BaiduFanyi]: 'ragNode', - [Operator.QWeather]: 'ragNode', - [Operator.SearXNG]: 'ragNode', [Operator.ExeSQL]: 'ragNode', [Operator.Switch]: 'switchNode', [Operator.Concentrator]: 'logicNode', - [Operator.WenCai]: 'ragNode', - [Operator.AkShare]: 'ragNode', - [Operator.YahooFinance]: 'ragNode', - [Operator.Jin10]: 'ragNode', - [Operator.TuShare]: 'ragNode', [Operator.Note]: 'noteNode', [Operator.Crawler]: 'ragNode', [Operator.Invoke]: 'ragNode', @@ -894,10 +468,11 @@ export const NodeMap = { [Operator.WaitingDialogue]: 'ragNode', [Operator.Agent]: 'agentNode', [Operator.Tool]: 'toolNode', - [Operator.TavilySearch]: 'ragNode', [Operator.UserFillUp]: 'ragNode', [Operator.StringTransform]: 'ragNode', - [Operator.TavilyExtract]: 'ragNode', + [Operator.Parser]: 'parserNode', + [Operator.Chunker]: 'chunkerNode', + [Operator.Tokenizer]: 'tokenizerNode', }; export enum BeginQueryType { diff --git a/web/src/pages/data-flow/hooks.tsx b/web/src/pages/data-flow/hooks.tsx index 779ba0928..42687313f 100644 --- a/web/src/pages/data-flow/hooks.tsx +++ b/web/src/pages/data-flow/hooks.tsx @@ -1,69 +1,12 @@ -import { - Connection, - Edge, - getOutgoers, - Node, - Position, - ReactFlowInstance, -} from '@xyflow/react'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { Connection, Edge, getOutgoers } from '@xyflow/react'; +import { useCallback } from 'react'; // import { shallow } from 'zustand/shallow'; -import { useFetchModelId } from '@/hooks/logic-hooks'; import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { humanId } from 'human-id'; -import { get, lowerFirst } from 'lodash'; +import { lowerFirst } from 'lodash'; import { useTranslation } from 'react-i18next'; -import { - initialAgentValues, - initialAkShareValues, - initialArXivValues, - initialBaiduFanyiValues, - initialBeginValues, - initialBingValues, - initialCategorizeValues, - initialCodeValues, - initialConcentratorValues, - initialCrawlerValues, - initialDeepLValues, - initialDuckValues, - initialEmailValues, - initialExeSqlValues, - initialGithubValues, - initialGoogleScholarValues, - initialGoogleValues, - initialInvokeValues, - initialIterationValues, - initialJin10Values, - initialKeywordExtractValues, - initialMessageValues, - initialNoteValues, - initialPubMedValues, - initialQWeatherValues, - initialRelevantValues, - initialRetrievalValues, - initialRewriteQuestionValues, - initialSearXNGValues, - initialStringTransformValues, - initialSwitchValues, - initialTavilyExtractValues, - initialTavilyValues, - initialTuShareValues, - initialUserFillUpValues, - initialWaitingDialogueValues, - initialWenCaiValues, - initialWikipediaValues, - initialYahooFinanceValues, - NodeMap, - Operator, - RestrictedUpstreamMap, -} from './constant'; +import { Operator, RestrictedUpstreamMap } from './constant'; import useGraphStore, { RFState } from './store'; -import { - generateNodeNamesWithIncreasingIndex, - getNodeDragHandle, - getRelativePositionToIterationNode, - replaceIdWithText, -} from './utils'; +import { replaceIdWithText } from './utils'; const selector = (state: RFState) => ({ nodes: state.nodes, @@ -83,83 +26,6 @@ export const useSelectCanvasData = () => { return useGraphStore(selector); }; -export const useInitializeOperatorParams = () => { - const llmId = useFetchModelId(); - - const initialFormValuesMap = useMemo(() => { - return { - [Operator.Begin]: initialBeginValues, - [Operator.Retrieval]: initialRetrievalValues, - [Operator.Categorize]: { ...initialCategorizeValues, llm_id: llmId }, - [Operator.Relevant]: { ...initialRelevantValues, llm_id: llmId }, - [Operator.RewriteQuestion]: { - ...initialRewriteQuestionValues, - llm_id: llmId, - }, - [Operator.Message]: initialMessageValues, - [Operator.KeywordExtract]: { - ...initialKeywordExtractValues, - llm_id: llmId, - }, - [Operator.DuckDuckGo]: initialDuckValues, - [Operator.Wikipedia]: initialWikipediaValues, - [Operator.PubMed]: initialPubMedValues, - [Operator.ArXiv]: initialArXivValues, - [Operator.Google]: initialGoogleValues, - [Operator.Bing]: initialBingValues, - [Operator.GoogleScholar]: initialGoogleScholarValues, - [Operator.DeepL]: initialDeepLValues, - [Operator.SearXNG]: initialSearXNGValues, - [Operator.GitHub]: initialGithubValues, - [Operator.BaiduFanyi]: initialBaiduFanyiValues, - [Operator.QWeather]: initialQWeatherValues, - [Operator.ExeSQL]: { ...initialExeSqlValues, llm_id: llmId }, - [Operator.Switch]: initialSwitchValues, - [Operator.WenCai]: initialWenCaiValues, - [Operator.AkShare]: initialAkShareValues, - [Operator.YahooFinance]: initialYahooFinanceValues, - [Operator.Jin10]: initialJin10Values, - [Operator.Concentrator]: initialConcentratorValues, - [Operator.TuShare]: initialTuShareValues, - [Operator.Note]: initialNoteValues, - [Operator.Crawler]: initialCrawlerValues, - [Operator.Invoke]: initialInvokeValues, - [Operator.Email]: initialEmailValues, - [Operator.Iteration]: initialIterationValues, - [Operator.IterationStart]: initialIterationValues, - [Operator.Code]: initialCodeValues, - [Operator.WaitingDialogue]: initialWaitingDialogueValues, - [Operator.Agent]: { ...initialAgentValues, llm_id: llmId }, - [Operator.TavilySearch]: initialTavilyValues, - [Operator.TavilyExtract]: initialTavilyExtractValues, - [Operator.Tool]: {}, - [Operator.UserFillUp]: initialUserFillUpValues, - [Operator.StringTransform]: initialStringTransformValues, - }; - }, [llmId]); - - const initializeOperatorParams = useCallback( - (operatorName: Operator) => { - return initialFormValuesMap[operatorName]; - }, - [initialFormValuesMap], - ); - - return initializeOperatorParams; -}; - -export const useHandleDrag = () => { - const handleDragStart = useCallback( - (operatorId: string) => (ev: React.DragEvent) => { - ev.dataTransfer.setData('application/@xyflow/react', operatorId); - ev.dataTransfer.effectAllowed = 'move'; - }, - [], - ); - - return { handleDragStart }; -}; - export const useGetNodeName = () => { const { t } = useTranslation(); @@ -169,91 +35,6 @@ export const useGetNodeName = () => { }; }; -export const useHandleDrop = () => { - const addNode = useGraphStore((state) => state.addNode); - const nodes = useGraphStore((state) => state.nodes); - const [reactFlowInstance, setReactFlowInstance] = - useState>(); - const initializeOperatorParams = useInitializeOperatorParams(); - const getNodeName = useGetNodeName(); - - const onDragOver = useCallback((event: React.DragEvent) => { - event.preventDefault(); - event.dataTransfer.dropEffect = 'move'; - }, []); - - const onDrop = useCallback( - (event: React.DragEvent) => { - event.preventDefault(); - - const type = event.dataTransfer.getData('application/@xyflow/react'); - - // check if the dropped element is valid - if (typeof type === 'undefined' || !type) { - return; - } - - // reactFlowInstance.project was renamed to reactFlowInstance.screenToFlowPosition - // and you don't need to subtract the reactFlowBounds.left/top anymore - // details: https://@xyflow/react.dev/whats-new/2023-11-10 - const position = reactFlowInstance?.screenToFlowPosition({ - x: event.clientX, - y: event.clientY, - }); - const newNode: Node = { - id: `${type}:${humanId()}`, - type: NodeMap[type as Operator] || 'ragNode', - position: position || { - x: 0, - y: 0, - }, - data: { - label: `${type}`, - name: generateNodeNamesWithIncreasingIndex(getNodeName(type), nodes), - form: initializeOperatorParams(type as Operator), - }, - sourcePosition: Position.Right, - targetPosition: Position.Left, - dragHandle: getNodeDragHandle(type), - }; - - if (type === Operator.Iteration) { - newNode.width = 500; - newNode.height = 250; - const iterationStartNode: Node = { - id: `${Operator.IterationStart}:${humanId()}`, - type: 'iterationStartNode', - position: { x: 50, y: 100 }, - // draggable: false, - data: { - label: Operator.IterationStart, - name: Operator.IterationStart, - form: {}, - }, - parentId: newNode.id, - extent: 'parent', - }; - addNode(newNode); - addNode(iterationStartNode); - } else { - const subNodeOfIteration = getRelativePositionToIterationNode( - nodes, - position, - ); - if (subNodeOfIteration) { - newNode.parentId = subNodeOfIteration.parentId; - newNode.position = subNodeOfIteration.position; - newNode.extent = 'parent'; - } - addNode(newNode); - } - }, - [reactFlowInstance, getNodeName, nodes, initializeOperatorParams, addNode], - ); - - return { onDrop, onDragOver, setReactFlowInstance, reactFlowInstance }; -}; - export const useValidateConnection = () => { const { getOperatorTypeFromId, getParentIdById, edges, nodes } = useGraphStore((state) => state); @@ -352,52 +133,3 @@ export const useDuplicateNode = () => { return duplicateNode; }; - -export const useCopyPaste = () => { - const nodes = useGraphStore((state) => state.nodes); - const duplicateNode = useDuplicateNode(); - - const onCopyCapture = useCallback( - (event: ClipboardEvent) => { - if (get(event, 'srcElement.tagName') !== 'BODY') return; - - event.preventDefault(); - const nodesStr = JSON.stringify( - nodes.filter((n) => n.selected && n.data.label !== Operator.Begin), - ); - - event.clipboardData?.setData('agent:nodes', nodesStr); - }, - [nodes], - ); - - const onPasteCapture = useCallback( - (event: ClipboardEvent) => { - const nodes = JSON.parse( - event.clipboardData?.getData('agent:nodes') || '[]', - ) as RAGFlowNodeType[] | undefined; - - if (Array.isArray(nodes) && nodes.length) { - event.preventDefault(); - nodes.forEach((n) => { - duplicateNode(n.id, n.data.label); - }); - } - }, - [duplicateNode], - ); - - useEffect(() => { - window.addEventListener('copy', onCopyCapture); - return () => { - window.removeEventListener('copy', onCopyCapture); - }; - }, [onCopyCapture]); - - useEffect(() => { - window.addEventListener('paste', onPasteCapture); - return () => { - window.removeEventListener('paste', onPasteCapture); - }; - }, [onPasteCapture]); -}; diff --git a/web/src/pages/data-flow/hooks/use-add-node.ts b/web/src/pages/data-flow/hooks/use-add-node.ts index e3dad598e..8f1ebf77f 100644 --- a/web/src/pages/data-flow/hooks/use-add-node.ts +++ b/web/src/pages/data-flow/hooks/use-add-node.ts @@ -10,45 +10,29 @@ import { NodeMap, Operator, initialAgentValues, - initialAkShareValues, - initialArXivValues, - initialBaiduFanyiValues, initialBeginValues, - initialBingValues, initialCategorizeValues, + initialChunkerValues, initialCodeValues, initialConcentratorValues, initialCrawlerValues, - initialDeepLValues, - initialDuckValues, initialEmailValues, initialExeSqlValues, - initialGithubValues, - initialGoogleScholarValues, - initialGoogleValues, initialInvokeValues, initialIterationStartValues, initialIterationValues, - initialJin10Values, initialKeywordExtractValues, initialMessageValues, initialNoteValues, - initialPubMedValues, - initialQWeatherValues, + initialParserValues, initialRelevantValues, initialRetrievalValues, initialRewriteQuestionValues, - initialSearXNGValues, initialStringTransformValues, initialSwitchValues, - initialTavilyExtractValues, - initialTavilyValues, - initialTuShareValues, + initialTokenizerValues, initialUserFillUpValues, initialWaitingDialogueValues, - initialWenCaiValues, - initialWikipediaValues, - initialYahooFinanceValues, } from '../constant'; import useGraphStore from '../store'; import { @@ -80,26 +64,9 @@ export const useInitializeOperatorParams = () => { ...initialKeywordExtractValues, llm_id: llmId, }, - [Operator.DuckDuckGo]: initialDuckValues, - [Operator.Wikipedia]: initialWikipediaValues, - [Operator.PubMed]: initialPubMedValues, - [Operator.ArXiv]: initialArXivValues, - [Operator.Google]: initialGoogleValues, - [Operator.Bing]: initialBingValues, - [Operator.GoogleScholar]: initialGoogleScholarValues, - [Operator.DeepL]: initialDeepLValues, - [Operator.SearXNG]: initialSearXNGValues, - [Operator.GitHub]: initialGithubValues, - [Operator.BaiduFanyi]: initialBaiduFanyiValues, - [Operator.QWeather]: initialQWeatherValues, [Operator.ExeSQL]: initialExeSqlValues, [Operator.Switch]: initialSwitchValues, - [Operator.WenCai]: initialWenCaiValues, - [Operator.AkShare]: initialAkShareValues, - [Operator.YahooFinance]: initialYahooFinanceValues, - [Operator.Jin10]: initialJin10Values, [Operator.Concentrator]: initialConcentratorValues, - [Operator.TuShare]: initialTuShareValues, [Operator.Note]: initialNoteValues, [Operator.Crawler]: initialCrawlerValues, [Operator.Invoke]: initialInvokeValues, @@ -110,10 +77,11 @@ export const useInitializeOperatorParams = () => { [Operator.WaitingDialogue]: initialWaitingDialogueValues, [Operator.Agent]: { ...initialAgentValues, llm_id: llmId }, [Operator.Tool]: {}, - [Operator.TavilySearch]: initialTavilyValues, [Operator.UserFillUp]: initialUserFillUpValues, [Operator.StringTransform]: initialStringTransformValues, - [Operator.TavilyExtract]: initialTavilyExtractValues, + [Operator.Parser]: initialParserValues, + [Operator.Chunker]: initialChunkerValues, + [Operator.Tokenizer]: initialTokenizerValues, }; }, [llmId]); diff --git a/web/src/pages/data-flow/hooks/use-agent-tool-initial-values.ts b/web/src/pages/data-flow/hooks/use-agent-tool-initial-values.ts deleted file mode 100644 index 05864184d..000000000 --- a/web/src/pages/data-flow/hooks/use-agent-tool-initial-values.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { omit, pick } from 'lodash'; -import { useCallback } from 'react'; -import { Operator } from '../constant'; -import { useInitializeOperatorParams } from './use-add-node'; - -export function useAgentToolInitialValues() { - const { initialFormValuesMap } = useInitializeOperatorParams(); - - const initializeAgentToolValues = useCallback( - (operatorName: Operator) => { - const initialValues = initialFormValuesMap[operatorName]; - - switch (operatorName) { - case Operator.Retrieval: - return { - ...omit(initialValues, 'query'), - description: '', - }; - case (Operator.TavilySearch, Operator.TavilyExtract): - return { - api_key: '', - }; - case Operator.ExeSQL: - return omit(initialValues, 'sql'); - case Operator.Bing: - return omit(initialValues, 'query'); - case Operator.YahooFinance: - return omit(initialValues, 'stock_code'); - - case Operator.Email: - return pick( - initialValues, - 'smtp_server', - 'smtp_port', - 'email', - 'password', - 'sender_name', - ); - - case Operator.DuckDuckGo: - return pick(initialValues, 'top_n', 'channel'); - - case Operator.Wikipedia: - return pick(initialValues, 'top_n', 'language'); - case Operator.Google: - return pick(initialValues, 'api_key', 'country', 'language'); - case Operator.GoogleScholar: - return omit(initialValues, 'query', 'outputs'); - case Operator.ArXiv: - return pick(initialValues, 'top_n', 'sort_by'); - case Operator.PubMed: - return pick(initialValues, 'top_n', 'email'); - case Operator.GitHub: - return pick(initialValues, 'top_n'); - case Operator.WenCai: - return pick(initialValues, 'top_n', 'query_type'); - case Operator.Code: - return {}; - case Operator.SearXNG: - return pick(initialValues, 'searxng_url', 'top_n'); - - default: - return initialValues; - } - }, - [initialFormValuesMap], - ); - - return { initializeAgentToolValues }; -} diff --git a/web/src/pages/data-flow/index.tsx b/web/src/pages/data-flow/index.tsx index 4a1fc81ae..10798b5e8 100644 --- a/web/src/pages/data-flow/index.tsx +++ b/web/src/pages/data-flow/index.tsx @@ -29,7 +29,7 @@ import { } from 'lucide-react'; import { ComponentPropsWithoutRef, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import AgentCanvas from './canvas'; +import DataFlowCanvas from './canvas'; import { DropdownProvider } from './canvas/context'; import { useHandleExportOrImportJsonFile } from './hooks/use-export-json'; import { useFetchDataOnMount } from './hooks/use-fetch-data'; @@ -161,10 +161,10 @@ export default function DataFlow() { - + > {fileUploadVisible && ( diff --git a/web/src/pages/data-flow/operator-icon.tsx b/web/src/pages/data-flow/operator-icon.tsx index b8ebc34ba..a11145ace 100644 --- a/web/src/pages/data-flow/operator-icon.tsx +++ b/web/src/pages/data-flow/operator-icon.tsx @@ -1,17 +1,3 @@ -import { ReactComponent as ArxivIcon } from '@/assets/svg/arxiv.svg'; -import { ReactComponent as BingIcon } from '@/assets/svg/bing.svg'; -import { ReactComponent as CrawlerIcon } from '@/assets/svg/crawler.svg'; -import { ReactComponent as DuckIcon } from '@/assets/svg/duck.svg'; -import { ReactComponent as GithubIcon } from '@/assets/svg/github.svg'; -import { ReactComponent as GoogleScholarIcon } from '@/assets/svg/google-scholar.svg'; -import { ReactComponent as GoogleIcon } from '@/assets/svg/google.svg'; -import { ReactComponent as PubMedIcon } from '@/assets/svg/pubmed.svg'; -import { ReactComponent as SearXNGIcon } from '@/assets/svg/searxng.svg'; -import { ReactComponent as TavilyIcon } from '@/assets/svg/tavily.svg'; -import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg'; -import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg'; -import { ReactComponent as YahooFinanceIcon } from '@/assets/svg/yahoo-finance.svg'; - import { IconFont } from '@/components/icon-font'; import { cn } from '@/lib/utils'; import { HousePlus } from 'lucide-react'; @@ -39,30 +25,13 @@ export const OperatorIconMap = { [Operator.Email]: 'sendemail-0', }; -export const SVGIconMap = { - [Operator.ArXiv]: ArxivIcon, - [Operator.GitHub]: GithubIcon, - [Operator.Bing]: BingIcon, - [Operator.DuckDuckGo]: DuckIcon, - [Operator.Google]: GoogleIcon, - [Operator.GoogleScholar]: GoogleScholarIcon, - [Operator.PubMed]: PubMedIcon, - [Operator.SearXNG]: SearXNGIcon, - [Operator.TavilyExtract]: TavilyIcon, - [Operator.TavilySearch]: TavilyIcon, - [Operator.Wikipedia]: WikipediaIcon, - [Operator.YahooFinance]: YahooFinanceIcon, - [Operator.WenCai]: WenCaiIcon, - [Operator.Crawler]: CrawlerIcon, -}; - const Empty = () => { return
; }; const OperatorIcon = ({ name, className }: IProps) => { const Icon = OperatorIconMap[name as keyof typeof OperatorIconMap] || Empty; - const SvgIcon = SVGIconMap[name as keyof typeof SVGIconMap] || Empty; + const SvgIcon = Empty; if (name === Operator.Begin) { return ( @@ -80,7 +49,7 @@ const OperatorIcon = ({ name, className }: IProps) => { return typeof Icon === 'string' ? ( ) : ( - + ); };