UNPKG

jbxl-workflow

Version:

流程图

589 lines (582 loc) 25 kB
import {Node} from '@antv/x6' import { register } from '@antv/x6-vue-shape'; import StartNodeComponent from "@/components/StartNode.vue"; import EndNodeComponent from "@/components/EndNode.vue"; import InputParamsList from "@/components/InputParams.vue"; import OutputParamsList from '@/components/OutputParams.vue' import LLMNodeComponent from "@/components/LLMNode.vue"; import PluginNodeComponent from '@/components/PluginNode.vue' import ParameterNodeComponent from '@/components/ParameterNode.vue' import ParameterExtractWrap from '@/components/ParameterExtractWrap.vue' import {BasicInputParamsList, NodeParamItem, StartNodeParamsList, PluginNodeInputParamsList, ParameterNodeInputParamsList} from "@/ParamsList.class"; import {deepClone} from "@/utils/common"; import {generateRandomId} from "@dang_8899/xl-ui" import {BasicPorts} from "@/Port.class"; import ModelSelect from "@/components/ModelSelect.vue"; import CurlyBracesTextarea from "@/components/CurlyBracesTextarea.vue"; import {ref} from "vue"; /** * @class 基础节点 * @param title {string} 标题 * @param description {string} 描述 * @param ports {Array<Port>} 节点 * @param paramsList {Array<NodeParamItem>} 输入参数列表 * @param 节点类型(根据节点类型生成不同的节点类) * @param x: number; 节点x坐标 * @param y: number; 节点y坐标 * @param width: number; 节点宽度 * @param height: number; 节点高度 * @param nodeStartColor: string; 节点开始颜色 * @param nodeEndColor: string; 节点结束颜色 * */ class BasicNode extends Node{ _chunks = [] // 循环渲染的区块 _ports = [] // 端口 constructor(obj) { super(obj); this.whiteList = ['x', 'y', 'width', 'height', 'title', 'description', 'modelList', 'allIsOpen', 'options','nextList', 'currentModel', 'portsData', '_prevList', '_prevNode', 'paramsData', 'outputParamsData', 'outputType', 'temperatureValue', 'maxTokensValue', 'currRoadInstruction', 'currRoadInstructionRichText', 'systemPrompt', 'systemPromptRichText', 'pluginId', 'chatType', 'courtUuidList', 'list', 'basicDataList']; const {title, description, ports, type, shapeType, x, y, width, height, allIsOpen, options, modelList, id} = obj || {} // this.$shape = shape || 'html' // 到时需要改写 this.id = id || `${generateRandomId()}${shapeType}`; this.nodeId = '' // 从 this.type = type; this.runDebugStatus = '' // success running error this.title = title; this.modelList = modelList this.validateRes = false this.vueInstance = null; this.x = x; this.y = y; this.width = width; this.height = height; this.description = description; this.shapeType = shapeType; // this.shape = shapeType; this.paramsData = null this.outputParamsData = null this.allIsOpen = allIsOpen; this.nextList = []; // 下一个节点列表 this.portsData = null; // 当前节点的端口列表,从Port.vue的args传来,用于获取 this.setData(obj, options) this._prevList = []; //上游节点列表; this._prevNode = null; //上一个节点 // 输入参数里面的参数值的列表,用于渲染参数输入框 this.paramValList = [{ value: 2 , label: '引用' }, {value: 1 , label: '输入'}] } setChunks (chunks) { this._chunks = chunks; } getChunks () { return deepClone(this._chunks); } getData() { const portsData = this.getPortsList(); const paramsData = this.paramsData?.getList() && typeof this.paramsData?.getList === 'function' ? this.paramsData.getList() : null; const outputParamsData = this.outputParamsData?.getList && typeof this.outputParamsData.getList === 'function' ? this.outputParamsData.getList() : null; return { portsData: portsData ? structuredClone(portsData) : null, paramsData: paramsData ? structuredClone(paramsData) : null, outputParamsData: outputParamsData ? structuredClone(outputParamsData) : null, } } // 设置数据,用于更新节点信息 // 设置数据,用于更新节点信息 setData (data, options = {overwrite: true }) { if (!data) return this; // 先处理白名单内的属性 const superData = {}; for (let key in data) { if (this.whiteList.includes(key)) { // 直接赋值给当前实例 this[key] = data[key]; } // 所有属性都添加到要传给父类的数据中 // superData[key] = data[key]; } // 只调用一次父类的 setData super.setData(superData, options); return this; } setPortsList (ports) { this._ports = deepClone(ports); } getPortsList() { return deepClone(this._ports); } // 初始化 create () { throw new Error("节点类create方法必须实现"); } // 获取graph.addNode需要的参数 getGraphPureParams (obj) { const {title, description, ports, type, shapeType, x, y, width, height, allIsOpen, options} = this; // return {} return { data: { self: obj || this, title, description, ports, type, shapeType, x, y, width, height, allIsOpen, options }, shape: shapeType, // type: this.type, x, y } } // 设置下一个节点 async setNext (downStreamNode) { if (Array.isArray(this.nextList) && this.nextList.every(item => item.id !== downStreamNode.id)) { this.nextList.push(downStreamNode); } } removeNextNode(downStreamNodeId) { if (Array.isArray(this.nextList)) { const index = this.nextList.findIndex(item => item.id === downStreamNodeId) this.nextList.splice(index, 1) } } async setPrev (upStreamNode) { if (Array.isArray(this._prevList)) { this._prevList = [...this._prevList || [], ...upStreamNode]; } else { this._prevList = [...this._prevList || [], upStreamNode]; } } // 校验逻辑 async validate () { if (this.vueInstance) { const {validate} = this.vueInstance.exposed || {}; if (typeof validate === 'function') { return await validate(); } } } // 调试执行逻辑 async runDebug (obj) { if (this.vueInstance) { const {runDebug} = this.vueInstance.exposed || {}; if (typeof runDebug === 'function') { return await runDebug(obj); } } } // 显示结果 async showResult (show) { if (this.vueInstance) { const {showResult} = this.vueInstance.exposed || {}; if (typeof showResult === 'function') { return await showResult(show); } } } // 设置运行结果状态,时间,输出参数,输入参数 /** * @param status {string} 状态,时间,输出参数,输入参数 * * @param type {string} 类型,默认为status, 其他状态为 time、 output、 input * */ async setRunResultStatus (status, type = 'status') { if (this.vueInstance) { const {setRunResultStatus, setTime, setOutputParams, setInputParams} = this.vueInstance.exposed || {}; // 设置运行结果状态 if (typeof setRunResultStatus === 'function' && type === 'status') { return await setRunResultStatus(status); } // 设置运行结果时间 if (typeof setTime === 'function' && type === 'time') { return await setTime(status); } // 设置运行结果输出参数 if (typeof setOutputParams === 'function' && type === 'output') { return await setOutputParams(status); } // 设置运行结果输入参数 if (typeof setInputParams === 'function' && type === 'input') { return await setInputParams(status); } } } // async setRunResultParams (params) { // if (this.vueInstance) { // const {setRunResultParams} = this.vueInstance.exposed || {}; // if (typeof setRunResultParams === 'function') { // return await setRunResultParams(params); // } // } // } next () { this.validate().then(res => { if (res) { this.nextList.forEach(node => node.validate()); } }) } } /** * @params paramsDataList {Array<NodeParamItem>} 输入参数列表 * * */ class StartNode extends BasicNode { constructor({title, description, ports, type, shape, x, y, width, height, shapeType, id, allIsOpen, nodeId, paramsDataList}) { super({title, description, ports, type, shape, x, y, width, height, shapeType: shapeType || 'start-node-shape', id, allIsOpen, nodeId, paramsDataList}); this.paramsDataList = paramsDataList this.initParamsList() this.create() } add () { this.paramsData.add() } getParamsData () { return this.paramsData.getList() } getOutputParamsData () { return this.outputParamsData.getList() } initParamsList () { this.paramsData = new StartNodeParamsList(); console.log('this.paramsDataList', this.paramsDataList) this.paramsData.init({showInputParamType: true, showInputParamVal: false, showDesc: true, paramsDataList: this.paramsDataList || []}) } // 注册节点 create() { // 生成开始节点port const startNodePorts = new BasicPorts({type: 'startNode', dx: 560}) // 赋值开始节点port列表 this.setPortsList(startNodePorts.getPortsList()) // 把port赋值给当前节点 const options = { shape: 'start-node-shape', width: this.width, height: this.height, component: StartNodeComponent, data: { paramsData: this.paramsData, }, ports: { // 获取port列表,并合并到ports中 ...this.getPortsList(), } // component: ProgressNode, } register(options); } } /** * modelList 大模型列表 * @class 大模型列表 大部分属性通常 * @param currentModel {string} 当前模型 * @param modelList {string} 模型列表 * @param maxTokensValue {number} 最大token值 * @param temperatureValue {number} 温度值 * @param systemPrompt {string} 系统提示词 * @param currRoadInstruction {string} 本轮指令 * @param chunks {array} chunks列表 * @param paramsDataList {Array<NodeParamItem>} 传入的list * @param showSystemPrompt {boolean} 是否显示系统提示词 * @param outputParamsDataList {Array<NodeParamItem>} 输出参数列表 * @param systemPromptRichText {string} 系统提示词富文本 * @param currRoadInstructionRichText {string} 本轮指令富文本 * */ class LLMNode extends BasicNode { constructor({title, description, ports, type, shape, x, y, width, height, shapeType, id, currentModel, paramsDataList, outputParamsDataList, systemPrompt, systemPromptRichText, currRoadInstructionRichText, currRoadInstruction, maxTokensValue, temperatureValue, showSystemPrompt}) { super({title, description, ports, type, shape, x, y, width, height, shapeType: shapeType || 'llm-node-shape', id, currentModel, paramsDataList, outputParamsDataList}); this.paramsData = new BasicInputParamsList(); // 初始化输入参数列表 this.paramsData.init({showInputParamType: false, showInputParamVal: true, paramsDataList}) // 输出参数 this.outputParamsData = new BasicInputParamsList(); // 初始化输出参数列表 // 初始化输出参数列表 const outputParamsItem = new NodeParamItem({name: 'context', paramTypeVal: this.outputParamsData.inputParamTypeList[0].value, showDesc: true, description: '模型输出结果', showRequired: false, showInputParamVal: false, disabled: true, isDefault: true, type: 'output'}) this.outputParamsData.init({showInputParamVal: false, showInputParamType: true, showDesc: true, paramsItem: outputParamsItem, paramsDataList: outputParamsDataList}) // this.initChunks() this.currentModel = currentModel || '' // 当前模型 this.temperatureValue = temperatureValue || 1.0 // 温度值 this.maxTokensValue = maxTokensValue || 512 this.modelType = '' // 默认的大语言模型类型 this.systemPrompt = systemPrompt || '' // 系统提示词 this.currRoadInstruction = currRoadInstruction || '' // 本轮指令 this.systemPromptRichText = systemPromptRichText || '' // 系统提示词富文本 this.currRoadInstructionRichText = currRoadInstructionRichText || '' // 本轮指令富文本 this.showSystemPrompt = typeof showSystemPrompt === 'boolean' ? showSystemPrompt : false // 是否显示系统提示词 this.create() } // 获取默认的chunks getDefaultChunks ({modelList, currentModel = '', }) { return [ { title: '模型', isOpen: true, component: ModelSelect, options: modelList || this.modelList, id: generateRandomId(), currentModel: this.currentModel || currentModel, key: 'model' }, { title: '输入参数', isOpen: true, component: InputParamsList, paramsData: this.paramsData, currentModel: '', id: generateRandomId() }, /** * modelValue放置已经处理好的字符串,inputValue放置原始字符串,modelValue是处理后的html标签 * */ { title: '系统提示词', isOpen: this.showSystemPrompt, id: generateRandomId(), component: CurlyBracesTextarea, hasParams: true, paramsData: this.paramsData, inputValue: this.systemPromptRichText, modelValue: this.systemPrompt, key: 'systemPrompt', show: this.showSystemPrompt }, { title: '本轮指令', isOpen: true, id: generateRandomId(), component: CurlyBracesTextarea, hasParams: true, paramsData: this.paramsData, inputValue: this.currRoadInstructionRichText, modelValue: this.currRoadInstruction, key: 'currRoadInstruction', show: true }, { title: '输出参数', isOpen: true, id: generateRandomId(), component: InputParamsList, paramsData: this.outputParamsData, type: 'output' } ] } changeChunks () { const type = this.modelList?.find(item => item.value === this.currentModel)?.type this.modelType = type if (type === 'image') { const chunks = this.getDefaultChunks({currentModel : this.currentModel}) const list = chunks.filter(item => item.key !== 'systemPrompt') this.setChunks(list) } else { this.setChunks(this.getDefaultChunks({currentModel : this.currentModel})) } } // 初始化chunks, 在LLMNode.vue生成 initChunks ({modelList} = {}) { // this.setModelList(modelList) this.setChunks(this.getDefaultChunks({modelList})) } create () { const startNodePorts = new BasicPorts({dx: 546}) // 赋值开始节点port列表 this.setPortsList(startNodePorts.getPortsList()) register({ shape: 'llm-node-shape', width: this.width, height: this.height, component: LLMNodeComponent, data: { paramsData: this.paramsData, modelList: this.modelList, outputParamsData: this.outputParamsData, currentModel: this.currentModel, systemPrompt: this.systemPrompt, currRoadInstruction: this.currRoadInstruction, }, ports: { // 获取port列表,并合并到ports中 ...this.getPortsList(), } // component: ProgressNode, }); } } // 插件节点 class PluginNode extends BasicNode { constructor(opts) { opts = Object.assign({ shapeType: 'plugin-node-shape' }, opts) super(opts) this.pluginId = opts.pluginId || '' this.nextList = [] this.paramsData = new PluginNodeInputParamsList() this.outputParamsData = new BasicInputParamsList() this.paramsDataList = opts.paramsDataList || [] this.outputParamsDataList = opts.outputParamsDataList || [] if (opts.pluginId) { this.initChunks({ inputParamsList: this.paramsDataList.map(item => { return { ...item, value: item.paramVal === 1 || item.id ? item.value : '' } }), outputParamsList: this.outputParamsDataList }) } this.create() } create() { const basicPorts = new BasicPorts({ dx: 546 }) this.setPortsList(basicPorts.getPortsList()) register({ shape: 'plugin-node-shape', width: this.width, height: this.height, ports: { // 获取port列表,并合并到 ports 中 ...this.getPortsList(), }, component: PluginNodeComponent }) } initChunks({ inputParamsList, outputParamsList }) { this.paramsData.list = inputParamsList?.map(item => { return new NodeParamItem({ ...item }) }) this.outputParamsData.list = this.getOutputParamsDataList(outputParamsList) this.setChunks([ { id: generateRandomId(), title: '输入参数', isOpen: true, collapsePaddingTop: 12, paramsData: this.paramsData, component: InputParamsList }, { id: generateRandomId(), title: '输出参数', isOpen: true, collapsePaddingTop: 8, paramsData: this.outputParamsData, component: OutputParamsList } ]) } getOutputParamsDataList(outputParamsList) { return outputParamsList?.map(item => { return new NodeParamItem({ ...item, children: item.children?.length ? this.getOutputParamsDataList(item.children) : [] }) }) } } // 参数提取节点 class ParameterNode extends BasicNode { constructor(opts) { opts = Object.assign({ shapeType: 'parameter-node-shape' }, opts) super(opts) this.nextList = [] this.paramsData = new ParameterNodeInputParamsList(opts) this.outputParamsData = new BasicInputParamsList() this.paramsDataList = opts.paramsDataList || [] this.outputParamsDataList = opts.outputParamsDataList || [] if (this.paramsDataList?.length || this.outputParamsDataList?.length) { this.setInputParamsDataValue(this.paramsDataList[0].id ? this.paramsDataList[0].value : '') this.addParameterExtractItem(this.outputParamsDataList) } this.create() } create() { const basicPorts = new BasicPorts({ dx: 546 }) this.setPortsList(basicPorts.getPortsList()) register({ shape: 'parameter-node-shape', width: this.width, height: this.height, ports: { // 获取port列表,并合并到 ports 中 ...this.getPortsList(), }, component: ParameterNodeComponent }) } initChunks() { this.setChunks([ { id: generateRandomId(), type: 'input', title: '输入参数', isOpen: true, collapsePaddingTop: 12, paramsData: this.paramsData, component: InputParamsList }, { id: generateRandomId(), type: 'extract', title: '提取参数', isOpen: true, collapsePaddingTop: 8, paramsData: this.outputParamsData, component: ParameterExtractWrap } ]) } setInputParamsDataValue(value) { this.paramsData.list[0].value = value } addParameterExtractItem(paramList) { const paramDataList = [] const paramNameList = this.outputParamsData.list.map(item => item.name) paramList?.forEach(param => { let paramName = param.name if (paramNameList.includes(paramName)) { const defaultParamName = paramName let num = 1 while (paramNameList.includes(paramName)) { // 通过在参数名后面加上下划线和累加的数字来处理相同的参数名,直到不重复为止 paramName = `${defaultParamName}_${num++}` } } paramDataList.push(new NodeParamItem({ ...param, name: paramName })) paramNameList.push(paramName) }) this.outputParamsData.list = paramDataList.concat(this.outputParamsData.list) } editParameterExtractItem(param) { const index = this.outputParamsData.list.findIndex(item => item.id === param.id) if (index > -1) { Object.assign(this.outputParamsData.list[index], param) } } deleteParameterExtractItem(param) { const index = this.outputParamsData.list.findIndex(item => item.id === param.id) if (index > -1) { this.outputParamsData.list.splice(index, 1) } } } /** * @param paramsDataList {Array<NodeParamItem>} 传入的list * @param basicDataList {Array<NodeParamItem>} 基础数据list,再运行提交的时候,会把基础数据list和outputParamsDataList合并 * */ class EndNode extends BasicNode { constructor({title, description, ports, type, shape, x, y, width, height, shapeType, id, allIsOpen, nodeId, outputParamsDataList, outputType, chatType, courtUuidList, basicDataList}) { super({title, description, ports, type, shape, x, y, width, height, shapeType: shapeType || 'start-node-shape', id, allIsOpen, nodeId, outputParamsDataList}); this.outputParamsDataList = outputParamsDataList this.outputType = outputType || 3 // 输出类型,0: 输出api参数列表;1:普通报表 2: 物业报表 3:输出接口 // this.nextList = [] // TODO: 目前先写死courtUuidList this.courtUuidList = courtUuidList?.[0] || [] // 选择所属小区 this.basicDataList = basicDataList || [] // 基础数据列表 this.chatType = chatType || 0 // 聊天类型 this.initParamsFunc({outputParamsDataList: outputParamsDataList || []}) // 默认是加载输出api参数 this.create() } // 初始化参数 initParamsFunc ({outputParamsDataList = []}) { const outputParamsData = new BasicInputParamsList(); // 初始化输出参数列表 const outputParamsItem = new NodeParamItem({name: '', showDesc: false, showRequired: false, showInputParamVal: true, isDefault: false, type: 'output', tableHeaderTitle: ''}) outputParamsData.init({paramsItem: outputParamsItem, showDesc: false, showInputParamVal: true, showInputParamType: false, showTableHeaderTitle: this.outputType !== 3, nameFormItemWidth: 100, paramsDataList: outputParamsDataList}) this.setData({outputParamsData}) } create () { // 生成结束节点port const endNodePorts = new BasicPorts({type: 'endNode'}) this.setPortsList(endNodePorts.getPortsList()) const options = { shape: 'end-node-shape', width: this.width, height: this.height, component: EndNodeComponent, data: { paramsData: this.paramsData, outputParamsData: this.outputParamsData, showTableHeaderTitle: false }, ports: { // 获取port列表,并合并到ports中 ...this.getPortsList(), } // component: ProgressNode, } register(options); } } export {StartNode, EndNode, LLMNode, PluginNode, ParameterNode}