chore: make codes the repository root
This commit is contained in:
90
internal/sop/validator.go
Normal file
90
internal/sop/validator.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package sop
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/model"
|
||||
)
|
||||
|
||||
var allowedNodeTypes = map[string]bool{"start": true, "message": true, "question": true, "form": true, "choice": true, "condition": true, "knowledge": true, "escalate": true, "finish": true}
|
||||
|
||||
func ValidateGraph(startNodeKey string, nodes []model.SOPNode, edges []model.SOPEdge) []string {
|
||||
var problems []string
|
||||
if startNodeKey == "" {
|
||||
problems = append(problems, "未设置开始节点")
|
||||
}
|
||||
nodeMap := make(map[string]model.SOPNode, len(nodes))
|
||||
startCount := 0
|
||||
finishCount := 0
|
||||
for _, node := range nodes {
|
||||
if node.NodeKey == "" {
|
||||
problems = append(problems, "存在没有标识的节点")
|
||||
continue
|
||||
}
|
||||
if _, exists := nodeMap[node.NodeKey]; exists {
|
||||
problems = append(problems, fmt.Sprintf("节点标识重复:%s", node.NodeKey))
|
||||
}
|
||||
nodeMap[node.NodeKey] = node
|
||||
if !allowedNodeTypes[node.Type] {
|
||||
problems = append(problems, fmt.Sprintf("节点 %s 类型不支持", node.Title))
|
||||
}
|
||||
if node.Type == "start" {
|
||||
startCount++
|
||||
}
|
||||
if node.Type == "finish" || node.Type == "escalate" {
|
||||
finishCount++
|
||||
}
|
||||
}
|
||||
if startCount != 1 {
|
||||
problems = append(problems, "流程必须且只能包含一个开始节点")
|
||||
}
|
||||
if finishCount == 0 {
|
||||
problems = append(problems, "流程至少需要一个结束或转人工节点")
|
||||
}
|
||||
if _, exists := nodeMap[startNodeKey]; !exists && startNodeKey != "" {
|
||||
problems = append(problems, "开始节点不存在")
|
||||
}
|
||||
|
||||
adjacency := make(map[string][]string)
|
||||
outgoing := make(map[string]int)
|
||||
for _, edge := range edges {
|
||||
if _, exists := nodeMap[edge.SourceNodeKey]; !exists {
|
||||
problems = append(problems, fmt.Sprintf("连线起点不存在:%s", edge.SourceNodeKey))
|
||||
}
|
||||
if _, exists := nodeMap[edge.TargetNodeKey]; !exists {
|
||||
problems = append(problems, fmt.Sprintf("连线终点不存在:%s", edge.TargetNodeKey))
|
||||
}
|
||||
if len(edge.Condition) > 0 && !json.Valid(edge.Condition) {
|
||||
problems = append(problems, fmt.Sprintf("连线 %s -> %s 的条件不是有效 JSON", edge.SourceNodeKey, edge.TargetNodeKey))
|
||||
}
|
||||
adjacency[edge.SourceNodeKey] = append(adjacency[edge.SourceNodeKey], edge.TargetNodeKey)
|
||||
outgoing[edge.SourceNodeKey]++
|
||||
}
|
||||
for _, node := range nodes {
|
||||
if node.Type != "finish" && node.Type != "escalate" && outgoing[node.NodeKey] == 0 {
|
||||
problems = append(problems, fmt.Sprintf("节点“%s”没有下一步", node.Title))
|
||||
}
|
||||
}
|
||||
|
||||
visited := map[string]bool{}
|
||||
var walk func(string)
|
||||
walk = func(key string) {
|
||||
if visited[key] {
|
||||
return
|
||||
}
|
||||
visited[key] = true
|
||||
for _, next := range adjacency[key] {
|
||||
walk(next)
|
||||
}
|
||||
}
|
||||
if startNodeKey != "" {
|
||||
walk(startNodeKey)
|
||||
}
|
||||
for key, node := range nodeMap {
|
||||
if !visited[key] {
|
||||
problems = append(problems, fmt.Sprintf("节点“%s”无法从开始节点到达", node.Title))
|
||||
}
|
||||
}
|
||||
return problems
|
||||
}
|
||||
Reference in New Issue
Block a user