mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-29 07:01:04 +03:00
add if else node and logic
This commit is contained in:
@@ -95,9 +95,13 @@ export const getNodeModulesPackagePath = (packageName: string): string => {
|
||||
* Construct graph and node dependencies score
|
||||
* @param {IReactFlowNode[]} reactFlowNodes
|
||||
* @param {IReactFlowEdge[]} reactFlowEdges
|
||||
* @param {boolean} isNondirected
|
||||
* @param {{ isNonDirected?: boolean, isReversed?: boolean }} options
|
||||
*/
|
||||
export const constructGraphs = (reactFlowNodes: IReactFlowNode[], reactFlowEdges: IReactFlowEdge[], isNondirected = false) => {
|
||||
export const constructGraphs = (
|
||||
reactFlowNodes: IReactFlowNode[],
|
||||
reactFlowEdges: IReactFlowEdge[],
|
||||
options?: { isNonDirected?: boolean; isReversed?: boolean }
|
||||
) => {
|
||||
const nodeDependencies = {} as INodeDependencies
|
||||
const graph = {} as INodeDirectedGraph
|
||||
|
||||
@@ -107,6 +111,23 @@ export const constructGraphs = (reactFlowNodes: IReactFlowNode[], reactFlowEdges
|
||||
graph[nodeId] = []
|
||||
}
|
||||
|
||||
if (options && options.isReversed) {
|
||||
for (let i = 0; i < reactFlowEdges.length; i += 1) {
|
||||
const source = reactFlowEdges[i].source
|
||||
const target = reactFlowEdges[i].target
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(graph, target)) {
|
||||
graph[target].push(source)
|
||||
} else {
|
||||
graph[target] = [source]
|
||||
}
|
||||
|
||||
nodeDependencies[target] += 1
|
||||
}
|
||||
|
||||
return { graph, nodeDependencies }
|
||||
}
|
||||
|
||||
for (let i = 0; i < reactFlowEdges.length; i += 1) {
|
||||
const source = reactFlowEdges[i].source
|
||||
const target = reactFlowEdges[i].target
|
||||
@@ -117,7 +138,7 @@ export const constructGraphs = (reactFlowNodes: IReactFlowNode[], reactFlowEdges
|
||||
graph[source] = [target]
|
||||
}
|
||||
|
||||
if (isNondirected) {
|
||||
if (options && options.isNonDirected) {
|
||||
if (Object.prototype.hasOwnProperty.call(graph, target)) {
|
||||
graph[target].push(source)
|
||||
} else {
|
||||
@@ -179,21 +200,49 @@ export const getStartingNodes = (graph: INodeDirectedGraph, endNodeId: string) =
|
||||
return { startingNodeIds, depthQueue: depthQueueReversed }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all connected nodes from startnode
|
||||
* @param {INodeDependencies} graph
|
||||
* @param {string} startNodeId
|
||||
*/
|
||||
export const getAllConnectedNodes = (graph: INodeDirectedGraph, startNodeId: string) => {
|
||||
const visited = new Set<string>()
|
||||
const queue: Array<[string]> = [[startNodeId]]
|
||||
|
||||
while (queue.length > 0) {
|
||||
const [currentNode] = queue.shift()!
|
||||
|
||||
if (visited.has(currentNode)) {
|
||||
continue
|
||||
}
|
||||
|
||||
visited.add(currentNode)
|
||||
|
||||
for (const neighbor of graph[currentNode]) {
|
||||
if (!visited.has(neighbor)) {
|
||||
queue.push([neighbor])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...visited]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ending node and check if flow is valid
|
||||
* @param {INodeDependencies} nodeDependencies
|
||||
* @param {INodeDirectedGraph} graph
|
||||
*/
|
||||
export const getEndingNode = (nodeDependencies: INodeDependencies, graph: INodeDirectedGraph) => {
|
||||
let endingNodeId = ''
|
||||
export const getEndingNodes = (nodeDependencies: INodeDependencies, graph: INodeDirectedGraph) => {
|
||||
const endingNodeIds: string[] = []
|
||||
Object.keys(graph).forEach((nodeId) => {
|
||||
if (Object.keys(nodeDependencies).length === 1) {
|
||||
endingNodeId = nodeId
|
||||
endingNodeIds.push(nodeId)
|
||||
} else if (!graph[nodeId].length && nodeDependencies[nodeId] > 0) {
|
||||
endingNodeId = nodeId
|
||||
endingNodeIds.push(nodeId)
|
||||
}
|
||||
})
|
||||
return endingNodeId
|
||||
return endingNodeIds
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,6 +262,7 @@ export const getEndingNode = (nodeDependencies: INodeDependencies, graph: INodeD
|
||||
export const buildLangchain = async (
|
||||
startingNodeIds: string[],
|
||||
reactFlowNodes: IReactFlowNode[],
|
||||
reactFlowEdges: IReactFlowEdge[],
|
||||
graph: INodeDirectedGraph,
|
||||
depthQueue: IDepthQueue,
|
||||
componentNodes: IComponentNodes,
|
||||
@@ -232,6 +282,7 @@ export const buildLangchain = async (
|
||||
const nodeQueue = [] as INodeQueue[]
|
||||
const exploredNode = {} as IExploredNode
|
||||
const dynamicVariables = {} as Record<string, unknown>
|
||||
let ignoreNodeIds: string[] = []
|
||||
|
||||
// In the case of infinite loop, only max 3 loops will be executed
|
||||
const maxLoop = 3
|
||||
@@ -296,6 +347,29 @@ export const buildLangchain = async (
|
||||
outputResult = outputResult?.output
|
||||
}
|
||||
|
||||
// Determine which nodes to route next when it comes to ifElse
|
||||
if (reactFlowNode.data.name === 'ifElseFunction' && typeof outputResult === 'object') {
|
||||
let sourceHandle = ''
|
||||
if (outputResult.type === true) {
|
||||
sourceHandle = `${nodeId}-output-returnFalse-string|number|boolean|json|array`
|
||||
} else if (outputResult.type === false) {
|
||||
sourceHandle = `${nodeId}-output-returnTrue-string|number|boolean|json|array`
|
||||
}
|
||||
|
||||
const ifElseEdge = reactFlowEdges.find((edg) => edg.source === nodeId && edg.sourceHandle === sourceHandle)
|
||||
if (ifElseEdge) {
|
||||
const { graph } = constructGraphs(
|
||||
reactFlowNodes,
|
||||
reactFlowEdges.filter((edg) => !(edg.source === nodeId && edg.sourceHandle === sourceHandle)),
|
||||
{ isNonDirected: true }
|
||||
)
|
||||
ignoreNodeIds.push(ifElseEdge.target, ...getAllConnectedNodes(graph, ifElseEdge.target))
|
||||
ignoreNodeIds = [...new Set(ignoreNodeIds)]
|
||||
}
|
||||
|
||||
outputResult = outputResult?.output
|
||||
}
|
||||
|
||||
flowNodes[nodeIndex].data.instance = outputResult
|
||||
|
||||
logger.debug(`[server]: Finished initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||
@@ -305,7 +379,7 @@ export const buildLangchain = async (
|
||||
throw new Error(e)
|
||||
}
|
||||
|
||||
const neighbourNodeIds = graph[nodeId]
|
||||
let neighbourNodeIds = graph[nodeId]
|
||||
const nextDepth = depth + 1
|
||||
|
||||
// Find other nodes that are on the same depth level
|
||||
@@ -316,9 +390,11 @@ export const buildLangchain = async (
|
||||
neighbourNodeIds.push(id)
|
||||
}
|
||||
|
||||
neighbourNodeIds = neighbourNodeIds.filter((neigh) => !ignoreNodeIds.includes(neigh))
|
||||
|
||||
for (let i = 0; i < neighbourNodeIds.length; i += 1) {
|
||||
const neighNodeId = neighbourNodeIds[i]
|
||||
|
||||
if (ignoreNodeIds.includes(neighNodeId)) continue
|
||||
// If nodeId has been seen, cycle detected
|
||||
if (Object.prototype.hasOwnProperty.call(exploredNode, neighNodeId)) {
|
||||
const { remainingLoop, lastSeenDepth } = exploredNode[neighNodeId]
|
||||
@@ -336,6 +412,12 @@ export const buildLangchain = async (
|
||||
nodeQueue.push({ nodeId: neighNodeId, depth: nextDepth })
|
||||
}
|
||||
}
|
||||
|
||||
// Move end node to last
|
||||
if (!neighbourNodeIds.length) {
|
||||
const index = flowNodes.findIndex((nd) => nd.data.id === nodeId)
|
||||
flowNodes.push(flowNodes.splice(index, 1)[0])
|
||||
}
|
||||
}
|
||||
return flowNodes
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user