feat(web): 尝试增加并行节点解决解析问题
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package com.lanyuanxiaoyao.service.ai.web.flow;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250625
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseNode extends NodeComponent {
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
log.info(getClass().getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.lanyuanxiaoyao.service.ai.web.flow;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250625
|
||||
*/
|
||||
public class EndNode extends BaseNode {
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
package com.lanyuanxiaoyao.service.ai.web.flow;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.eclipsecollections.EclipseCollectionsModule;
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.collections.api.factory.Lists;
|
||||
import org.eclipse.collections.api.factory.Maps;
|
||||
import org.eclipse.collections.api.list.ImmutableList;
|
||||
import org.eclipse.collections.api.list.MutableList;
|
||||
import org.eclipse.collections.api.map.ImmutableMap;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250625
|
||||
*/
|
||||
@Slf4j
|
||||
public class LiteFlowService {
|
||||
public LiteFlowService() {
|
||||
createNode("start-amis-node", NodeTypeEnum.COMMON, StartNode.class);
|
||||
createNode("end-amis-node", NodeTypeEnum.COMMON, EndNode.class);
|
||||
createNode("llm-amis-node", NodeTypeEnum.COMMON, LlmNode.class);
|
||||
}
|
||||
|
||||
private static void createNode(String name, NodeTypeEnum type, Class<? extends NodeComponent> clazz) {
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId(name)
|
||||
.setName(name)
|
||||
.setType(type)
|
||||
.setClazz(clazz)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws JsonProcessingException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.registerModule(new EclipseCollectionsModule());
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// language=JSON
|
||||
String source = """
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "A",
|
||||
"type": "start",
|
||||
"position": {
|
||||
"x": 8,
|
||||
"y": 272
|
||||
},
|
||||
"data": {},
|
||||
"measured": {
|
||||
"width": 256,
|
||||
"height": 75
|
||||
},
|
||||
"selected": false,
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"id": "F",
|
||||
"type": "end",
|
||||
"position": {
|
||||
"x": 1439.5556937134281,
|
||||
"y": 282.2797340760818
|
||||
},
|
||||
"data": {},
|
||||
"measured": {
|
||||
"width": 256,
|
||||
"height": 75
|
||||
},
|
||||
"selected": false,
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"id": "C",
|
||||
"type": "normal",
|
||||
"position": {
|
||||
"x": 902.6781018665707,
|
||||
"y": 115.31234529524048
|
||||
},
|
||||
"data": {},
|
||||
"measured": {
|
||||
"width": 256,
|
||||
"height": 75
|
||||
},
|
||||
"selected": false,
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"id": "B",
|
||||
"type": "normal",
|
||||
"position": {
|
||||
"x": 338,
|
||||
"y": 287
|
||||
},
|
||||
"data": {},
|
||||
"measured": {
|
||||
"width": 256,
|
||||
"height": 75
|
||||
},
|
||||
"selected": false,
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"id": "E",
|
||||
"type": "normal",
|
||||
"position": {
|
||||
"x": 1086.6322978498904,
|
||||
"y": 371.3061114283591
|
||||
},
|
||||
"data": {},
|
||||
"measured": {
|
||||
"width": 256,
|
||||
"height": 75
|
||||
},
|
||||
"selected": true,
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"id": "D",
|
||||
"type": "normal",
|
||||
"position": {
|
||||
"x": 700.0944461714178,
|
||||
"y": 369.84258971430364
|
||||
},
|
||||
"data": {},
|
||||
"measured": {
|
||||
"width": 256,
|
||||
"height": 75
|
||||
},
|
||||
"selected": false,
|
||||
"dragging": false
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "A",
|
||||
"target": "B",
|
||||
"id": "xy-edge__A-B"
|
||||
},
|
||||
{
|
||||
"source": "B",
|
||||
"target": "C",
|
||||
"id": "xy-edge__B-C"
|
||||
},
|
||||
{
|
||||
"source": "C",
|
||||
"target": "F",
|
||||
"id": "xy-edge__C-F"
|
||||
},
|
||||
{
|
||||
"source": "D",
|
||||
"target": "E",
|
||||
"id": "xy-edge__D-E"
|
||||
},
|
||||
{
|
||||
"source": "B",
|
||||
"target": "D",
|
||||
"id": "xy-edge__B-D"
|
||||
},
|
||||
{
|
||||
"source": "E",
|
||||
"target": "F",
|
||||
"id": "xy-edge__E-F"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"A": {
|
||||
"inputs": {
|
||||
"name": {
|
||||
"type": "text"
|
||||
},
|
||||
"description": {
|
||||
"type": "text",
|
||||
"description": "文件描述"
|
||||
}
|
||||
}
|
||||
},
|
||||
"C": {
|
||||
"model": "qwen3",
|
||||
"outputs": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"systemPrompt": "你是个沙雕"
|
||||
},
|
||||
"B": {
|
||||
"count": 3,
|
||||
"score": 0.75,
|
||||
"knowledgeId": 3585368238960640,
|
||||
"query": "hello world"
|
||||
},
|
||||
"E": {
|
||||
"type": "python",
|
||||
"content": "code='hello'\\nprint(code)"
|
||||
},
|
||||
"D": {
|
||||
"model": "qwen3",
|
||||
"outputs": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"systemPrompt": "你是个聪明人"
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
FlowData root = mapper.readValue(StrUtil.trim(source), FlowData.class);
|
||||
log.info("\n{}", buildEl(root.nodes, root.edges));
|
||||
}
|
||||
|
||||
public static String buildEl(ImmutableList<FlowData.Node> nodes, ImmutableList<FlowData.Edge> edges) {
|
||||
var nodeMap = nodes.toMap(FlowData.Node::getId, node -> node);
|
||||
var adjacencyGraph = Maps.mutable.<String, MutableList<String>>empty();
|
||||
var reverseAdjacencyGraph = Maps.mutable.<String, MutableList<String>>empty();
|
||||
var inDegree = Maps.mutable.<String, Integer>empty();
|
||||
|
||||
nodes.forEach(node -> {
|
||||
adjacencyGraph.put(node.getId(), Lists.mutable.empty());
|
||||
reverseAdjacencyGraph.put(node.getId(), Lists.mutable.empty());
|
||||
inDegree.put(node.getId(), 0);
|
||||
});
|
||||
edges.forEach(edge -> {
|
||||
adjacencyGraph.get(edge.getSource()).add(edge.getTarget());
|
||||
reverseAdjacencyGraph.get(edge.getTarget()).add(edge.getSource());
|
||||
inDegree.put(edge.getTarget(), inDegree.get(edge.getTarget()) + 1);
|
||||
});
|
||||
|
||||
Queue<String> queue = new LinkedList<>();
|
||||
var topologicalSortedList = Lists.mutable.<String>empty();
|
||||
|
||||
inDegree.forEachKeyValue((id, count) -> {
|
||||
if (count == 0) {
|
||||
queue.offer(id);
|
||||
}
|
||||
});
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
String id = queue.poll();
|
||||
topologicalSortedList.add(id);
|
||||
for (var neighborId : adjacencyGraph.get(id)) {
|
||||
inDegree.put(neighborId, inDegree.get(neighborId) - 1);
|
||||
if (inDegree.get(neighborId) == 0) {
|
||||
queue.offer(neighborId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
topologicalSortedList.forEach(id -> log.info("{} {}", id, adjacencyGraph.get(id)));
|
||||
topologicalSortedList.forEach(id -> log.info("{} {}", id, reverseAdjacencyGraph.get(id)));
|
||||
|
||||
var nodeQueue = new LinkedList<>(topologicalSortedList);
|
||||
var chains = Lists.mutable.<MutableList<String>>empty();
|
||||
while (!nodeQueue.isEmpty()) {
|
||||
String currentId = nodeQueue.poll();
|
||||
var subChain = Lists.mutable.<String>empty();
|
||||
while (true) {
|
||||
subChain.add(currentId);
|
||||
nodeQueue.remove(currentId);
|
||||
if (adjacencyGraph.get(currentId).size() != 1) {
|
||||
break;
|
||||
}
|
||||
String nextId = adjacencyGraph.get(currentId).get(0);
|
||||
if (reverseAdjacencyGraph.get(nextId).size() > 1) {
|
||||
break;
|
||||
}
|
||||
currentId = nextId;
|
||||
}
|
||||
chains.add(subChain);
|
||||
}
|
||||
|
||||
log.info("{}", chains);
|
||||
|
||||
return StrUtil.join(",", topologicalSortedList);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class FlowData {
|
||||
private ImmutableList<Node> nodes;
|
||||
private ImmutableList<Edge> edges;
|
||||
private ImmutableMap<String, Object> data;
|
||||
|
||||
@Data
|
||||
public static class Node {
|
||||
private String id;
|
||||
private String type;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Edge {
|
||||
private String id;
|
||||
private String source;
|
||||
private String target;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.lanyuanxiaoyao.service.ai.web.flow;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250625
|
||||
*/
|
||||
public class LlmNode extends BaseNode {
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.lanyuanxiaoyao.service.ai.web.flow;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250625
|
||||
*/
|
||||
public class StartNode extends BaseNode {
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user