refactor: 重构工作流执行图构建与节点上下文处理
This commit is contained in:
@@ -15,17 +15,19 @@ const (
|
||||
NodeNameVideoModel = "生成视频"
|
||||
NodeNameAudioModel = "生成音频"
|
||||
NodeNameBatchModel = "批量处理一起返回"
|
||||
NodeNameDataConversionModel = "参数转换"
|
||||
NodeNameSenseOptimizeModel = "语义优化"
|
||||
NodeNameStoryOptimizeModel = "分镜优化"
|
||||
NodeNameScriptOptimizeModel = "剧本优化"
|
||||
NodeNameDataConversionModel = "参数转换"
|
||||
NodeNameModel = "模型"
|
||||
NodeNameMerge = "结果合并"
|
||||
NodeNameDataMerge = "结果汇集"
|
||||
NodeNameJudge = "条件判断"
|
||||
NodeNameLoop = "循环"
|
||||
NodeNameForm = "表单"
|
||||
NodeNameHttp = "HTTP(S)接口"
|
||||
NodeNameCustomNode = "自定义节点"
|
||||
NodeNameSystemSum = "系统-结果汇总"
|
||||
)
|
||||
|
||||
// 表单字段 Label
|
||||
@@ -54,20 +56,22 @@ const (
|
||||
NodeTypeAudioModel NodeType = "audio_model"
|
||||
NodeTypeBatchModel NodeType = "batch_model"
|
||||
|
||||
NodeTypeDataConversionModel NodeType = "data_conversion_model"
|
||||
NodeTypeSenseOptimizeModel NodeType = "sense_optimize_model"
|
||||
NodeTypeStoryOptimizeModel NodeType = "story_optimize_model"
|
||||
NodeTypeScriptOptimizeModel NodeType = "script_optimize_model"
|
||||
// 基础
|
||||
NodeTypeDataConversionModel NodeType = "data_conversion_model"
|
||||
NodeTypeModel NodeType = "model"
|
||||
NodeTypeMerge NodeType = "merge"
|
||||
NodeTypeDataMerge NodeType = "data_merge"
|
||||
NodeTypeJudge NodeType = "judge"
|
||||
NodeTypeForm NodeType = "form"
|
||||
NodeTypeIntent NodeType = "intent"
|
||||
NodeTypeHttp NodeType = "http"
|
||||
NodeTypeModel NodeType = "model"
|
||||
NodeTypeMerge NodeType = "merge"
|
||||
NodeTypeDataMerge NodeType = "data_merge"
|
||||
NodeTypeJudge NodeType = "judge"
|
||||
NodeTypeForm NodeType = "form"
|
||||
NodeTypeIntent NodeType = "intent"
|
||||
NodeTypeHttp NodeType = "http"
|
||||
// 自定义
|
||||
NodeTypeCustomNode NodeType = "custom_node"
|
||||
// 系统
|
||||
NodeTypeSystemSum NodeType = "system_sum"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -363,49 +363,12 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
||||
}
|
||||
return nil, errors.New("文件格式不支持")
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// ✅【第1步】给所有判断节点自动生成意图识别节点
|
||||
// =========================================================================
|
||||
judge2IntentNodeMap := make(map[string]string)
|
||||
finalNodes := make([]entity.FlowNode, 0, len(req.FlowContent.Nodes)*2)
|
||||
for _, item := range req.FlowContent.Nodes {
|
||||
finalNodes = append(finalNodes, item)
|
||||
// 判断节点自动加 intent 节点
|
||||
if item.NodeCode == node.NodeTypeJudge {
|
||||
intentNodeID := fmt.Sprintf("intent_%s", item.Id)
|
||||
intentNode := entity.FlowNode{
|
||||
Id: intentNodeID,
|
||||
NodeCode: node.NodeTypeIntent,
|
||||
Name: fmt.Sprintf("意图识别-%s", item.Name),
|
||||
InputSource: item.InputSource, // ✅ 正确赋值
|
||||
FormConfig: item.FormConfig, // ✅ 用户配置
|
||||
ModelConfig: item.ModelConfig, // ✅ 系统配置
|
||||
}
|
||||
finalNodes = append(finalNodes, intentNode)
|
||||
judge2IntentNodeMap[item.Id] = intentNodeID
|
||||
}
|
||||
}
|
||||
|
||||
summaryNodeID := "summary_node"
|
||||
summaryNode := entity.FlowNode{
|
||||
Id: summaryNodeID,
|
||||
NodeCode: node.NodeTypeCustomNode, // 复用自定义节点类型,也可新增专属类型
|
||||
Name: "结果汇总节点",
|
||||
InputSource: []entity.FlowNodeInputSource{}, // 后续自动聚合所有节点输出
|
||||
FormConfig: nil,
|
||||
ModelConfig: node.ModelItem{},
|
||||
}
|
||||
finalNodes = append(finalNodes, summaryNode)
|
||||
|
||||
// 替换节点列表
|
||||
req.FlowContent.Nodes = finalNodes
|
||||
|
||||
// =========================================================================
|
||||
// ✅【第2步】构建执行图
|
||||
// =========================================================================
|
||||
var nodeList []entity.FlowNode
|
||||
var runGraph compose.Runnable[any, any]
|
||||
runGraph, err = BuildGraphFromFlowContent(execCtx, req.FlowContent, judge2IntentNodeMap, summaryNodeID)
|
||||
nodeList, runGraph, err = BuildGraphFromFlowContent(execCtx, req.FlowContent)
|
||||
if err != nil {
|
||||
executionReq := flowDto.UpdateFlowExecutionReq{
|
||||
Id: executionId,
|
||||
@@ -418,7 +381,6 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
||||
}
|
||||
return nil, fmt.Errorf("执行工作流失败: %v", err)
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// ✅【第3步】构建 ConfigMap
|
||||
// =========================================================================
|
||||
@@ -426,15 +388,9 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
||||
for _, cfg := range req.NodeInputParams {
|
||||
configMap[cfg.Id] = cfg
|
||||
}
|
||||
// 自动给意图节点复制配置
|
||||
for judgeID, intentID := range judge2IntentNodeMap {
|
||||
if cfg, ok := configMap[judgeID]; ok {
|
||||
configMap[intentID] = cfg
|
||||
}
|
||||
for _, i := range nodeList {
|
||||
configMap[i.Id] = &i
|
||||
}
|
||||
// 初始化汇总节点配置
|
||||
configMap[summaryNodeID] = &summaryNode
|
||||
|
||||
// =========================================================================
|
||||
// ✅【第4步】构建全局执行入参(现在 schemaMap 是有值的!)
|
||||
// =========================================================================
|
||||
@@ -475,7 +431,7 @@ func (s *flowExecutionService) Execute(ctx context.Context, req *flowDto.Execute
|
||||
}
|
||||
|
||||
// BuildGraphFromFlowContent 根据前端保存的工作流JSON,自动构建执行图
|
||||
func BuildGraphFromFlowContent(ctx context.Context, flowContent *entity.FlowInfo, judge2IntentNodeMap map[string]string, summaryNodeID string) (compose.Runnable[any, any], error) {
|
||||
func BuildGraphFromFlowContent(ctx context.Context, flowContent *entity.FlowInfo) ([]entity.FlowNode, compose.Runnable[any, any], error) {
|
||||
// 注册自定义合并函数:处理 *flowDto.FlowExecutionInput 类型合并
|
||||
// 由于 ConfigMap 是 map 引用类型,所有并行分支修改已经写入共享内存
|
||||
// 直接返回第一个实例即可,所有修改都已经可见
|
||||
@@ -488,9 +444,26 @@ func BuildGraphFromFlowContent(ctx context.Context, flowContent *entity.FlowInfo
|
||||
})
|
||||
|
||||
graph := compose.NewGraph[any, any]()
|
||||
nodeMap := make(map[string]entity.FlowNode)
|
||||
|
||||
var nodeList []entity.FlowNode
|
||||
nodeId := uuid.NewString()
|
||||
originalEndNodes := findEndNodes(flowContent.StartNodeId, flowContent.Edges)
|
||||
for i := range originalEndNodes {
|
||||
sprintf := fmt.Sprintf("%v_%d", nodeId, i)
|
||||
summaryNode := entity.FlowNode{
|
||||
Id: sprintf,
|
||||
NodeCode: node.NodeTypeSystemSum,
|
||||
Name: node.NodeNameSystemSum,
|
||||
InputSource: []entity.FlowNodeInputSource{}, // 后续自动聚合所有节点输出
|
||||
FormConfig: nil,
|
||||
ModelConfig: node.ModelItem{},
|
||||
}
|
||||
nodeList = append(nodeList, summaryNode)
|
||||
flowContent.Nodes = append(flowContent.Nodes, summaryNode)
|
||||
}
|
||||
|
||||
// 注册所有节点
|
||||
nodeMap := make(map[string]entity.FlowNode)
|
||||
for _, item := range flowContent.Nodes {
|
||||
nodeMap[item.Id] = item
|
||||
if item.NodeCode != node.NodeTypeJudge {
|
||||
@@ -498,6 +471,16 @@ func BuildGraphFromFlowContent(ctx context.Context, flowContent *entity.FlowInfo
|
||||
}
|
||||
}
|
||||
|
||||
// 注册所有边
|
||||
if flowContent.StartNodeId != "" {
|
||||
_ = graph.AddEdge(compose.START, flowContent.StartNodeId)
|
||||
}
|
||||
for i, endID := range originalEndNodes {
|
||||
sprintf := fmt.Sprintf("%v_%d", nodeId, i)
|
||||
_ = graph.AddEdge(endID, sprintf)
|
||||
_ = graph.AddEdge(sprintf, compose.END)
|
||||
}
|
||||
|
||||
// 构建边关系
|
||||
upstreamMap := make(map[string][]string)
|
||||
edgeMap := make(map[string][]entity.FlowEdge)
|
||||
@@ -510,15 +493,8 @@ func BuildGraphFromFlowContent(ctx context.Context, flowContent *entity.FlowInfo
|
||||
for fromNodeID, edges := range edgeMap {
|
||||
fromNode := nodeMap[fromNodeID]
|
||||
|
||||
// --------------------------
|
||||
// 判断节点 → 分支处理
|
||||
// --------------------------
|
||||
if fromNode.NodeCode == node.NodeTypeJudge {
|
||||
intentNodeID, ok := judge2IntentNodeMap[fromNodeID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("判断节点[%s]未生成意图节点", fromNodeID)
|
||||
}
|
||||
|
||||
branchMap := make(map[string]bool)
|
||||
for _, e := range edges {
|
||||
branchMap[e.To] = true
|
||||
@@ -553,11 +529,6 @@ func BuildGraphFromFlowContent(ctx context.Context, flowContent *entity.FlowInfo
|
||||
m["branch_id_name_map"] = branchIdNameMap // 传递ID-名称映射
|
||||
currentConfig.Config = m
|
||||
|
||||
// 从意图节点取输出
|
||||
if intentCfg, ok := execInput.ConfigMap[intentNodeID]; ok {
|
||||
currentConfig.OutputResult = intentCfg.OutputResult
|
||||
}
|
||||
|
||||
// 关键修改:构造 NodeExecutionInput 传入 JudgeLambda
|
||||
nodeExecInput := &flowDto.NodeExecutionInput{
|
||||
Config: currentConfig, // 当前判断节点配置
|
||||
@@ -566,34 +537,21 @@ func BuildGraphFromFlowContent(ctx context.Context, flowContent *entity.FlowInfo
|
||||
return JudgeLambda(ctx, nodeExecInput) // 传入 NodeExecutionInput 类型
|
||||
}
|
||||
|
||||
_ = graph.AddBranch(intentNodeID, compose.NewGraphBranch(judgeLambda, branchMap))
|
||||
_ = graph.AddBranch(upstreamMap[fromNodeID][0], compose.NewGraphBranch(judgeLambda, branchMap))
|
||||
continue
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// 普通节点连线
|
||||
// --------------------------
|
||||
for _, e := range edges {
|
||||
toNode := nodeMap[e.To]
|
||||
if toNode.NodeCode == node.NodeTypeJudge {
|
||||
_ = graph.AddEdge(e.From, fmt.Sprintf("intent_%s", toNode.Id))
|
||||
continue
|
||||
}
|
||||
_ = graph.AddEdge(e.From, e.To)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 第四步:处理开始/结束节点 ====================
|
||||
if flowContent.StartNodeId != "" {
|
||||
_ = graph.AddEdge(compose.START, flowContent.StartNodeId)
|
||||
}
|
||||
originalEndNodes := findEndNodes(flowContent.StartNodeId, flowContent.Edges)
|
||||
for _, endID := range originalEndNodes {
|
||||
_ = graph.AddEdge(endID, summaryNodeID)
|
||||
}
|
||||
_ = graph.AddEdge(summaryNodeID, compose.END)
|
||||
|
||||
return graph.Compile(ctx, compose.WithGraphName("auto_build_workflow"), compose.WithNodeTriggerMode(compose.AllPredecessor))
|
||||
compile, err := graph.Compile(ctx, compose.WithGraphName("auto_build_workflow"))
|
||||
return nodeList, compile, err
|
||||
}
|
||||
|
||||
// -------------------------- 节点自动注册器(核心分发) --------------------------
|
||||
@@ -703,13 +661,11 @@ func registerNodeToGraph(graph *compose.Graph[any, any], flowNode entity.FlowNod
|
||||
return execInput, nil
|
||||
}
|
||||
}
|
||||
if nodeID == "summary_node" {
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(SummaryLambda)))
|
||||
return
|
||||
}
|
||||
switch code {
|
||||
case "__start__":
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(StartLambda)))
|
||||
case node.NodeTypeSystemSum:
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(SummaryLambda)))
|
||||
case node.NodeTypeTextModel:
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(TextModelLambda)))
|
||||
case node.NodeTypeImageModel:
|
||||
@@ -722,12 +678,6 @@ func registerNodeToGraph(graph *compose.Graph[any, any], flowNode entity.FlowNod
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(BatchModelLambda)))
|
||||
case node.NodeTypeDataConversionModel:
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(DataConversionLambda)))
|
||||
//case node.NodeTypeSenseOptimizeModel:
|
||||
// _ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(SenseOptimizeModelLambda)))
|
||||
//case node.NodeTypeStoryOptimizeModel:
|
||||
// _ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(StoryOptimizeModelLambda)))
|
||||
//case node.NodeTypeScriptOptimizeModel:
|
||||
// _ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(ScriptOptimizeModelLambda)))
|
||||
case node.NodeTypeCustomNode:
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(CustomLambda)))
|
||||
case node.NodeTypeForm:
|
||||
@@ -737,49 +687,42 @@ func registerNodeToGraph(graph *compose.Graph[any, any], flowNode entity.FlowNod
|
||||
case node.NodeTypeMerge:
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(MergeLambda)))
|
||||
case node.NodeTypeDataMerge:
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(DataMergeLambda)))
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(DataMergeLambda)), compose.WithGraphCompileOptions(compose.WithNodeTriggerMode(compose.AllPredecessor)))
|
||||
case node.NodeTypeHttp:
|
||||
_ = graph.AddLambdaNode(nodeID, compose.InvokableLambda(wrapLambda(HttpLambda)))
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ✅【工具方法】找出所有没有出边的节点 → 作为结束节点连接 END
|
||||
// --------------------------------------------------------------------
|
||||
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}
|
||||
|
||||
// 🚀 只从【开始节点】递归遍历(关键修复)
|
||||
findLeafNodes(startNodeId, nextMap, endNodeSet)
|
||||
for len(queue) > 0 {
|
||||
node := queue[0]
|
||||
queue = queue[1:]
|
||||
|
||||
// 转成数组返回
|
||||
endNodes := make([]string, 0, len(endNodeSet))
|
||||
for id := range endNodeSet {
|
||||
endNodes = append(endNodes, id)
|
||||
}
|
||||
return endNodes
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ✅ 递归:查找以 nodeId 开头的所有叶子节点
|
||||
// --------------------------------------------------------------------
|
||||
func findLeafNodes(nodeId string, nextMap map[string][]string, endNodeSet map[string]struct{}) {
|
||||
nextNodes := nextMap[nodeId]
|
||||
|
||||
// 🚩 没有下一个节点 = 真实结束节点
|
||||
if len(nextNodes) == 0 {
|
||||
endNodeSet[nodeId] = struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
// 递归继续找下一个
|
||||
for _, nextId := range nextNodes {
|
||||
findLeafNodes(nextId, nextMap, endNodeSet)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -41,19 +41,35 @@ func JudgeLambda(ctx context.Context, input any) (string, error) {
|
||||
if !ok {
|
||||
return "", fmt.Errorf("入参类型错误,期望 *flowDto.NodeExecutionInput,实际 %T", input)
|
||||
}
|
||||
//inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
||||
//fmt.Printf("JudgeLambda路由:输入=%s\n", gjson.MustEncode(inputMap))
|
||||
//fmt.Printf("JudgeLambda路由:输出=%s\n", gjson.MustEncode(outputMap))
|
||||
//fmt.Printf("JudgeLambda路由:模型=%s\n", gjson.MustEncode(modelMap))
|
||||
//configMap := gconv.Map(nodeInput.Config.Config)
|
||||
//ids := gconv.Strings(configMap["branch_ids"])
|
||||
//fmt.Printf("JudgeLambda路由:目标节点ID=%s\n", gconv.String(ids))
|
||||
//
|
||||
//m := map[string]bool{
|
||||
// "80000a50-81e1-4c15-adae-aab6c0d781ad": true,
|
||||
// "59a6ffa2-3252-4535-b6ed-d3e49cdf6c55": true,
|
||||
//}
|
||||
//
|
||||
//return m, nil
|
||||
// 1. 直接用你原来的方法(返回两个 map)
|
||||
inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
||||
var outputResult []node.NodeFormField
|
||||
for _, valueAny := range inputMap {
|
||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||
outputResult = append(outputResult, field)
|
||||
}
|
||||
}
|
||||
for _, valueAny := range outputMap {
|
||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||
outputResult = append(outputResult, field)
|
||||
}
|
||||
}
|
||||
outputResult = append(outputResult, inputMap...)
|
||||
outputResult = append(outputResult, outputMap...)
|
||||
//for _, valueAny := range inputMap {
|
||||
// if field, ok := valueAny.(node.NodeFormField); ok {
|
||||
// outputResult = append(outputResult, field)
|
||||
// }
|
||||
//}
|
||||
//for _, valueAny := range outputMap {
|
||||
// if field, ok := valueAny.(node.NodeFormField); ok {
|
||||
// outputResult = append(outputResult, field)
|
||||
// }
|
||||
//}
|
||||
for _, valueAny := range modelMap {
|
||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||
outputResult = append(outputResult, field)
|
||||
@@ -204,6 +220,8 @@ func TextModelLambda(ctx context.Context, input any) (any, error) {
|
||||
return nil, err
|
||||
}
|
||||
nodeInput.Config.OutputResult = outputRes
|
||||
//}
|
||||
|
||||
return nodeInput, nil
|
||||
}
|
||||
|
||||
@@ -281,14 +299,13 @@ func VideoModelLambda(ctx context.Context, input any) (any, error) {
|
||||
Label: fmt.Sprintf("video_oss_url:content:%d", 0),
|
||||
Type: "string",
|
||||
})
|
||||
} else {
|
||||
outputRes = append(outputRes, node.NodeFormField{
|
||||
Field: fmt.Sprintf("concat_video_url:content:%d", 0),
|
||||
Value: urlPrefix + msg.FileURL,
|
||||
Label: fmt.Sprintf("concat_video_url:content:%d", 0),
|
||||
Type: "string",
|
||||
})
|
||||
}
|
||||
outputRes = append(outputRes, node.NodeFormField{
|
||||
Field: fmt.Sprintf("concat_video_url:content:%d", 0),
|
||||
Value: urlPrefix + msg.FileURL,
|
||||
Label: fmt.Sprintf("视频内容:content:%d", 0),
|
||||
Type: "string",
|
||||
})
|
||||
nodeInput.Config.OutputResult = outputRes
|
||||
|
||||
return nodeInput, nil
|
||||
@@ -303,6 +320,64 @@ func HttpLambda(ctx context.Context, input any) (any, error) {
|
||||
outputRes := make([]node.NodeFormField, 0)
|
||||
var err error
|
||||
outputRes, err = HttpNode(ctx, nodeInput)
|
||||
//if nodeInput.Config.Name == "生成视频" {
|
||||
// outputRes, err = HttpNode(ctx, nodeInput)
|
||||
//} else {
|
||||
// a := []map[string]any{
|
||||
// {
|
||||
// "timeline": "0.0-2.1",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/1.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "2.1-4.5",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/2.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "4.5-12.2",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/3.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "12.2-13.6",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/4.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "13.6-17.7",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/5.mp4model-gateway",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "17.7-31.0",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/6.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "31.0-33.2",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/7.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "33.2-37.4",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/8.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "37.4-38.9",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/9.mp4",
|
||||
// },
|
||||
// {
|
||||
// "timeline": "38.9-57.9",
|
||||
// "url": "https://ark-auto-2127201628-cn-beijing-default.tos-cn-beijing.volces.com/%E8%A7%86%E9%A2%91/10.mp4",
|
||||
// },
|
||||
// }
|
||||
// outputRes = append(outputRes, node.NodeFormField{
|
||||
// Field: fmt.Sprintf("segments"),
|
||||
// Value: a,
|
||||
// Label: fmt.Sprintf("segments"),
|
||||
// Type: "string",
|
||||
// })
|
||||
// outputRes = append(outputRes, node.NodeFormField{
|
||||
// Field: fmt.Sprintf("audioUrl"),
|
||||
// Value: "http://116.204.74.41:9000/tenantid-94/2026-06-11/9915351c-55b9-46d8-b783-3815126b.m4a",
|
||||
// Label: fmt.Sprintf("audioUrl"),
|
||||
// Type: "string",
|
||||
// })
|
||||
//}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -437,11 +512,8 @@ func MergeLambda(ctx context.Context, input any) (res any, err error) {
|
||||
// 1. 把所有节点输出拍平成 字段名->内容 的map
|
||||
dataMap := make(map[string]node.NodeFormField)
|
||||
_, outputMap, _ := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
||||
for _, valueAny := range outputMap {
|
||||
field := node.NodeFormField{}
|
||||
if field, ok = valueAny.(node.NodeFormField); ok {
|
||||
dataMap[field.Field] = field
|
||||
}
|
||||
for _, field := range outputMap {
|
||||
dataMap[field.Field] = field
|
||||
}
|
||||
|
||||
// 2. 提取所有文案:text_content_0,1,2...
|
||||
|
||||
@@ -583,7 +583,7 @@ func ImgNode(ctx context.Context, nodeInput *flowDto.NodeExecutionInput, skillNa
|
||||
outputRes = append(outputRes, node.NodeFormField{
|
||||
Field: fmt.Sprintf("img_url:%v:%d", k, i),
|
||||
Value: v,
|
||||
Label: fmt.Sprintf("img_url%v:%d", k, i),
|
||||
Label: fmt.Sprintf("图片内容%v:%d", k, i),
|
||||
Type: "string",
|
||||
})
|
||||
}
|
||||
@@ -674,7 +674,7 @@ func AudioOptimizeNode(ctx context.Context, nodeInput *flowDto.NodeExecutionInpu
|
||||
outputRes = append(outputRes, node.NodeFormField{
|
||||
Field: fmt.Sprintf("audio_url:%v:%d", k, i),
|
||||
Value: v,
|
||||
Label: fmt.Sprintf("audio_url:%v:%d", k, i),
|
||||
Label: fmt.Sprintf("音频内容:%v:%d", k, i),
|
||||
Type: "string",
|
||||
})
|
||||
}
|
||||
@@ -939,23 +939,17 @@ func HttpNode(ctx context.Context, nodeInput *flowDto.NodeExecutionInput) ([]nod
|
||||
func BuildParam(nodeInput *flowDto.NodeExecutionInput) (skillName string, resultFrom []map[string]any, resultUserFrom []map[string]any) {
|
||||
inputMap, outputMap, modelMap := GetNodeContextContent(nodeInput.Global, nodeInput.Config)
|
||||
var outputResult []node.NodeFormField
|
||||
for _, valueAny := range inputMap {
|
||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||
outputResult = append(outputResult, field)
|
||||
}
|
||||
}
|
||||
outputResult = append(outputResult, inputMap...)
|
||||
|
||||
resultUserFrom = []map[string]any{}
|
||||
for _, valueAny := range outputMap {
|
||||
if field, ok := valueAny.(node.NodeFormField); ok {
|
||||
if !strings.Contains(field.Field, "text_url") && !strings.Contains(field.Field, "img_url") {
|
||||
if strings.Contains(field.Field, "text_content") {
|
||||
field.Value = StripHtmlTags(gconv.String(field.Value))
|
||||
}
|
||||
resultUserFrom = append(resultUserFrom, map[string]any{
|
||||
field.Label: field.Value,
|
||||
})
|
||||
for _, field := range outputMap {
|
||||
if !strings.Contains(field.Field, "text_url") && !strings.Contains(field.Field, "img_url") {
|
||||
if strings.Contains(field.Field, "text_content") {
|
||||
field.Value = StripHtmlTags(gconv.String(field.Value))
|
||||
}
|
||||
resultUserFrom = append(resultUserFrom, map[string]any{
|
||||
field.Label: field.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, valueAny := range modelMap {
|
||||
@@ -963,18 +957,13 @@ func BuildParam(nodeInput *flowDto.NodeExecutionInput) (skillName string, result
|
||||
outputResult = append(outputResult, field)
|
||||
}
|
||||
}
|
||||
//if !nodeInput.Global.IsDialogue {
|
||||
for _, item := range outputResult {
|
||||
resultUserFrom = append(resultUserFrom, map[string]any{
|
||||
item.Label: item.Value,
|
||||
})
|
||||
if !nodeInput.Global.IsDialogue {
|
||||
for _, item := range outputResult {
|
||||
resultUserFrom = append(resultUserFrom, map[string]any{
|
||||
item.Label: item.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, item := range nodeInput.Config.FormConfig {
|
||||
resultUserFrom = append(resultUserFrom, map[string]any{
|
||||
item.Label: item.Value,
|
||||
})
|
||||
}
|
||||
//}
|
||||
if !g.IsEmpty(nodeInput.Global.Desc) {
|
||||
resultUserFrom = append(resultUserFrom, map[string]any{
|
||||
"desc": nodeInput.Global.Desc,
|
||||
@@ -998,83 +987,40 @@ func BuildParam(nodeInput *flowDto.NodeExecutionInput) (skillName string, result
|
||||
return skillName, resultFrom, resultUserFrom
|
||||
}
|
||||
|
||||
func GetNodeContextContent(execInput *flowDto.FlowExecutionInput, nodeEntity *entity.FlowNode) (map[string]any, map[string]any, map[string]any) {
|
||||
input := make(map[string]any)
|
||||
output := make(map[string]any)
|
||||
func GetNodeContextContent(execInput *flowDto.FlowExecutionInput, nodeEntity *entity.FlowNode) ([]node.NodeFormField, []node.NodeFormField, map[string]any) {
|
||||
var input []node.NodeFormField
|
||||
var output []node.NodeFormField
|
||||
model := make(map[string]any)
|
||||
// 1. 有引用 → 取引用节点的字段值
|
||||
if len(nodeEntity.InputSource) > 0 {
|
||||
for _, source := range nodeEntity.InputSource {
|
||||
refNodeID := source.NodeId
|
||||
fields := source.Field
|
||||
|
||||
refNode, ok := execInput.ConfigMap[refNodeID]
|
||||
refNode, ok := execInput.ConfigMap[source.NodeId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
inputMap := buildInputMap(refNode)
|
||||
outputMap := mergeOutput(refNode.OutputResult)
|
||||
modelMap := mergeModel(refNode.ModelConfig)
|
||||
if len(fields) > 0 {
|
||||
if len(source.Field) > 0 {
|
||||
// 取指定字段
|
||||
for _, f := range fields {
|
||||
if v, ok := inputMap[f]; ok {
|
||||
input[f] = v
|
||||
}
|
||||
if v, ok := modelMap[f]; ok {
|
||||
model[f] = v
|
||||
}
|
||||
for k, v := range outputMap {
|
||||
if strings.Contains(k, f) {
|
||||
model[k] = v
|
||||
for _, f := range source.Field {
|
||||
for _, v := range refNode.FormConfig {
|
||||
if strings.Contains(v.Label, f) {
|
||||
input = append(input, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 取全部
|
||||
if refNode.NodeCode != node.NodeTypeHttp {
|
||||
for k, v := range inputMap {
|
||||
input[k] = v
|
||||
for _, v := range refNode.ModelConfig.ModelForm {
|
||||
if g.IsEmpty(v.Value) {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(v.Label, f) {
|
||||
model[f] = v
|
||||
}
|
||||
}
|
||||
for _, v := range refNode.OutputResult {
|
||||
if strings.Contains(v.Label, f) {
|
||||
output = append(output, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range modelMap {
|
||||
model[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return input, output, model
|
||||
}
|
||||
|
||||
// buildInputMap 从 FormConfig 构造输入map
|
||||
func buildInputMap(node *entity.FlowNode) map[string]any {
|
||||
m := make(map[string]any)
|
||||
for _, item := range node.FormConfig {
|
||||
m[item.Label] = item
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// mergeOutput 合并节点输出 []map → 单map
|
||||
func mergeOutput(output []node.NodeFormField) map[string]any {
|
||||
m := make(map[string]any)
|
||||
for _, item := range output {
|
||||
m[item.Label] = item
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// mergeOutput 合并节点输出 []map → 单map
|
||||
func mergeModel(output node.ModelItem) map[string]any {
|
||||
m := make(map[string]any)
|
||||
// 遍历 output.ModelForm 里的每一个 key 和原始值
|
||||
for _, rawValue := range output.ModelForm {
|
||||
if g.IsEmpty(rawValue.Value) {
|
||||
continue
|
||||
}
|
||||
// 包装成 { "value": 原始值 }
|
||||
m[rawValue.Label] = rawValue.Value
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user