package flow import ( "ai-agent/workflow/model/entity" "net/url" "path/filepath" "strings" ) // FindEndNodes 从指定起始节点开始,遍历图找到所有末端节点(没有出边的节点) func FindEndNodes(startNodeId string, edges []entity.FlowEdge) []string { nextMap := make(map[string][]string) for _, e := range edges { nextMap[e.From] = append(nextMap[e.From], e.To) } endNodeSet := make(map[string]struct{}) visited := make(map[string]struct{}) queue := []string{startNodeId} for len(queue) > 0 { node := queue[0] queue = queue[1:] if _, exist := visited[node]; exist { continue } visited[node] = struct{}{} nextList := nextMap[node] if len(nextList) == 0 { endNodeSet[node] = struct{}{} continue } queue = append(queue, nextList...) } res := make([]string, 0, len(endNodeSet)) for k := range endNodeSet { res = append(res, k) } return res } // ExtractFlowNodeFrom 从 FlowInfo 中提取节点列表(返回指针切片) func ExtractFlowNodeFrom(flowContent *entity.FlowInfo) []*entity.FlowNode { var flowNodes []*entity.FlowNode for _, item := range flowContent.Nodes { flowNodes = append(flowNodes, &item) } return flowNodes } // GetFileTypeByPath 根据文件路径/URL的后缀名判断文件类型 func GetFileTypeByPath(filePath string) string { if filePath == "" { return "" } // 解析 URL,获取真实路径(兼容 http 链接) u, err := url.Parse(filePath) if err == nil { filePath = u.Path } // 获取后缀(小写) ext := filepath.Ext(filePath) ext = strings.ToLower(ext) // 判断类型 switch ext { case ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp": return "image" case ".mp4", ".mov", ".avi", ".flv", ".wmv", ".mkv": return "video" case ".mp3", ".wav", ".m4a", ".flac", ".aac", ".ogg": return "audio" case ".txt", ".md", ".log", ".json", ".xml", ".inc": return "text" case ".html": return "html" case ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx": return "document" default: return "" } }