diff --git a/web/app/components/base/tag-input/index.tsx b/web/app/components/base/tag-input/index.tsx index 4824b6f62d..3daad54888 100644 --- a/web/app/components/base/tag-input/index.tsx +++ b/web/app/components/base/tag-input/index.tsx @@ -15,6 +15,7 @@ type TagInputProps = { customizedConfirmKey?: 'Enter' | 'Tab' isInWorkflow?: boolean placeholder?: string + inputClassName?: string } const TagInput: FC = ({ @@ -25,6 +26,7 @@ const TagInput: FC = ({ customizedConfirmKey = 'Enter', isInWorkflow, placeholder, + inputClassName, }) => { const { t } = useTranslation() const { notify } = useToastContext() @@ -93,15 +95,18 @@ const TagInput: FC = ({
{!isSpecialMode && !focused && } setFocused(true)} onBlur={handleBlur} value={value} diff --git a/web/app/components/rag-pipeline/hooks/use-pipeline-config.ts b/web/app/components/rag-pipeline/hooks/use-pipeline-config.ts index f40a002eff..fa5fdc5905 100644 --- a/web/app/components/rag-pipeline/hooks/use-pipeline-config.ts +++ b/web/app/components/rag-pipeline/hooks/use-pipeline-config.ts @@ -5,6 +5,9 @@ import { } from '@/app/components/workflow/store' import { useWorkflowConfig } from '@/service/use-workflow' import type { FetchWorkflowDraftResponse } from '@/types/workflow' +import { useDataSourceList } from '@/service/use-pipeline' +import type { ToolWithProvider } from '@/app/components/workflow/types' +import { basePath } from '@/utils/var' export const usePipelineConfig = () => { const pipelineId = useStore(s => s.pipelineId) @@ -39,4 +42,15 @@ export const usePipelineConfig = () => { pipelineId ? `/rag/pipelines/${pipelineId}/workflows/publish` : '', handleUpdatePublishedAt, ) + + const handleUpdateDataSourceList = useCallback((dataSourceList: ToolWithProvider[]) => { + dataSourceList.forEach((item) => { + if (typeof item.icon == 'string' && !item.icon.includes(basePath)) + item.icon = `${basePath}${item.icon}` + }) + const { setDataSourceList } = workflowStore.getState() + setDataSourceList!(dataSourceList) + }, [workflowStore]) + + useDataSourceList(!!pipelineId, handleUpdateDataSourceList) } diff --git a/web/app/components/rag-pipeline/store/index.ts b/web/app/components/rag-pipeline/store/index.ts index 857c60529f..e39fdaa0f3 100644 --- a/web/app/components/rag-pipeline/store/index.ts +++ b/web/app/components/rag-pipeline/store/index.ts @@ -1,5 +1,8 @@ import type { RAGPipelineVariables } from '@/models/pipeline' import type { StateCreator } from 'zustand' +import type { + ToolWithProvider, +} from '@/app/components/workflow/types' export type RagPipelineSliceShape = { pipelineId: string @@ -9,6 +12,8 @@ export type RagPipelineSliceShape = { setNodesDefaultConfigs: (nodesDefaultConfigs: Record) => void ragPipelineVariables: RAGPipelineVariables setRagPipelineVariables: (ragPipelineVariables: RAGPipelineVariables) => void + dataSourceList: ToolWithProvider[] + setDataSourceList: (dataSourceList: ToolWithProvider[]) => void } export type CreateRagPipelineSliceSlice = StateCreator @@ -20,4 +25,6 @@ export const createRagPipelineSliceSlice: StateCreator = setNodesDefaultConfigs: nodesDefaultConfigs => set(() => ({ nodesDefaultConfigs })), ragPipelineVariables: [], setRagPipelineVariables: (ragPipelineVariables: RAGPipelineVariables) => set(() => ({ ragPipelineVariables })), + dataSourceList: [], + setDataSourceList: (dataSourceList: ToolWithProvider[]) => set(() => ({ dataSourceList })), }) diff --git a/web/app/components/workflow/block-selector/hooks.ts b/web/app/components/workflow/block-selector/hooks.ts index 5bfd7fe62b..208a44dff6 100644 --- a/web/app/components/workflow/block-selector/hooks.ts +++ b/web/app/components/workflow/block-selector/hooks.ts @@ -3,8 +3,6 @@ import { useState, } from 'react' import { useTranslation } from 'react-i18next' -import { useDataSourceList } from '@/service/use-pipeline' -import { useStore } from '../store' import { TabsEnum, ToolTypeEnum, @@ -77,10 +75,3 @@ export const useToolTabs = () => { }, ] } - -export const useDataSources = () => { - const pipelineId = useStore(s => s.pipelineId) - const { data: dataSourceList } = useDataSourceList(!!pipelineId) - - return dataSourceList || [] -} diff --git a/web/app/components/workflow/block-selector/index.tsx b/web/app/components/workflow/block-selector/index.tsx index a9f3059770..7329b63b82 100644 --- a/web/app/components/workflow/block-selector/index.tsx +++ b/web/app/components/workflow/block-selector/index.tsx @@ -5,10 +5,11 @@ import type { NodeSelectorProps } from './main' import NodeSelector from './main' import { useHooksStore } from '@/app/components/workflow/hooks-store/store' import { BlockEnum } from '@/app/components/workflow/types' -import { useDataSources } from './hooks' +import { useStore } from '../store' const NodeSelectorWrapper = (props: NodeSelectorProps) => { const availableNodesMetaData = useHooksStore(s => s.availableNodesMetaData) + const dataSourceList = useStore(s => s.dataSourceList) const blocks = useMemo(() => { const result = availableNodesMetaData?.nodes || [] @@ -33,8 +34,6 @@ const NodeSelectorWrapper = (props: NodeSelectorProps) => { }) }, [availableNodesMetaData?.nodes]) - const dataSourceList = useDataSources() - return ( { const workflowTools = useStore(s => s.workflowTools) const { data: strategyProviders } = useStrategyProviders() const datasetsDetail = useDatasetsDetailStore(s => s.datasetsDetail) + const { getStartNodes } = useWorkflow() const getCheckData = useCallback((data: CommonNodeType<{}>) => { let checkData = data @@ -62,7 +64,14 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { const needWarningNodes = useMemo(() => { const list = [] - const { validNodes } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges) + const filteredNodes = nodes.filter(node => node.type === CUSTOM_NODE) + const startNodes = getStartNodes(filteredNodes) + const validNodesFlattened = startNodes.map(startNode => getValidTreeNodes(startNode, filteredNodes, edges)) + const validNodes = validNodesFlattened.reduce((acc, curr) => { + if (curr.validNodes) + acc.push(...curr.validNodes) + return acc + }, [] as Node[]) for (let i = 0; i < nodes.length; i++) { const node = nodes[i] @@ -126,7 +135,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { }) return list - }, [nodes, edges, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders, getCheckData]) + }, [nodes, edges, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders, getCheckData, getStartNodes]) return needWarningNodes } @@ -143,6 +152,7 @@ export const useChecklistBeforePublish = () => { const { data: strategyProviders } = useStrategyProviders() const updateDatasetsDetail = useDatasetsDetailStore(s => s.updateDatasetsDetail) const updateTime = useRef(0) + const { getStartNodes } = useWorkflow() const getCheckData = useCallback((data: CommonNodeType<{}>, datasets: DataSet[]) => { let checkData = data @@ -170,15 +180,22 @@ export const useChecklistBeforePublish = () => { getNodes, edges, } = store.getState() - const nodes = getNodes().filter(node => node.type === CUSTOM_NODE) - const { - validNodes, - maxDepth, - } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges) + const nodes = getNodes() + const filteredNodes = nodes.filter(node => node.type === CUSTOM_NODE) + const startNodes = getStartNodes(filteredNodes) + const validNodesFlattened = startNodes.map(startNode => getValidTreeNodes(startNode, filteredNodes, edges)) + const validNodes = validNodesFlattened.reduce((acc, curr) => { + if (curr.validNodes) + acc.push(...curr.validNodes) + return acc + }, [] as Node[]) + const maxDepthArr = validNodesFlattened.map(item => item.maxDepth) - if (maxDepth > MAX_TREE_DEPTH) { - notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) }) - return false + for (let i = 0; i < maxDepthArr.length; i++) { + if (maxDepthArr[i] > MAX_TREE_DEPTH) { + notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) }) + return false + } } // Before publish, we need to fetch datasets detail, in case of the settings of datasets have been changed const knowledgeRetrievalNodes = nodes.filter(node => node.data.type === BlockEnum.KnowledgeRetrieval) @@ -243,7 +260,7 @@ export const useChecklistBeforePublish = () => { } return true - }, [store, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData]) + }, [store, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData, getStartNodes]) return { handleCheckBeforePublish, diff --git a/web/app/components/workflow/hooks/use-tool-icon.ts b/web/app/components/workflow/hooks/use-tool-icon.ts index 8b0f504716..9e72029455 100644 --- a/web/app/components/workflow/hooks/use-tool-icon.ts +++ b/web/app/components/workflow/hooks/use-tool-icon.ts @@ -10,7 +10,6 @@ import { import { useStore, } from '../store' -import { useDataSources } from '../block-selector/hooks' import { CollectionType } from '@/app/components/tools/types' import { canFindTool } from '@/utils' @@ -18,7 +17,7 @@ export const useToolIcon = (data: Node['data']) => { const buildInTools = useStore(s => s.buildInTools) const customTools = useStore(s => s.customTools) const workflowTools = useStore(s => s.workflowTools) - const dataSourceList = useDataSources() + const dataSourceList = useStore(s => s.dataSourceList) // const a = useStore(s => s.data) const toolIcon = useMemo(() => { if (data.type === BlockEnum.Tool) { @@ -32,7 +31,7 @@ export const useToolIcon = (data: Node['data']) => { return targetTools.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon } if (data.type === BlockEnum.DataSource) - return dataSourceList.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon + return dataSourceList?.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon }, [data, buildInTools, customTools, workflowTools, dataSourceList]) return toolIcon diff --git a/web/app/components/workflow/hooks/use-workflow.ts b/web/app/components/workflow/hooks/use-workflow.ts index e24a5f5b21..03334ae58b 100644 --- a/web/app/components/workflow/hooks/use-workflow.ts +++ b/web/app/components/workflow/hooks/use-workflow.ts @@ -347,8 +347,8 @@ export const useWorkflow = () => { return [] }, [store]) - const checkNestedParallelLimit = useCallback((nodes: Node[], edges: Edge[], targetNode?: Node) => { - const { id, parentId } = targetNode || {} + const getStartNodes = useCallback((nodes: Node[], currentNode?: Node) => { + const { id, parentId } = currentNode || {} let startNodes: Node[] = [] if (parentId) { @@ -367,6 +367,12 @@ export const useWorkflow = () => { if (!startNodes.length) startNodes = getRootNodesById(id || '') + return startNodes + }, [nodesMap, getRootNodesById]) + + const checkNestedParallelLimit = useCallback((nodes: Node[], edges: Edge[], targetNode?: Node) => { + const startNodes = getStartNodes(nodes, targetNode) + for (let i = 0; i < startNodes.length; i++) { const { parallelList, @@ -389,7 +395,7 @@ export const useWorkflow = () => { } return true - }, [t, workflowStore, nodesMap, getRootNodesById]) + }, [t, workflowStore, getStartNodes]) const isValidConnection = useCallback(({ source, sourceHandle, target }: Connection) => { const { @@ -454,6 +460,7 @@ export const useWorkflow = () => { getIterationNodeChildren, getLoopNodeChildren, getRootNodesById, + getStartNodes, } } diff --git a/web/app/components/workflow/nodes/_base/node.tsx b/web/app/components/workflow/nodes/_base/node.tsx index 0a5f397c56..81e7e29e96 100644 --- a/web/app/components/workflow/nodes/_base/node.tsx +++ b/web/app/components/workflow/nodes/_base/node.tsx @@ -146,7 +146,7 @@ const BaseNode: FC = ({ data.type === BlockEnum.DataSource && (
- data source + {t('workflow.blocks.data-source')}
) diff --git a/web/app/components/workflow/nodes/data-source/panel.tsx b/web/app/components/workflow/nodes/data-source/panel.tsx index 329b47ef6b..854e9235c9 100644 --- a/web/app/components/workflow/nodes/data-source/panel.tsx +++ b/web/app/components/workflow/nodes/data-source/panel.tsx @@ -65,14 +65,17 @@ const Panel: FC> = ({ id, data }) => { - +
+ +
) diff --git a/web/app/components/workflow/utils/workflow.ts b/web/app/components/workflow/utils/workflow.ts index f81b255b78..0e3d55191f 100644 --- a/web/app/components/workflow/utils/workflow.ts +++ b/web/app/components/workflow/utils/workflow.ts @@ -84,9 +84,7 @@ export const getNodesConnectedSourceOrTargetHandleIdsMap = (changes: ConnectedSo return nodesConnectedSourceOrTargetHandleIdsMap } -export const getValidTreeNodes = (nodes: Node[], edges: Edge[]) => { - const startNode = nodes.find(node => node.data.type === BlockEnum.Start) - +export const getValidTreeNodes = (startNode: Node, nodes: Node[], edges: Edge[]) => { if (!startNode) { return { validNodes: [], diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index db578d940b..d230f90dc1 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -770,11 +770,6 @@ const translation = { currentLoopCount: 'Current loop count: {{count}}', totalLoopCount: 'Total loop count: {{count}}', }, - knowledgeBase: { - chunkStructure: 'Chunk Structure', - changeChunkStructure: 'Change Chunk Structure', - aboutRetrieval: 'about retrieval method.', - }, note: { addNote: 'Add Note', editor: { @@ -889,6 +884,15 @@ const translation = { cancel: 'Cancel', }, }, + dataSource: { + supportedFileFormats: 'Supported file formats', + supportedFileFormatsPlaceholder: 'File extension, e.g. doc', + }, + knowledgeBase: { + chunkStructure: 'Chunk Structure', + changeChunkStructure: 'Change Chunk Structure', + aboutRetrieval: 'about retrieval method.', + }, }, tracing: { stopBy: 'Stop by {{user}}', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index 54cd596268..667dd4bf62 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -771,11 +771,6 @@ const translation = { currentLoopCount: '当前循环次数:{{count}}', totalLoopCount: '总循环次数:{{count}}', }, - knowledgeBase: { - chunkStructure: '分段结构', - changeChunkStructure: '更改分段结构', - aboutRetrieval: '关于知识检索。', - }, note: { addNote: '添加注释', editor: { @@ -890,6 +885,15 @@ const translation = { cancel: '取消', }, }, + dataSource: { + supportedFileFormats: '支持的文件格式', + supportedFileFormatsPlaceholder: '文件格式,例如:doc', + }, + knowledgeBase: { + chunkStructure: '分段结构', + changeChunkStructure: '更改分段结构', + aboutRetrieval: '关于知识检索。', + }, }, tracing: { stopBy: '由{{user}}终止', diff --git a/web/service/use-pipeline.ts b/web/service/use-pipeline.ts index 58b2a32756..46520b996a 100644 --- a/web/service/use-pipeline.ts +++ b/web/service/use-pipeline.ts @@ -160,12 +160,14 @@ export const usePublishedPipelineProcessingParams = (params: PipelineProcessingP }) } -export const useDataSourceList = (enabled?: boolean) => { +export const useDataSourceList = (enabled: boolean, onSuccess: (v: ToolWithProvider[]) => void) => { return useQuery({ enabled, queryKey: [NAME_SPACE, 'data-source'], - queryFn: () => { - return get('/rag/pipelines/datasource-plugins') + queryFn: async () => { + const data = await get('/rag/pipelines/datasource-plugins') + onSuccess(data) + return data }, retry: false, })