125 lines
3.6 KiB
TypeScript
125 lines
3.6 KiB
TypeScript
import {has, isEmpty} from 'licia'
|
|
import type {JSX} from 'react'
|
|
import {getAllIncomerNodeOutputVariables} from './Helper.tsx'
|
|
import CodeNode from './node/CodeNode.tsx'
|
|
import KnowledgeNode from './node/KnowledgeNode.tsx'
|
|
import LlmNode from './node/LlmNode.tsx'
|
|
import OutputNode from './node/OutputNode.tsx'
|
|
import SwitchNode from './node/SwitchNode.tsx'
|
|
import TemplateNode from './node/TemplateNode.tsx'
|
|
import type {NodeChecker} from './types.ts'
|
|
|
|
const inputSingleVariableChecker: (field: string) => NodeChecker = field => {
|
|
return (id, inputSchema, nodes, edges, data) => {
|
|
let nodeData = data[id] ?? {}
|
|
if (has(nodeData, field)) {
|
|
let expression = nodeData?.[field] ?? ''
|
|
if (!isEmpty(expression)) {
|
|
let outputVariables = new Set([
|
|
...getAllIncomerNodeOutputVariables(id, nodes, edges, data).map(i => `${i.id}.${i.variable}`),
|
|
...Object.keys(inputSchema),
|
|
])
|
|
if (!outputVariables.has(expression)) {
|
|
return {
|
|
error: true,
|
|
message: `节点 ${id} 存在错误:变量 ${expression} 不存在`,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return {error: false}
|
|
}
|
|
}
|
|
|
|
const inputMultiVariableChecker: NodeChecker = (id, inputSchema, nodes, edges, data) => {
|
|
let nodeData = data[id] ?? {}
|
|
if (has(nodeData, 'inputs')) {
|
|
let inputs = nodeData?.inputs ?? {}
|
|
if (!isEmpty(inputs)) {
|
|
let outputVariables = new Set([
|
|
...getAllIncomerNodeOutputVariables(id, nodes, edges, data).map(i => `${i.id}.${i.variable}`),
|
|
...Object.keys(inputSchema),
|
|
])
|
|
for (const key of Object.keys(inputs)) {
|
|
let variable = inputs[key]?.variable ?? ''
|
|
if (!outputVariables.has(variable)) {
|
|
return {
|
|
error: true,
|
|
message: `节点 ${id} 存在错误:变量 ${variable} 不存在`,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return {error: false}
|
|
}
|
|
|
|
type NodeDefine = {
|
|
key: string,
|
|
group: string,
|
|
name: string,
|
|
icon: JSX.Element,
|
|
description: string,
|
|
component: any,
|
|
checkers: NodeChecker[],
|
|
}
|
|
|
|
export const NodeRegistry: NodeDefine[] = [
|
|
{
|
|
key: 'llm-node',
|
|
group: '普通节点',
|
|
name: '大模型',
|
|
icon: <i className="fa fa-message"/>,
|
|
description: '使用大模型对话',
|
|
component: LlmNode,
|
|
checkers: [inputMultiVariableChecker],
|
|
},
|
|
{
|
|
key: 'knowledge-node',
|
|
group: '普通节点',
|
|
name: '知识库',
|
|
icon: <i className="fa fa-book-bookmark"/>,
|
|
description: '',
|
|
component: KnowledgeNode,
|
|
checkers: [inputMultiVariableChecker],
|
|
},
|
|
{
|
|
key: 'code-node',
|
|
group: '普通节点',
|
|
name: '代码执行',
|
|
icon: <i className="fa fa-code"/>,
|
|
description: '执行自定义的处理代码',
|
|
component: CodeNode,
|
|
checkers: [inputMultiVariableChecker],
|
|
},
|
|
{
|
|
key: 'template-node',
|
|
group: '普通节点',
|
|
name: '模板替换',
|
|
icon: <i className="fa fa-pen-nib"/>,
|
|
description: '使用模板聚合转换变量表示',
|
|
component: TemplateNode,
|
|
checkers: [inputMultiVariableChecker],
|
|
},
|
|
{
|
|
key: 'switch-node',
|
|
group: '逻辑节点',
|
|
name: '分支',
|
|
icon: <i className="fa fa-code-fork"/>,
|
|
description: '根据不同的情况前往不同的分支',
|
|
component: SwitchNode,
|
|
checkers: [],
|
|
},
|
|
{
|
|
key: 'output-node',
|
|
group: '输出节点',
|
|
name: '输出',
|
|
icon: <i className="fa fa-file"/>,
|
|
description: '定义输出变量',
|
|
component: OutputNode,
|
|
checkers: [inputSingleVariableChecker('output')],
|
|
},
|
|
]
|
|
|
|
export const NodeRegistryMap: Record<string, NodeDefine> = NodeRegistry.reduce((a, v) => ({...a, [v.key]: v}), {})
|