- 新增同会话+同工作流最近执行失败且参数一致时断点续跑逻辑 - exec_workflow/exec_chat 新增 error 字段存储原始错误,error_message 仅存友好提示 - 新增 UpdateExecChatReq 与 exec_chat_dao Update 方法 - 新增 GetLatestBySessionAndFlow 查询最近执行记录 - 修正 ListDates 分组与排序 SQL 表达式 - 新增 pipeline 配置结构,删除旧设计文档
494 lines
13 KiB
Go
494 lines
13 KiB
Go
package node
|
|
|
|
// NodeGroup 节点分组标识
|
|
type NodeGroup string
|
|
|
|
// NodeType 节点类型标识
|
|
type NodeType string
|
|
|
|
// 分组常量定义
|
|
const (
|
|
NodeGroupBase NodeGroup = "base"
|
|
NodeGroupSystem NodeGroup = "system"
|
|
)
|
|
|
|
// 节点类型常量定义
|
|
const (
|
|
NodeTypeStart NodeType = "__start__"
|
|
NodeTypeModel NodeType = "model"
|
|
NodeTypeDataMerge NodeType = "data_merge"
|
|
NodeTypeForm NodeType = "form"
|
|
NodeTypeSubFlow NodeType = "sub_flow"
|
|
NodeTypeHttp NodeType = "http"
|
|
NodeTypeSystemSum NodeType = "system_sum"
|
|
NodeTypeScriptTranscribe NodeType = "script_transcribe"
|
|
)
|
|
|
|
// NodeGroupMeta 节点分组元数据
|
|
type NodeGroupMeta struct {
|
|
Key NodeGroup `json:"key"` // 后端存储标识
|
|
Name string `json:"name"` // 前端展示中文名称
|
|
}
|
|
|
|
// NodeTypeMeta 节点元数据
|
|
type NodeTypeMeta struct {
|
|
Key NodeType `json:"key"` // 节点类型标识
|
|
Name string `json:"name"` // 节点中文名称
|
|
Group NodeGroup `json:"group"` // 所属分组
|
|
Sort int `json:"sort"` // UI排序字段
|
|
Desc string `json:"desc,omitempty"` // 可选:节点简介
|
|
PatchLayout bool `json:"patchLayout"`
|
|
IsMultiParameter bool `json:"isMultiParameter"`
|
|
BatchExecOption bool `json:"batchExecOption"`
|
|
PreToolOption []NodePresetField `json:"preToolOption"`
|
|
PostToolOption []NodePresetField `json:"postToolOption"`
|
|
IsSaveFileOption bool `json:"isSaveFileOption"`
|
|
FormConfigOption bool `json:"formConfigOption"`
|
|
ModelConfigOption bool `json:"modelConfigOption"`
|
|
SkillOption bool `json:"skillOption"`
|
|
PromptOption bool `json:"promptOption"`
|
|
NegativePromptOption bool `json:"negativePromptOption"`
|
|
PresetOption []NodePresetField `json:"presetOption"`
|
|
OutputField []NodeOutputField `json:"outputField"`
|
|
}
|
|
|
|
type NodeOutputField struct {
|
|
Field string `json:"field"`
|
|
Label string `json:"label"`
|
|
}
|
|
|
|
type NodePresetField struct {
|
|
Value string `json:"value"`
|
|
ValueSource []ValueSource `json:"valueSource"`
|
|
Field string `json:"field"`
|
|
Label string `json:"label"`
|
|
Type string `json:"type"`
|
|
IsFormField bool `json:"isFormField"`
|
|
Constraint FieldConstraint `json:"constraint"`
|
|
Required bool `json:"required"`
|
|
Options []SelectOption `json:"options"`
|
|
}
|
|
|
|
type ValueSource struct {
|
|
NodeId string `json:"nodeId"`
|
|
Field string `json:"field"`
|
|
Label string `json:"label"`
|
|
}
|
|
|
|
// FieldConstraint 字段约束
|
|
type FieldConstraint struct {
|
|
// 数字类型:int、float、double、string
|
|
Type string `json:"type" dc:"类型"`
|
|
Min any `json:"min" dc:"最小值"`
|
|
Max any `json:"max" dc:"最大值"`
|
|
}
|
|
|
|
type SelectOption struct {
|
|
Key string `json:"key"`
|
|
Value string `json:"value"`
|
|
Config []NodePresetField `json:"config"`
|
|
}
|
|
|
|
// NodeGroupTree 对外输出树形结构:分组 + 分组下所有节点
|
|
type NodeGroupTree struct {
|
|
Group NodeGroupMeta `json:"group"`
|
|
Nodes []NodeTypeMeta `json:"nodes"`
|
|
}
|
|
|
|
// ===================== 元数据集中注册区(英文标识+中文文案统一维护) =====================
|
|
var NodeGroupMetaList = []NodeGroupMeta{
|
|
{
|
|
Key: NodeGroupBase,
|
|
Name: "基础",
|
|
},
|
|
}
|
|
|
|
var NodeTypeMetaList = []NodeTypeMeta{
|
|
{
|
|
Key: NodeTypeModel,
|
|
Name: "模型",
|
|
Group: NodeGroupBase,
|
|
Sort: 1,
|
|
Desc: "模型调用节点,可配置模型参数、模型配置、技能、提示语、结果汇集、结果保存、结果返回、结果展示等信息。",
|
|
PatchLayout: true,
|
|
IsMultiParameter: true,
|
|
BatchExecOption: true,
|
|
PreToolOption: []NodePresetField{
|
|
{
|
|
Field: "perTool",
|
|
Label: "前置方法",
|
|
Type: "select",
|
|
Required: false,
|
|
Options: []SelectOption{},
|
|
},
|
|
},
|
|
PostToolOption: []NodePresetField{
|
|
{
|
|
Field: "postTool",
|
|
Label: "后置方法",
|
|
Type: "select",
|
|
Required: false,
|
|
Options: []SelectOption{},
|
|
},
|
|
},
|
|
IsSaveFileOption: true,
|
|
FormConfigOption: false,
|
|
ModelConfigOption: true,
|
|
SkillOption: false,
|
|
PromptOption: true,
|
|
NegativePromptOption: false,
|
|
},
|
|
{
|
|
Key: NodeTypeDataMerge,
|
|
Name: "结果汇集",
|
|
Group: NodeGroupBase,
|
|
Sort: 2,
|
|
Desc: "结果汇集节点,可配置结果汇集方式、结果保存、结果返回、结果展示等信息。",
|
|
IsMultiParameter: false,
|
|
BatchExecOption: false,
|
|
IsSaveFileOption: false,
|
|
FormConfigOption: false,
|
|
ModelConfigOption: false,
|
|
SkillOption: false,
|
|
PromptOption: false,
|
|
NegativePromptOption: false,
|
|
},
|
|
{
|
|
Key: NodeTypeForm,
|
|
Name: "表单",
|
|
Group: NodeGroupBase,
|
|
Sort: 3,
|
|
Desc: "表单节点,可配置表单字段、表单配置、结果汇集、结果保存、结果返回、结果展示等信息。",
|
|
IsMultiParameter: false,
|
|
BatchExecOption: false,
|
|
IsSaveFileOption: false,
|
|
FormConfigOption: true,
|
|
ModelConfigOption: false,
|
|
SkillOption: false,
|
|
PromptOption: false,
|
|
NegativePromptOption: false,
|
|
},
|
|
{
|
|
Key: NodeTypeSubFlow,
|
|
Name: "子流程",
|
|
Group: NodeGroupBase,
|
|
Sort: 4,
|
|
PresetOption: []NodePresetField{
|
|
{
|
|
Field: "maxConcurrency",
|
|
Label: "生成次数",
|
|
Type: "input",
|
|
Value: "1",
|
|
IsFormField: true,
|
|
Constraint: FieldConstraint{
|
|
Type: "int",
|
|
Min: 1,
|
|
Max: 10,
|
|
},
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Key: NodeTypeHttp,
|
|
Name: "HTTP(S)接口",
|
|
Group: NodeGroupBase,
|
|
Sort: 5,
|
|
Desc: "HTTP(S)接口节点,可配置HTTP(S)接口地址、请求方式、请求头、请求体、结果返回结构、结果返回方式、结果返回结构、结果返回方式等信息。",
|
|
BatchExecOption: false,
|
|
IsSaveFileOption: true,
|
|
FormConfigOption: false,
|
|
ModelConfigOption: false,
|
|
SkillOption: false,
|
|
PromptOption: false,
|
|
NegativePromptOption: false,
|
|
PresetOption: []NodePresetField{
|
|
{
|
|
Field: "method",
|
|
Label: "请求方式",
|
|
Type: "select",
|
|
Required: true,
|
|
Options: []SelectOption{
|
|
{Key: "GET", Value: "GET"},
|
|
{Key: "POST", Value: "POST"},
|
|
},
|
|
},
|
|
{
|
|
Field: "url",
|
|
Label: "请求地址",
|
|
Type: "input",
|
|
Constraint: FieldConstraint{
|
|
Type: "string",
|
|
Min: 1,
|
|
Max: -1,
|
|
},
|
|
Required: true,
|
|
},
|
|
{
|
|
Field: "headers",
|
|
Label: "请求头(支持Authorization鉴权)",
|
|
Type: "keyValue",
|
|
Required: false,
|
|
},
|
|
{
|
|
Field: "bodyType",
|
|
Label: "请求体类型",
|
|
Type: "select",
|
|
Required: true,
|
|
Options: []SelectOption{
|
|
{Key: "None", Value: "无"},
|
|
{Key: "JSON", Value: "JSON"},
|
|
},
|
|
},
|
|
{
|
|
Field: "body",
|
|
Label: "请求体内容",
|
|
Type: "schemaJson",
|
|
Required: false,
|
|
},
|
|
{
|
|
Field: "response",
|
|
Label: "结果返回结构",
|
|
Type: "schemaJson",
|
|
Required: true,
|
|
},
|
|
{
|
|
Field: "responseType",
|
|
Label: "结果返回方式",
|
|
Type: "select",
|
|
Required: true,
|
|
Options: []SelectOption{
|
|
{Key: "sync", Value: "同步返回"},
|
|
{Key: "callback", Value: "等候回调", Config: []NodePresetField{
|
|
{
|
|
Field: "callbackUrl",
|
|
Label: "回调地址(只需要填写字段名称)",
|
|
Type: "input",
|
|
Constraint: FieldConstraint{
|
|
Type: "string",
|
|
Min: 1,
|
|
Max: -1,
|
|
},
|
|
Required: true,
|
|
},
|
|
}},
|
|
{Key: "pull", Value: "主动拉取", Config: []NodePresetField{
|
|
{
|
|
Field: "method",
|
|
Label: "请求方式",
|
|
Type: "select",
|
|
Required: true,
|
|
Options: []SelectOption{
|
|
{Key: "GET", Value: "GET"},
|
|
{Key: "POST", Value: "POST"},
|
|
},
|
|
},
|
|
{
|
|
Field: "url",
|
|
Label: "请求地址",
|
|
Type: "input",
|
|
Constraint: FieldConstraint{
|
|
Type: "string",
|
|
Min: 1,
|
|
Max: -1,
|
|
},
|
|
Required: true,
|
|
},
|
|
{
|
|
Field: "headers",
|
|
Label: "请求头(支持Authorization鉴权)",
|
|
Type: "keyValue",
|
|
Required: false,
|
|
},
|
|
{
|
|
Field: "bodyType",
|
|
Label: "请求体类型",
|
|
Type: "select",
|
|
Required: true,
|
|
Options: []SelectOption{
|
|
{Key: "None", Value: "无"},
|
|
{Key: "JSON", Value: "JSON"},
|
|
},
|
|
},
|
|
{
|
|
Field: "body",
|
|
Label: "请求体内容",
|
|
Type: "schemaJson",
|
|
Required: true,
|
|
},
|
|
{
|
|
Field: "response",
|
|
Label: "结果返回结构",
|
|
Type: "schemaJson",
|
|
Required: true,
|
|
},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Key: NodeTypeScriptTranscribe,
|
|
Name: "脚本转写",
|
|
Group: NodeGroupBase,
|
|
Sort: 6,
|
|
Desc: "脚本转写节点,把文案/视频分析结果通过大模型转写为结构化分镜脚本([]Shot),作为视频生成节点的 shots 输入。",
|
|
IsMultiParameter: false,
|
|
BatchExecOption: false,
|
|
IsSaveFileOption: false,
|
|
FormConfigOption: false,
|
|
ModelConfigOption: true,
|
|
SkillOption: false,
|
|
PromptOption: false,
|
|
NegativePromptOption: false,
|
|
PresetOption: []NodePresetField{
|
|
{
|
|
Field: "totalDuration",
|
|
Label: "视频总时长",
|
|
Type: "input",
|
|
Constraint: FieldConstraint{
|
|
Type: "int",
|
|
Min: 1,
|
|
Max: 300,
|
|
},
|
|
Required: true,
|
|
},
|
|
{
|
|
Field: "modelId",
|
|
Label: "视频模型",
|
|
Type: "select",
|
|
Required: true,
|
|
Options: []SelectOption{},
|
|
},
|
|
},
|
|
OutputField: []NodeOutputField{
|
|
{
|
|
Field: "prompt",
|
|
Label: "转写内容",
|
|
},
|
|
{
|
|
Field: "duration",
|
|
Label: "时长",
|
|
},
|
|
{
|
|
Field: "seed",
|
|
Label: "种子",
|
|
},
|
|
{
|
|
Field: "reference_urls",
|
|
Label: "参考链接",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Key: NodeTypeSystemSum,
|
|
Name: "工作流内置节点-保存结果",
|
|
Group: NodeGroupSystem,
|
|
Sort: 7,
|
|
},
|
|
}
|
|
|
|
// ===================== 缓存map & 工具函数 =====================
|
|
var (
|
|
nodeTypeMetaMap map[NodeType]NodeTypeMeta
|
|
nodeGroupMap map[NodeGroup]NodeGroupMeta
|
|
)
|
|
|
|
func init() {
|
|
// 初始化分组缓存
|
|
nodeGroupMap = make(map[NodeGroup]NodeGroupMeta, len(NodeGroupMetaList))
|
|
for _, meta := range NodeGroupMetaList {
|
|
nodeGroupMap[meta.Key] = meta
|
|
}
|
|
|
|
// 初始化节点缓存
|
|
nodeTypeMetaMap = make(map[NodeType]NodeTypeMeta, len(NodeTypeMetaList))
|
|
for _, meta := range NodeTypeMetaList {
|
|
nodeTypeMetaMap[meta.Key] = meta
|
|
}
|
|
}
|
|
|
|
// GetNodeTypeMeta 根据节点类型获取元信息
|
|
func GetNodeTypeMeta(typ NodeType) (NodeTypeMeta, bool) {
|
|
meta, ok := nodeTypeMetaMap[typ]
|
|
return meta, ok
|
|
}
|
|
|
|
// GetNodeTypeName 快速获取节点中文名称,不存在返回原始key
|
|
func GetNodeTypeName(typ NodeType) string {
|
|
meta, ok := nodeTypeMetaMap[typ]
|
|
if !ok {
|
|
return string(typ)
|
|
}
|
|
return meta.Name
|
|
}
|
|
|
|
// GetNodeGroupMeta 根据分组标识获取分组元信息
|
|
func GetNodeGroupMeta(g NodeGroup) (NodeGroupMeta, bool) {
|
|
meta, ok := nodeGroupMap[g]
|
|
return meta, ok
|
|
}
|
|
|
|
// GetNodeGroupName 快速获取分组中文名称
|
|
func GetNodeGroupName(g NodeGroup) string {
|
|
meta, ok := nodeGroupMap[g]
|
|
if !ok {
|
|
return string(g)
|
|
}
|
|
return meta.Name
|
|
}
|
|
|
|
// GetAllNodeTypeMeta 返回全部节点元数据副本
|
|
func GetAllNodeTypeMeta() []NodeTypeMeta {
|
|
list := make([]NodeTypeMeta, len(NodeTypeMetaList))
|
|
copy(list, NodeTypeMetaList)
|
|
return list
|
|
}
|
|
|
|
// GetNodeGroupTree 获取【分组+节点】树形列表,完整所有节点
|
|
func GetNodeGroupTree() []NodeGroupTree {
|
|
return getFilteredNodeTree(nil)
|
|
}
|
|
|
|
// GetFilterNodeTree 根据指定分组过滤节点树形结构
|
|
// groups: 需要展示的分组key列表,传入nil返回全部
|
|
func GetFilterNodeTree(groups []NodeGroup) []NodeGroupTree {
|
|
return getFilteredNodeTree(groups)
|
|
}
|
|
|
|
// getFilteredNodeTree 内部通用树形构建逻辑
|
|
func getFilteredNodeTree(filterGroups []NodeGroup) []NodeGroupTree {
|
|
// 构建分组过滤集合
|
|
filterSet := make(map[NodeGroup]bool)
|
|
for _, g := range filterGroups {
|
|
filterSet[g] = true
|
|
}
|
|
|
|
groupNodeMap := make(map[NodeGroup][]NodeTypeMeta)
|
|
for _, node := range NodeTypeMetaList {
|
|
// 有过滤条件 && 当前分组不在过滤列表,则跳过
|
|
if len(filterSet) > 0 && !filterSet[node.Group] {
|
|
continue
|
|
}
|
|
groupNodeMap[node.Group] = append(groupNodeMap[node.Group], node)
|
|
}
|
|
|
|
var tree []NodeGroupTree
|
|
// 按定义顺序组装分组
|
|
for _, gMeta := range NodeGroupMetaList {
|
|
// 如果开启过滤,跳过不在筛选列表中的分组
|
|
if len(filterSet) > 0 && !filterSet[gMeta.Key] {
|
|
continue
|
|
}
|
|
nodes := groupNodeMap[gMeta.Key]
|
|
if len(nodes) == 0 {
|
|
continue
|
|
}
|
|
tree = append(tree, NodeGroupTree{
|
|
Group: gMeta,
|
|
Nodes: nodes,
|
|
})
|
|
}
|
|
return tree
|
|
}
|