Files
ai-agent/workflow/service/flow/flow_helper.go
T
19904408334 d699f7ce14 feat(workflow): 增加工作流计费与执行生命周期管理
- 新增计费模块:执行开始建单、终态结算/取消/失败处理,支持按条/按秒/按token计费
- 新增执行生命周期跟踪:优雅关停时取消运行中执行并等待落库
- 新增异步任务等待/通知机制(Wait/Notify)
- 重构执行记录落库与进度上报,统一失败分类与重试语义
- 重命名文件:async_task.go→async.go、flow_checkpoint_store.go→exec_checkpoint.go、flow_graph_util.go→exec_record.go
- 更新 .gitignore 与数据库密码配置
2026-09-03 13:22:22 +08:00

88 lines
2.0 KiB
Go

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 ""
}
}