Files
hudi-service/service-web/client/test.ts

85 lines
5.6 KiB
TypeScript

type Node = {
id: string
type: 'start' | 'end' | 'normal'
}
type Edge = {
source: string
target: string
}
// language=JSON
let data = JSON.parse('{\n "nodes": [\n {\n "id": "A",\n "type": "start",\n "position": {\n "x": 8,\n "y": 272\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 75\n },\n "selected": false,\n "dragging": false\n },\n {\n "id": "F",\n "type": "end",\n "position": {\n "x": 1439.5556937134281,\n "y": 282.2797340760818\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 75\n },\n "selected": false,\n "dragging": false\n },\n {\n "id": "C",\n "type": "normal",\n "position": {\n "x": 902.6781018665707,\n "y": 115.31234529524048\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 75\n },\n "selected": false,\n "dragging": false\n },\n {\n "id": "B",\n "type": "normal",\n "position": {\n "x": 338,\n "y": 287\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 75\n },\n "selected": false,\n "dragging": false\n },\n {\n "id": "E",\n "type": "normal",\n "position": {\n "x": 1086.6322978498904,\n "y": 371.3061114283591\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 75\n },\n "selected": true,\n "dragging": false\n },\n {\n "id": "D",\n "type": "normal",\n "position": {\n "x": 700.0944461714178,\n "y": 369.84258971430364\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 75\n },\n "selected": false,\n "dragging": false\n }\n ],\n "edges": [\n {\n "source": "A",\n "target": "B",\n "id": "xy-edge__A-B"\n },\n {\n "source": "B",\n "target": "C",\n "id": "xy-edge__B-C"\n },\n {\n "source": "C",\n "target": "F",\n "id": "xy-edge__C-F"\n },\n {\n "source": "D",\n "target": "E",\n "id": "xy-edge__D-E"\n },\n {\n "source": "B",\n "target": "D",\n "id": "xy-edge__B-D"\n },\n {\n "source": "E",\n "target": "F",\n "id": "xy-edge__E-F"\n }\n ],\n "data": {\n "A": {\n "inputs": {\n "name": {\n "type": "text"\n },\n "description": {\n "type": "text",\n "description": "文件描述"\n }\n }\n },\n "C": {\n "model": "qwen3",\n "outputs": {\n "text": {\n "type": "string"\n }\n },\n "systemPrompt": "你是个沙雕"\n },\n "B": {\n "count": 3,\n "score": 0.75,\n "knowledgeId": 3585368238960640,\n "query": "hello world"\n },\n "E": {\n "type": "python",\n "content": "code=\'hello\'\\nprint(code)"\n },\n "D": {\n "model": "qwen3",\n "outputs": {\n "text": {\n "type": "string"\n }\n },\n "systemPrompt": "你是个聪明人"\n }\n }\n}')
// THEN(A, B, WHEN(C, THEN(D, E)), F)
function buildEL(nodes: Node[], edges: Edge[]): string {
// Build adjacency list and in-degree map
const adjList = new Map<string, string[]>()
const inDegree = new Map<string, number>()
for (const node of nodes) {
adjList.set(node.id, [])
inDegree.set(node.id, 0)
}
for (const edge of edges) {
adjList.get(edge.source)!.push(edge.target)
inDegree.set(edge.target, inDegree.get(edge.target)! + 1)
}
// Compute levels (longest path from start)
const levelMap = new Map<string, number>()
function computeLevel(nodeId: string): number {
if (levelMap.has(nodeId)) return levelMap.get(nodeId)!
const preds = edges.filter(e => e.target === nodeId).map(e => e.source)
const level = preds.length === 0 ? 0 : Math.max(...preds.map(p => computeLevel(p))) + 1
levelMap.set(nodeId, level)
return level
}
for (const node of nodes) computeLevel(node.id)
// Group nodes by level
const maxLevel = Math.max(...Array.from(levelMap.values()))
const levels: string[][] = Array.from({length: maxLevel + 1}, () => [])
for (const node of nodes) levels[levelMap.get(node.id)!].push(node.id)
// Build EL expression
const expressions: string[] = []
for (let i = 0; i <= maxLevel; i++) {
const nodesAtLevel = levels[i]
if (nodesAtLevel.length === 0) continue
// Identify serial chains starting from this level
const serialChains: string[] = []
for (const nodeId of nodesAtLevel) {
let chain = [nodeId]
let current = nodeId
while (adjList.get(current)?.length === 1) {
const next = adjList.get(current)![0]
if (inDegree.get(next) === 1 && levelMap.get(next) === i + chain.length) {
chain.push(next)
current = next
} else break
}
if (chain.length > 1) {
serialChains.push(`THEN(${chain.join(', ')})`)
// Remove processed nodes from their levels
for (let j = 1; j < chain.length; j++) {
const level = levelMap.get(chain[j])!
levels[level] = levels[level].filter(n => n !== chain[j])
}
} else {
serialChains.push(nodeId)
}
}
// Combine chains or nodes at this level
expressions.push(serialChains.length > 1 ? `WHEN(${serialChains.join(', ')})` : serialChains[0])
}
return `THEN(${expressions.join(', ')})`
}
console.log(buildEL(data.nodes, data.edges))