mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: 工作编排
This commit is contained in:
parent
7bf01df60b
commit
a1ca81341c
|
|
@ -18,4 +18,6 @@ class ContainCompare(Compare):
|
|||
return True
|
||||
|
||||
def compare(self, source_value, compare, target_value):
|
||||
if isinstance(source_value, str):
|
||||
return str(target_value) in source_value
|
||||
return any([str(item) == str(target_value) for item in source_value])
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class IReplyNode(INode):
|
|||
return ReplyNodeParamsSerializer
|
||||
|
||||
def _run(self):
|
||||
return self.execute(**self.flow_params_serializer.data)
|
||||
return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data)
|
||||
|
||||
def execute(self, reply_type, stream, fields=None, content=None, **kwargs) -> NodeResult:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class BaseReplyNode(IReplyNode):
|
|||
else:
|
||||
result = self.generate_reply_content(content)
|
||||
if stream:
|
||||
return NodeResult({'result': iter(AIMessageChunk(content=result))}, {},
|
||||
return NodeResult({'result': iter([AIMessageChunk(content=result)])}, {},
|
||||
_to_response=to_stream_response)
|
||||
else:
|
||||
return NodeResult({'result': AIMessage(content=result)}, {}, _to_response=to_response)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
@date:2024/1/9 17:40
|
||||
@desc:
|
||||
"""
|
||||
import json
|
||||
import uuid
|
||||
from typing import List, Dict
|
||||
|
||||
from langchain_core.prompts import PromptTemplate
|
||||
|
|
@ -172,3 +174,500 @@ class WorkflowManage:
|
|||
def get_node_reference(self, reference_address: Dict):
|
||||
node = self.get_node_by_id(reference_address.get('node_id'))
|
||||
return node.context[reference_address.get('node_field')]
|
||||
|
||||
|
||||
json_str = """
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "base-node",
|
||||
"type": "base-node",
|
||||
"x": 200,
|
||||
"y": 270,
|
||||
"properties": {
|
||||
"height": 200,
|
||||
"stepName": "基本信息",
|
||||
"node_data": {
|
||||
"name": "",
|
||||
"desc": "",
|
||||
"prologue": "您好,我是 MaxKB 小助手,您可以向我提出 MaxKB 使用问题。"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "start-node",
|
||||
"type": "start-node",
|
||||
"x": 140,
|
||||
"y": 800,
|
||||
"properties": {
|
||||
"height": 200,
|
||||
"stepName": "开始",
|
||||
"output": [
|
||||
{
|
||||
"key": ""
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"label": "用户问题",
|
||||
"value": "question"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5",
|
||||
"type": "search-dataset-node",
|
||||
"x": 1490,
|
||||
"y": 580,
|
||||
"properties": {
|
||||
"height": 200,
|
||||
"stepName": "知识库检索",
|
||||
"input": [
|
||||
{
|
||||
"key": "输入"
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"key": "输出"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"label": "检索结果",
|
||||
"value": "data"
|
||||
},
|
||||
{
|
||||
"label": "满足直接回答的分段内容",
|
||||
"value": "paragraph"
|
||||
}
|
||||
],
|
||||
"node_data": {
|
||||
"dataset_id_list": [
|
||||
"e750b5f5-247a-11ef-8fc8-a8a1595801ab",
|
||||
"1e42a226-1bfd-11ef-be5f-a8a1595801ab",
|
||||
"e3b4ad8d-18f2-11ef-9a18-a8a1595801ab",
|
||||
"861d1f5c-18f3-11ef-a40e-a8a1595801ab"
|
||||
],
|
||||
"dataset_setting": {
|
||||
"top_n": 3,
|
||||
"similarity": 0.6,
|
||||
"max_paragraph_char_number": 5000,
|
||||
"search_mode": "embedding"
|
||||
},
|
||||
"question_reference_address": [
|
||||
"start-node",
|
||||
"question"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
|
||||
"type": "condition-node",
|
||||
"x": 1080,
|
||||
"y": 500,
|
||||
"properties": {
|
||||
"height": 200,
|
||||
"width": 600,
|
||||
"stepName": "判断器",
|
||||
"input": [
|
||||
{
|
||||
"key": "输入"
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"key": "9208"
|
||||
},
|
||||
{
|
||||
"key": "1143"
|
||||
},
|
||||
{
|
||||
"key": "输出"
|
||||
}
|
||||
],
|
||||
"node_data": {
|
||||
"branch": [
|
||||
{
|
||||
"conditions": [
|
||||
{
|
||||
"field": [
|
||||
"03597cb0-ed4c-4bcb-b25b-3b358f72b266",
|
||||
"answer"
|
||||
],
|
||||
"compare": "contain",
|
||||
"value": "打招呼"
|
||||
}
|
||||
],
|
||||
"id": "2391",
|
||||
"type": "IF",
|
||||
"condition": "and"
|
||||
},
|
||||
{
|
||||
"conditions": [
|
||||
{
|
||||
"field": [
|
||||
"03597cb0-ed4c-4bcb-b25b-3b358f72b266",
|
||||
"answer"
|
||||
],
|
||||
"compare": "contain",
|
||||
"value": "售前咨询"
|
||||
}
|
||||
],
|
||||
"id": "1143",
|
||||
"type": "IF ELSE 1",
|
||||
"condition": "and"
|
||||
},
|
||||
{
|
||||
"conditions": [
|
||||
|
||||
],
|
||||
"id": "9208",
|
||||
"type": "ELSE",
|
||||
"condition": "and"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
|
||||
"type": "ai-chat-node",
|
||||
"x": 580,
|
||||
"y": 400,
|
||||
"properties": {
|
||||
"height": "",
|
||||
"stepName": "AI 对话",
|
||||
"input": [
|
||||
{
|
||||
"key": "输入"
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"key": "输出"
|
||||
}
|
||||
],
|
||||
"node_data": {
|
||||
"model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab",
|
||||
"system": "你是问题分析大师",
|
||||
"prompt": "请直接返回所属的问题分类,不要说推理过程。用户问题为:{{context['start-node'].question}} 问题分类是:打招呼 售前咨询 售后咨询其他咨询",
|
||||
"dialogue_number": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "6649ee86-348c-4d68-9cad-71f0612beb05",
|
||||
"type": "ai-chat-node",
|
||||
"x": 2030,
|
||||
"y": 500,
|
||||
"properties": {
|
||||
"height": "",
|
||||
"stepName": "AI 对话",
|
||||
"input": [
|
||||
{
|
||||
"key": "输入"
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"key": "输出"
|
||||
}
|
||||
],
|
||||
"node_data": {
|
||||
"model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab",
|
||||
"system": "你是售前咨询工程师",
|
||||
"prompt": "已知信息:{{context['34902d3d-a3ff-497f-b8e1-0c34a44d7dd5'].data}}回答用户问题:{{context['start-node'].question}}",
|
||||
"dialogue_number": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "0004a9c9-e2fa-40ac-9215-2e1ad04f09c5",
|
||||
"type": "ai-chat-node",
|
||||
"x": 1360,
|
||||
"y": 1300,
|
||||
"properties": {
|
||||
"height": "",
|
||||
"stepName": "AI 对话",
|
||||
"input": [
|
||||
{
|
||||
"key": "输入"
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"key": "输出"
|
||||
}
|
||||
],
|
||||
"node_data": {
|
||||
"model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab",
|
||||
"system": "你是售后咨询工程师",
|
||||
"prompt": "{{context['start-node'].question}}",
|
||||
"dialogue_number": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "30c16d31-3881-48cd-991e-da3f99c45681",
|
||||
"type": "reply-node",
|
||||
"x": 1690,
|
||||
"y": 170,
|
||||
"properties": {
|
||||
"height": "",
|
||||
"stepName": "指定回复",
|
||||
"input": [
|
||||
{
|
||||
"key": ""
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"key": ""
|
||||
}
|
||||
],
|
||||
"node_data": {
|
||||
"reply_type": "content",
|
||||
"content": "你好,有什么需要帮助的吗",
|
||||
"fields": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "214aa478-78ce-4c95-89aa-11f821bc65d2",
|
||||
"type": "app-edge",
|
||||
"sourceNodeId": "start-node",
|
||||
"targetNodeId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
|
||||
"startPoint": {
|
||||
"x": 300,
|
||||
"y": 865.3335000000001
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 420,
|
||||
"y": 677
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 300,
|
||||
"y": 865.3335000000001
|
||||
},
|
||||
{
|
||||
"x": 410,
|
||||
"y": 865.3335000000001
|
||||
},
|
||||
{
|
||||
"x": 310,
|
||||
"y": 677
|
||||
},
|
||||
{
|
||||
"x": 420,
|
||||
"y": 677
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "start-node__right",
|
||||
"targetAnchorId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266_输入_left"
|
||||
},
|
||||
{
|
||||
"id": "d56fb64a-4fc0-4779-911b-283a2238ef7b",
|
||||
"type": "app-edge",
|
||||
"sourceNodeId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
|
||||
"targetNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
|
||||
"startPoint": {
|
||||
"x": 740,
|
||||
"y": 672
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 790,
|
||||
"y": 678.6665
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 740,
|
||||
"y": 672
|
||||
},
|
||||
{
|
||||
"x": 850,
|
||||
"y": 672
|
||||
},
|
||||
{
|
||||
"x": 680,
|
||||
"y": 678.6665
|
||||
},
|
||||
{
|
||||
"x": 790,
|
||||
"y": 678.6665
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266_输出_right",
|
||||
"targetAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_输入_left"
|
||||
},
|
||||
{
|
||||
"id": "26fe01d6-8d41-4025-a637-e09f41c9b2c8",
|
||||
"type": "app-edge",
|
||||
"sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
|
||||
"targetNodeId": "30c16d31-3881-48cd-991e-da3f99c45681",
|
||||
"startPoint": {
|
||||
"x": 1370,
|
||||
"y": 673.6665
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1530,
|
||||
"y": 286
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 1370,
|
||||
"y": 673.6665
|
||||
},
|
||||
{
|
||||
"x": 1480,
|
||||
"y": 673.6665
|
||||
},
|
||||
{
|
||||
"x": 1420,
|
||||
"y": 286
|
||||
},
|
||||
{
|
||||
"x": 1530,
|
||||
"y": 286
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_9208_right",
|
||||
"targetAnchorId": "30c16d31-3881-48cd-991e-da3f99c45681__left"
|
||||
},
|
||||
{
|
||||
"id": "5c85d2bb-cb27-44ed-9e05-505f702381f6",
|
||||
"type": "app-edge",
|
||||
"sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
|
||||
"targetNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5",
|
||||
"startPoint": {
|
||||
"x": 1370,
|
||||
"y": 697.6665
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1330,
|
||||
"y": 898.889
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 1370,
|
||||
"y": 697.6665
|
||||
},
|
||||
{
|
||||
"x": 1480,
|
||||
"y": 697.6665
|
||||
},
|
||||
{
|
||||
"x": 1220,
|
||||
"y": 898.889
|
||||
},
|
||||
{
|
||||
"x": 1330,
|
||||
"y": 898.889
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_1143_right",
|
||||
"targetAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输入_left"
|
||||
},
|
||||
{
|
||||
"id": "4d4b5740-910e-48b0-badd-8b9ce10e6e4e",
|
||||
"type": "app-edge",
|
||||
"sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5",
|
||||
"targetNodeId": "6649ee86-348c-4d68-9cad-71f0612beb05",
|
||||
"startPoint": {
|
||||
"x": 1650,
|
||||
"y": 893.889
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1870,
|
||||
"y": 777
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 1650,
|
||||
"y": 893.889
|
||||
},
|
||||
{
|
||||
"x": 1760,
|
||||
"y": 893.889
|
||||
},
|
||||
{
|
||||
"x": 1760,
|
||||
"y": 777
|
||||
},
|
||||
{
|
||||
"x": 1870,
|
||||
"y": 777
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输出_right",
|
||||
"targetAnchorId": "6649ee86-348c-4d68-9cad-71f0612beb05_输入_left"
|
||||
},
|
||||
{
|
||||
"id": "9c446d4d-e500-4867-8d47-ed99f80b9b48",
|
||||
"type": "app-edge",
|
||||
"sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
|
||||
"targetNodeId": "0004a9c9-e2fa-40ac-9215-2e1ad04f09c5",
|
||||
"startPoint": {
|
||||
"x": 1370,
|
||||
"y": 721.6665
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1200,
|
||||
"y": 1577
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 1370,
|
||||
"y": 721.6665
|
||||
},
|
||||
{
|
||||
"x": 1480,
|
||||
"y": 721.6665
|
||||
},
|
||||
{
|
||||
"x": 1090,
|
||||
"y": 1577
|
||||
},
|
||||
{
|
||||
"x": 1200,
|
||||
"y": 1577
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_2391_right",
|
||||
"targetAnchorId": "0004a9c9-e2fa-40ac-9215-2e1ad04f09c5_输入_left"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
f = Flow.new_instance(json.loads(json_str))
|
||||
_id = str(uuid.uuid1())
|
||||
w_manage = WorkflowManage(flow=f,
|
||||
params={"history_chat_record": [], "question": "有企业版吗", "chat_id": _id,
|
||||
"chat_record_id": _id,
|
||||
"stream": True, "client_id": _id, "client_type": "xxxx"})
|
||||
w_manage.run()
|
||||
|
|
|
|||
|
|
@ -25,3 +25,9 @@ def post_handler():
|
|||
|
||||
|
||||
post_handler()
|
||||
|
||||
|
||||
def run():
|
||||
from application.flow.workflow_manage import WorkflowManage
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,20 +8,6 @@
|
|||
</div>
|
||||
<div><slot></slot></div>
|
||||
</div>
|
||||
<!-- <div class="input-container" v-resize="resetInputContainer">
|
||||
<div v-for="(item, index) in nodeModel.properties.input" :key="index" class="step-field">
|
||||
<span>{{ item.key }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-container" v-resize="resetOutputContainer">
|
||||
<div
|
||||
v-for="(item, index) in nodeModel.properties.output"
|
||||
:key="index"
|
||||
class="out-step-field"
|
||||
>
|
||||
<span>{{ item.key }}</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -42,33 +28,7 @@ const height = ref<{
|
|||
const resizeStepContainer = (wh: any) => {
|
||||
if (wh.height) {
|
||||
height.value.stepContainerHeight = wh.height
|
||||
props.nodeModel.setHeight(
|
||||
height.value.stepContainerHeight,
|
||||
height.value.inputContainerHeight,
|
||||
height.value.outputContainerHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const resetOutputContainer = (wh: { height: number; width: number }) => {
|
||||
if (wh.height) {
|
||||
height.value.outputContainerHeight = wh.height
|
||||
props.nodeModel.setHeight(
|
||||
height.value.stepContainerHeight,
|
||||
height.value.inputContainerHeight,
|
||||
height.value.outputContainerHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const resetInputContainer = (wh: { height: number; width: number }) => {
|
||||
if (wh.height) {
|
||||
height.value.inputContainerHeight = wh.height
|
||||
props.nodeModel.setHeight(
|
||||
height.value.stepContainerHeight,
|
||||
height.value.inputContainerHeight,
|
||||
height.value.outputContainerHeight
|
||||
)
|
||||
props.nodeModel.setHeight(height.value.stepContainerHeight)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,24 +47,6 @@ class AppNode extends HtmlNode {
|
|||
}
|
||||
|
||||
class AppNodeModel extends HtmlNodeModel {
|
||||
/**
|
||||
* 给model自定义添加字段方法
|
||||
*/
|
||||
addField(item: any) {
|
||||
this.properties.output.unshift(item)
|
||||
this.setAttributes()
|
||||
// 为了保持节点顶部位置不变,在节点变化后,对节点进行一个位移,位移距离为添加高度的一半。
|
||||
this.move(0, 24 / 2)
|
||||
// 更新节点连接边的path
|
||||
this.incoming.edges.forEach((edge: any) => {
|
||||
// 调用自定义的更新方案
|
||||
edge.updatePathByAnchor()
|
||||
})
|
||||
this.outgoing.edges.forEach((edge: any) => {
|
||||
// 调用自定义的更新方案
|
||||
edge.updatePathByAnchor()
|
||||
})
|
||||
}
|
||||
getOutlineStyle() {
|
||||
const style = super.getOutlineStyle()
|
||||
style.stroke = 'none'
|
||||
|
|
@ -87,12 +69,8 @@ class AppNodeModel extends HtmlNodeModel {
|
|||
return style
|
||||
}
|
||||
|
||||
setHeight(height: number, inputContainerHeight: number, outputContainerHeight: number) {
|
||||
this.height = height + inputContainerHeight + outputContainerHeight + 100
|
||||
this.baseHeight = height
|
||||
this.inputContainerHeight = inputContainerHeight
|
||||
this.outputContainerHeight = outputContainerHeight
|
||||
|
||||
setHeight(height: number) {
|
||||
this.height = height + 100
|
||||
this.outgoing.edges.forEach((edge: any) => {
|
||||
// 调用自定义的更新方案
|
||||
edge.updatePathByAnchor()
|
||||
|
|
@ -104,7 +82,6 @@ class AppNodeModel extends HtmlNodeModel {
|
|||
}
|
||||
setAttributes() {
|
||||
this.width = this.properties?.width || 340
|
||||
|
||||
const circleOnlyAsTarget = {
|
||||
message: '只允许从右边的锚点连出',
|
||||
validate: (sourceNode: any, targetNode: any, sourceAnchor: any) => {
|
||||
|
|
@ -120,50 +97,21 @@ class AppNodeModel extends HtmlNodeModel {
|
|||
})
|
||||
}
|
||||
getDefaultAnchor() {
|
||||
const {
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
properties: { input, output }
|
||||
} = this
|
||||
|
||||
if (this.baseHeight === undefined) {
|
||||
this.baseHeight = 0
|
||||
}
|
||||
if (this.inputContainerHeight === undefined) {
|
||||
this.inputContainerHeight = 0
|
||||
}
|
||||
if (this.height === undefined) {
|
||||
this.height = 200
|
||||
}
|
||||
if (this.outputContainerHeight === undefined) {
|
||||
this.outputContainerHeight = 0
|
||||
}
|
||||
|
||||
const { id, x, y, width } = this
|
||||
const anchors: any = []
|
||||
if (input) {
|
||||
input.forEach((field: any, index: any) => {
|
||||
anchors.push({
|
||||
x: x - width / 2 + 10,
|
||||
y: y - height / 2 + this.baseHeight + 35 + index * 24,
|
||||
id: `${id}_${field.key}_left`,
|
||||
edgeAddable: false,
|
||||
type: 'left'
|
||||
})
|
||||
})
|
||||
}
|
||||
if (output) {
|
||||
output.forEach((field: any, index: any) => {
|
||||
anchors.push({
|
||||
x: x + width / 2 - 10,
|
||||
y: y - height / 2 + this.baseHeight + this.inputContainerHeight + 30 + index * 24,
|
||||
id: `${id}_${field.key}_right`,
|
||||
type: 'right'
|
||||
})
|
||||
})
|
||||
}
|
||||
anchors.push({
|
||||
x: x - width / 2 + 10,
|
||||
y: y,
|
||||
id: `${id}`,
|
||||
edgeAddable: false,
|
||||
type: 'left'
|
||||
})
|
||||
anchors.push({
|
||||
x: x + width / 2 - 10,
|
||||
y: y,
|
||||
id: `${id}`,
|
||||
type: 'right'
|
||||
})
|
||||
|
||||
return anchors
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ class CustomEdge2 extends BezierEdge {}
|
|||
|
||||
class CustomEdgeModel2 extends BezierEdgeModel {
|
||||
getArrowStyle() {
|
||||
return { offset: 0 }
|
||||
const arrowStyle = super.getArrowStyle()
|
||||
arrowStyle.offset = 1
|
||||
arrowStyle.verticalLength = 0
|
||||
return arrowStyle
|
||||
}
|
||||
|
||||
getEdgeStyle() {
|
||||
|
|
@ -13,6 +16,7 @@ class CustomEdgeModel2 extends BezierEdgeModel {
|
|||
// svg属性
|
||||
style.strokeWidth = 2
|
||||
style.stroke = '#BBBFC4'
|
||||
style.offset = 0
|
||||
return style
|
||||
}
|
||||
/**
|
||||
|
|
@ -50,6 +54,7 @@ class CustomEdgeModel2 extends BezierEdgeModel {
|
|||
x: targetAnchor.x,
|
||||
y: targetAnchor.y
|
||||
}
|
||||
|
||||
this.updateEndPoint(endPoint)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,34 +61,13 @@ const graphData = {
|
|||
type: 'condition-node',
|
||||
x: 810,
|
||||
y: 760,
|
||||
|
||||
properties: {
|
||||
height: 200,
|
||||
width: 600,
|
||||
stepName: '判断器',
|
||||
input: [{ key: '输入' }],
|
||||
output: [{ key: '9208' }, { key: '1143' }, { key: '输出' }],
|
||||
node_data: {
|
||||
branch: [
|
||||
{
|
||||
conditions: [{ field: [], compare: '', value: '' }],
|
||||
id: '2391',
|
||||
type: 'IF',
|
||||
condition: 'and'
|
||||
},
|
||||
{
|
||||
conditions: [{ field: [], compare: '', value: '' }],
|
||||
id: '1143',
|
||||
type: 'IF ELSE 1',
|
||||
condition: 'and'
|
||||
},
|
||||
{
|
||||
conditions: [{ field: [], compare: '', value: '' }],
|
||||
id: '9208',
|
||||
type: 'ELSE',
|
||||
condition: 'and'
|
||||
}
|
||||
]
|
||||
}
|
||||
output: [{ key: '9208' }, { key: '1143' }, { key: '输出' }]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -118,8 +97,6 @@ const graphData = {
|
|||
properties: {
|
||||
height: '',
|
||||
stepName: 'AI 对话',
|
||||
input: [{ key: '输入' }],
|
||||
output: [{ key: '输出' }],
|
||||
node_data: {
|
||||
model_id: '',
|
||||
system: '',
|
||||
|
|
@ -137,8 +114,6 @@ const graphData = {
|
|||
properties: {
|
||||
height: '',
|
||||
stepName: 'AI 对话',
|
||||
input: [{ key: '输入' }],
|
||||
output: [{ key: '输出' }],
|
||||
node_data: {
|
||||
model_id: '',
|
||||
system: '',
|
||||
|
|
@ -161,93 +136,7 @@ const graphData = {
|
|||
}
|
||||
}
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
id: '8dde4baf-0965-4999-9d37-f867ab16d638',
|
||||
type: 'app-edge',
|
||||
sourceNodeId: 'start-node',
|
||||
targetNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5',
|
||||
startPoint: { x: 340, y: 788 },
|
||||
endPoint: { x: 440, y: 469 },
|
||||
properties: {},
|
||||
pointsList: [
|
||||
{ x: 340, y: 788 },
|
||||
{ x: 450, y: 788 },
|
||||
{ x: 330, y: 469 },
|
||||
{ x: 440, y: 469 }
|
||||
],
|
||||
sourceAnchorId: 'start-node_输出_right',
|
||||
targetAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输入_left'
|
||||
},
|
||||
{
|
||||
id: 'b60de7b4-d8d2-4e7d-bba6-3738b9e523b9',
|
||||
type: 'app-edge',
|
||||
sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5',
|
||||
targetNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
|
||||
startPoint: { x: 760, y: 503 },
|
||||
endPoint: { x: 520, y: 931.0625 },
|
||||
properties: {},
|
||||
pointsList: [
|
||||
{ x: 760, y: 503 },
|
||||
{ x: 870, y: 503 },
|
||||
{ x: 410, y: 931.0625 },
|
||||
{ x: 520, y: 931.0625 }
|
||||
],
|
||||
sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输出_right',
|
||||
targetAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_输入_left'
|
||||
},
|
||||
{
|
||||
id: '8de0da85-b5d6-459a-8be9-4d00082baf1c',
|
||||
type: 'app-edge',
|
||||
sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
|
||||
targetNodeId: '03597cb0-ed4c-4bcb-b25b-3b358f72b266',
|
||||
startPoint: { x: 1100, y: 926.0625 },
|
||||
endPoint: { x: 1170, y: 969 },
|
||||
properties: {},
|
||||
pointsList: [
|
||||
{ x: 1100, y: 926.0625 },
|
||||
{ x: 1210, y: 926.0625 },
|
||||
{ x: 1060, y: 969 },
|
||||
{ x: 1170, y: 969 }
|
||||
],
|
||||
sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_9208_right',
|
||||
targetAnchorId: '03597cb0-ed4c-4bcb-b25b-3b358f72b266_输入_left'
|
||||
},
|
||||
{
|
||||
id: '3e66821a-ce0a-4ef9-a6cf-ea4095158261',
|
||||
type: 'app-edge',
|
||||
sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
|
||||
targetNodeId: '6649ee86-348c-4d68-9cad-71f0612beb05',
|
||||
startPoint: { x: 1100, y: 950.0625 },
|
||||
endPoint: { x: 1160, y: 1269 },
|
||||
properties: {},
|
||||
pointsList: [
|
||||
{ x: 1100, y: 950.0625 },
|
||||
{ x: 1210, y: 950.0625 },
|
||||
{ x: 1050, y: 1269 },
|
||||
{ x: 1160, y: 1269 }
|
||||
],
|
||||
sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_1143_right',
|
||||
targetAnchorId: '6649ee86-348c-4d68-9cad-71f0612beb05_输入_left'
|
||||
},
|
||||
{
|
||||
id: 'cc52ab90-58e7-4f54-9660-d9fb16f776ea',
|
||||
type: 'app-edge',
|
||||
sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
|
||||
targetNodeId: '0004a9c9-e2fa-40ac-9215-2e1ad04f09c5',
|
||||
startPoint: { x: 1100, y: 1016.75 },
|
||||
endPoint: { x: 1200, y: 1413 },
|
||||
properties: {},
|
||||
pointsList: [
|
||||
{ x: 1100, y: 974.0625 },
|
||||
{ x: 1210, y: 974.0625 },
|
||||
{ x: 1090, y: 1579 },
|
||||
{ x: 1200, y: 1579 }
|
||||
],
|
||||
sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_输出_right',
|
||||
targetAnchorId: '0004a9c9-e2fa-40ac-9215-2e1ad04f09c5_输入_left'
|
||||
}
|
||||
]
|
||||
edges: []
|
||||
}
|
||||
const lf = ref()
|
||||
|
||||
|
|
@ -318,6 +207,11 @@ onMounted(() => {
|
|||
lf.value.setDefaultEdgeType('app-edge')
|
||||
|
||||
lf.value.render(graphData)
|
||||
lf.value.graphModel.eventCenter.on('delete_edge', (id_list: Array<string>) => {
|
||||
id_list.forEach((id: string) => {
|
||||
lf.value.deleteEdge(id)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
const validate = () => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,69 @@
|
|||
import ConditioNodeVue from './index.vue'
|
||||
import { cloneDeep, set } from 'lodash'
|
||||
import { AppNode, AppNodeModel } from '@/workflow/common/app-node'
|
||||
class ConditioNode extends AppNode {
|
||||
constructor(props: any) {
|
||||
super(props, ConditioNodeVue)
|
||||
}
|
||||
}
|
||||
const get_up_index_height = (condition_list: Array<any>, index: number) => {
|
||||
return condition_list
|
||||
.filter((item, i) => i < index)
|
||||
.map((item) => item.height + 8)
|
||||
.reduce((x, y) => x + y, 0)
|
||||
}
|
||||
class ConditionModel extends AppNodeModel {
|
||||
refreshBranch() {
|
||||
// 为了保持节点顶部位置不变,在节点变化后,对节点进行一个位移,位移距离为添加高度的一半。
|
||||
this.move(0, 24 / 2)
|
||||
// 更新节点连接边的path
|
||||
this.incoming.edges.forEach((edge: any) => {
|
||||
// 调用自定义的更新方案
|
||||
edge.updatePathByAnchor()
|
||||
})
|
||||
this.outgoing.edges.forEach((edge: any) => {
|
||||
edge.updatePathByAnchor()
|
||||
})
|
||||
}
|
||||
getDefaultAnchor() {
|
||||
const {
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
properties: { barnch_condition_list }
|
||||
} = this
|
||||
if (this.height === undefined) {
|
||||
this.height = 200
|
||||
}
|
||||
const anchors: any = []
|
||||
anchors.push({
|
||||
x: x - width / 2 + 10,
|
||||
y: y,
|
||||
id: `${id}`,
|
||||
edgeAddable: false,
|
||||
type: 'left'
|
||||
})
|
||||
|
||||
if (barnch_condition_list) {
|
||||
for (let index = 0; index < barnch_condition_list.length; index++) {
|
||||
const element = barnch_condition_list[index]
|
||||
const h = get_up_index_height(barnch_condition_list, index)
|
||||
anchors.push({
|
||||
x: x + width / 2 - 10,
|
||||
y: y - height / 2 + 75 + h + element.height / 2,
|
||||
id: `${id}_${element.id}_right`,
|
||||
type: 'right'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return anchors
|
||||
}
|
||||
}
|
||||
export default {
|
||||
type: 'condition-node',
|
||||
model: AppNodeModel,
|
||||
model: ConditionModel,
|
||||
view: ConditioNode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,13 @@
|
|||
@mousedown.stop
|
||||
@mousemove.stop
|
||||
>
|
||||
<template v-for="(item, index) in form_data.branch" :key="index">
|
||||
<el-card shadow="never" class="card-never mb-8" style="--el-card-padding: 12px">
|
||||
<template v-for="(item, index) in form_data.branch" :key="item.id">
|
||||
<el-card
|
||||
v-resize="(wh) => resizeCondition(wh, item, index)"
|
||||
shadow="never"
|
||||
class="card-never mb-8"
|
||||
style="--el-card-padding: 12px"
|
||||
>
|
||||
<div class="flex-between lighter">
|
||||
{{ item.type }}
|
||||
<div class="info" v-if="item.conditions.length > 1">
|
||||
|
|
@ -110,9 +115,10 @@ import { cloneDeep, set } from 'lodash'
|
|||
import NodeContainer from '@/workflow/common/NodeContainer.vue'
|
||||
import NodeCascader from '@/workflow/common/NodeCascader.vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted, nextTick } from 'vue'
|
||||
import { randomId } from '@/utils/utils'
|
||||
import { compareList } from '@/workflow/common/data'
|
||||
|
||||
const props = defineProps<{ nodeModel: any }>()
|
||||
const form = {
|
||||
branch: [
|
||||
|
|
@ -137,12 +143,28 @@ const form = {
|
|||
]
|
||||
}
|
||||
|
||||
const resizeCondition = (wh: any, row: any, index: number) => {
|
||||
const barnch_condition_list = cloneDeep(
|
||||
props.nodeModel.properties.barnch_condition_list
|
||||
? props.nodeModel.properties.barnch_condition_list
|
||||
: []
|
||||
)
|
||||
const new_barnch_condition_list = barnch_condition_list.map((item: any) => {
|
||||
if (item.id === row.id) {
|
||||
return { ...item, height: wh.height, index: index }
|
||||
}
|
||||
return item
|
||||
})
|
||||
set(props.nodeModel.properties, 'barnch_condition_list', new_barnch_condition_list)
|
||||
refreshBranchAnchor(props.nodeModel.properties.node_data.branch, true)
|
||||
}
|
||||
const form_data = computed({
|
||||
get: () => {
|
||||
if (props.nodeModel.properties.node_data) {
|
||||
return props.nodeModel.properties.node_data
|
||||
} else {
|
||||
set(props.nodeModel.properties, 'node_data', form)
|
||||
refreshBranchAnchor(form.branch, true)
|
||||
}
|
||||
return props.nodeModel.properties.node_data
|
||||
},
|
||||
|
|
@ -157,16 +179,6 @@ const validate = () => {
|
|||
ConditionNodeFormRef.value?.validate()
|
||||
}
|
||||
|
||||
// const judgeLabel = (index: number) => {
|
||||
// if (index === 0) {
|
||||
// return 'IF'
|
||||
// } else if (index === form_data.value.branch.length - 1) {
|
||||
// return 'ELSE'
|
||||
// } else {
|
||||
// return 'ELSE IF ' + index
|
||||
// }
|
||||
// }
|
||||
|
||||
function addBranch() {
|
||||
const list = cloneDeep(props.nodeModel.properties.node_data.branch)
|
||||
const obj = {
|
||||
|
|
@ -182,9 +194,31 @@ function addBranch() {
|
|||
condition: 'and'
|
||||
}
|
||||
list.splice(list.length - 1, 0, obj)
|
||||
props.nodeModel.addField({ key: obj.id })
|
||||
refreshBranchAnchor(list, true)
|
||||
set(props.nodeModel.properties.node_data, 'branch', list)
|
||||
}
|
||||
function refreshBranchAnchor(list: Array<any>, is_add: boolean) {
|
||||
const barnch_condition_list = cloneDeep(
|
||||
props.nodeModel.properties.barnch_condition_list
|
||||
? props.nodeModel.properties.barnch_condition_list
|
||||
: []
|
||||
)
|
||||
const new_barnch_condition_list = list
|
||||
.map((item, index) => {
|
||||
const find = barnch_condition_list.find((b) => b.id === item.id)
|
||||
if (find) {
|
||||
return { index: index, height: find.height, id: item.id }
|
||||
} else {
|
||||
if (is_add) {
|
||||
return { index: index, height: 12, id: item.id }
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter((item) => item)
|
||||
|
||||
set(props.nodeModel.properties, 'barnch_condition_list', new_barnch_condition_list)
|
||||
props.nodeModel.refreshBranch()
|
||||
}
|
||||
|
||||
function addCondition(index: number) {
|
||||
const list = cloneDeep(props.nodeModel.properties.node_data.branch)
|
||||
|
|
@ -200,7 +234,18 @@ function deleteCondition(index: number, cIndex: number) {
|
|||
const list = cloneDeep(props.nodeModel.properties.node_data.branch)
|
||||
list[index]['conditions'].splice(cIndex, 1)
|
||||
if (list[index]['conditions'].length === 0) {
|
||||
list.splice(index, 1)
|
||||
const delete_edge = list.splice(index, 1)
|
||||
const delete_target_anchor_id_list = delete_edge.map(
|
||||
(item) => props.nodeModel.id + '_' + item.id + '_right'
|
||||
)
|
||||
|
||||
props.nodeModel.graphModel.eventCenter.emit(
|
||||
'delete_edge',
|
||||
props.nodeModel.outgoing.edges
|
||||
.filter((item) => delete_target_anchor_id_list.includes(item.sourceAnchorId))
|
||||
.map((item) => item.id)
|
||||
)
|
||||
refreshBranchAnchor(list, false)
|
||||
}
|
||||
set(props.nodeModel.properties.node_data, 'branch', list)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue