mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-19 19:59:10 +08:00
Merge branch 'feat/workflow-parallel-support' of github.com:langgenius/dify into feat/workflow-parallel-support
This commit is contained in:
commit
708256ef1d
@ -327,6 +327,7 @@ export const ITERATION_PADDING = {
|
||||
left: 16,
|
||||
}
|
||||
export const PARALLEL_LIMIT = 10
|
||||
export const PARALLEL_DEPTH_LIMIT = 3
|
||||
|
||||
export const RETRIEVAL_OUTPUT_STRUCT = `{
|
||||
"content": "",
|
||||
|
@ -30,6 +30,7 @@ import {
|
||||
useWorkflowStore,
|
||||
} from '../store'
|
||||
import {
|
||||
// PARALLEL_DEPTH_LIMIT,
|
||||
PARALLEL_LIMIT,
|
||||
SUPPORT_OUTPUT_VARS_NODE,
|
||||
} from '../constants'
|
||||
@ -279,6 +280,53 @@ export const useWorkflow = () => {
|
||||
return isUsed
|
||||
}, [isVarUsedInNodes])
|
||||
|
||||
const checkParallelLimit = useCallback((nodeId: string) => {
|
||||
const {
|
||||
getNodes,
|
||||
edges,
|
||||
} = store.getState()
|
||||
const nodes = getNodes()
|
||||
const currentNode = nodes.find(node => node.id === nodeId)!
|
||||
const sourceNodeOutgoers = getOutgoers(currentNode, nodes, edges)
|
||||
if (sourceNodeOutgoers.length > PARALLEL_LIMIT - 1) {
|
||||
const { setShowTips } = workflowStore.getState()
|
||||
setShowTips(t('workflow.common.parallelTip.limit', { num: PARALLEL_LIMIT }))
|
||||
return false
|
||||
}
|
||||
// if (sourceNodeOutgoers.length > 0) {
|
||||
// let hasOverDepth = false
|
||||
// let parallelDepth = 1
|
||||
// const traverse = (root: Node, depth: number) => {
|
||||
// if (depth > PARALLEL_DEPTH_LIMIT) {
|
||||
// hasOverDepth = true
|
||||
// return
|
||||
// }
|
||||
// if (depth > parallelDepth)
|
||||
// parallelDepth = depth
|
||||
|
||||
// const incomerNodes = getIncomers(root, nodes, edges)
|
||||
|
||||
// if (incomerNodes.length) {
|
||||
// incomerNodes.forEach((incomer) => {
|
||||
// const incomerOutgoers = getOutgoers(incomer, nodes, edges)
|
||||
|
||||
// if (incomerOutgoers.length > 1)
|
||||
// traverse(incomer, depth + 1)
|
||||
// else
|
||||
// traverse(incomer, depth)
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// traverse(currentNode, parallelDepth)
|
||||
// if (hasOverDepth) {
|
||||
// const { setShowTips } = workflowStore.getState()
|
||||
// setShowTips(t('workflow.common.parallelTip.depthLimit', { num: PARALLEL_DEPTH_LIMIT }))
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
return true
|
||||
}, [store, workflowStore, t])
|
||||
|
||||
const isValidConnection = useCallback(({ source, target }: Connection) => {
|
||||
const {
|
||||
edges,
|
||||
@ -288,17 +336,12 @@ export const useWorkflow = () => {
|
||||
const sourceNode: Node = nodes.find(node => node.id === source)!
|
||||
const targetNode: Node = nodes.find(node => node.id === target)!
|
||||
|
||||
if (!checkParallelLimit(source!))
|
||||
return false
|
||||
|
||||
if (sourceNode.type === CUSTOM_NOTE_NODE || targetNode.type === CUSTOM_NOTE_NODE)
|
||||
return false
|
||||
|
||||
const sourceNodeOutgoers = getOutgoers(sourceNode, nodes, edges)
|
||||
|
||||
if (sourceNodeOutgoers.length > PARALLEL_LIMIT - 1) {
|
||||
const { setShowTips } = workflowStore.getState()
|
||||
setShowTips(t('workflow.common.parallelTip.limit', { num: PARALLEL_LIMIT }))
|
||||
return false
|
||||
}
|
||||
|
||||
if (sourceNode && targetNode) {
|
||||
const sourceNodeAvailableNextNodes = nodesExtraData[sourceNode.data.type].availableNextNodes
|
||||
const targetNodeAvailablePrevNodes = [...nodesExtraData[targetNode.data.type].availablePrevNodes, BlockEnum.Start]
|
||||
@ -325,7 +368,7 @@ export const useWorkflow = () => {
|
||||
}
|
||||
|
||||
return !hasCycle(targetNode)
|
||||
}, [store, nodesExtraData])
|
||||
}, [store, nodesExtraData, checkParallelLimit])
|
||||
|
||||
const formatTimeFromNow = useCallback((time: number) => {
|
||||
return dayjs(time).locale(locale === 'zh-Hans' ? 'zh-cn' : locale).fromNow()
|
||||
@ -348,6 +391,7 @@ export const useWorkflow = () => {
|
||||
isVarUsedInNodes,
|
||||
removeUsedVarInNodes,
|
||||
isNodeVarsUsedInNodes,
|
||||
checkParallelLimit,
|
||||
isValidConnection,
|
||||
formatTimeFromNow,
|
||||
getNode,
|
||||
|
@ -14,6 +14,12 @@ const LimitTips = () => {
|
||||
|
||||
return (
|
||||
<div className='absolute bottom-16 left-1/2 -translate-x-1/2 flex items-center rounded-xl p-2 h-10 border border-components-panel-border bg-components-panel-bg-blur shadow-md z-[9]'>
|
||||
<div
|
||||
className='absolute inset-0 opacity-[0.4] rounded-xl'
|
||||
style={{
|
||||
background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.25) 0%, rgba(255, 255, 255, 0.00) 100%)',
|
||||
}}
|
||||
></div>
|
||||
<div className='flex items-center justify-center w-5 h-5'>
|
||||
<RiAlertFill className='w-4 h-4 text-text-warning-secondary' />
|
||||
</div>
|
||||
@ -21,6 +27,7 @@ const LimitTips = () => {
|
||||
{showTips}
|
||||
</div>
|
||||
<ActionButton
|
||||
className='z-[1]'
|
||||
onClick={() => setShowTips('')}
|
||||
>
|
||||
<RiCloseLine className='w-4 h-4' />
|
||||
|
@ -19,12 +19,11 @@ import {
|
||||
useIsChatMode,
|
||||
useNodesInteractions,
|
||||
useNodesReadOnly,
|
||||
useWorkflow,
|
||||
} from '../../../hooks'
|
||||
import {
|
||||
useStore,
|
||||
useWorkflowStore,
|
||||
} from '../../../store'
|
||||
import { PARALLEL_LIMIT } from '../../../constants'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
type NodeHandleProps = {
|
||||
@ -119,13 +118,13 @@ export const NodeSourceHandle = memo(({
|
||||
}: NodeHandleProps) => {
|
||||
const { t } = useTranslation()
|
||||
const notInitialWorkflow = useStore(s => s.notInitialWorkflow)
|
||||
const workflowStore = useWorkflowStore()
|
||||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeAdd } = useNodesInteractions()
|
||||
const { getNodesReadOnly } = useNodesReadOnly()
|
||||
const { availableNextBlocks } = useAvailableBlocks(data.type, data.isInIteration)
|
||||
const isConnectable = !!availableNextBlocks.length
|
||||
const isChatMode = useIsChatMode()
|
||||
const { checkParallelLimit } = useWorkflow()
|
||||
|
||||
const connected = data._connectedSourceHandleIds?.includes(handleId)
|
||||
const handleOpenChange = useCallback((v: boolean) => {
|
||||
@ -133,13 +132,9 @@ export const NodeSourceHandle = memo(({
|
||||
}, [])
|
||||
const handleHandleClick = useCallback((e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
if (data._connectedSourceHandleIds!.length > PARALLEL_LIMIT - 1) {
|
||||
const { setShowTips } = workflowStore.getState()
|
||||
setShowTips(t('workflow.common.parallelTip.limit', { num: PARALLEL_LIMIT }))
|
||||
return
|
||||
}
|
||||
setOpen(v => !v)
|
||||
}, [data._connectedSourceHandleIds])
|
||||
if (checkParallelLimit(id))
|
||||
setOpen(v => !v)
|
||||
}, [checkParallelLimit, id])
|
||||
const handleSelect = useCallback((type: BlockEnum, toolDefaultValue?: ToolDefaultValue) => {
|
||||
handleNodeAdd(
|
||||
{
|
||||
@ -156,7 +151,7 @@ export const NodeSourceHandle = memo(({
|
||||
useEffect(() => {
|
||||
if (notInitialWorkflow && data.type === BlockEnum.Start && !isChatMode)
|
||||
setOpen(true)
|
||||
}, [notInitialWorkflow, data.type])
|
||||
}, [notInitialWorkflow, data.type, isChatMode])
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
@ -95,6 +95,7 @@ export function getIterationStartNode(iterationId: string): Node {
|
||||
title: '',
|
||||
desc: '',
|
||||
type: BlockEnum.IterationStart,
|
||||
isInIteration: true,
|
||||
},
|
||||
position: {
|
||||
x: 24,
|
||||
|
@ -88,6 +88,7 @@ const translation = {
|
||||
desc: ' to connect',
|
||||
},
|
||||
limit: 'Parallelism is limited to {{num}} branches.',
|
||||
depthLimit: 'Parallel nesting layer limit of {{num}} layers',
|
||||
},
|
||||
},
|
||||
env: {
|
||||
|
@ -88,6 +88,7 @@ const translation = {
|
||||
desc: '连接节点',
|
||||
},
|
||||
limit: '并行分支限制为 {{num}} 个',
|
||||
depthLimit: '并行嵌套层数限制 {{num}} 层',
|
||||
},
|
||||
},
|
||||
env: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user