Skip to content

Commit 44445b3

Browse files
committed
feat: Optimize application workflow publish validation
1 parent fe2a3cd commit 44445b3

5 files changed

Lines changed: 60 additions & 17 deletions

File tree

‎apps/application/serializers/application.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
import requests
2323
import uuid_utils.compat as uuid
24-
from application.workflow.common import new_instance
24+
from application.workflow.common import new_instance, WorkflowType
2525
from application.long_term_memory import schedule_extract_long_term_memory
2626
from application.models.application import Application, ApplicationFolder, ApplicationTypeChoices, ApplicationVersion
2727
from application.models.application_access_token import ApplicationAccessToken
@@ -1278,7 +1278,7 @@ def publish(self, instance, with_valid=True):
12781278
work_flow = application.work_flow
12791279
if work_flow is None:
12801280
raise AppApiException(500, _("work_flow is a required field"))
1281-
new_instance(work_flow).is_valid()
1281+
new_instance(work_flow).is_valid(workflow_type=WorkflowType.APPLICATION)
12821282
base_node = get_base_node_work_flow(work_flow)
12831283
if base_node is not None:
12841284
node_data = base_node.get("properties").get("node_data")

‎apps/application/workflow/common.py‎

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from enum import Enum
1111
from typing import List, Dict
1212

13+
from django.utils.translation import gettext as _
14+
from common.exception.app_exception import AppApiException
1315
from common.utils.common import group_by
1416

1517

@@ -106,6 +108,15 @@ def reset_variable(self, prompt: str):
106108
return prompt
107109

108110

111+
class WorkflowType(Enum):
112+
# 应用
113+
APPLICATION = "APPLICATION"
114+
# 知识库
115+
KNOWLEDGE = "KNOWLEDGE"
116+
# 工具
117+
TOOL = "TOOL"
118+
119+
109120
class Workflow:
110121
"""
111122
节点列表
@@ -194,17 +205,39 @@ def reset_prompt(self, prompt):
194205
prompt = node_field.reset_variable(prompt)
195206
return prompt
196207

197-
def is_valid(self):
198-
pass
199-
208+
def is_valid(self, workflow_type: WorkflowType):
209+
"""
210+
校验工作流数据:一趟遍历同时统计节点id出现次数、校验每个节点的参数
211+
"""
212+
start_node_list = []
213+
for node in self.nodes:
214+
if node.id == "start-node":
215+
start_node_list.append(node)
216+
self.is_valid_node(node, workflow_type)
217+
self.is_valid_start_node(start_node_list)
218+
219+
def is_valid_start_node(self, start_node_list: List[Node]):
220+
"""
221+
校验开始节点:有且只有一个 start-node
222+
"""
223+
if len(start_node_list) == 0:
224+
raise AppApiException(500, _("The starting node is required"))
225+
if len(start_node_list) > 1:
226+
raise AppApiException(500, _("There can only be one starting node"))
200227

201-
class WorkflowType(Enum):
202-
# 应用
203-
APPLICATION = "APPLICATION"
204-
# 知识库
205-
KNOWLEDGE = "KNOWLEDGE"
206-
# 工具
207-
TOOL = "TOOL"
228+
def is_valid_node(self, node: Node, workflow_type: WorkflowType = WorkflowType.APPLICATION):
229+
"""
230+
校验单个节点:交给该节点类型对应的序列化器
231+
"""
232+
from application.workflow.nodes import node_map
233+
234+
node_class = node_map.get(node.type, {}).get(workflow_type)
235+
if node_class is None or node_class.serializer_class is None:
236+
return
237+
try:
238+
node_class.serializer_class(data=get_node_parameters(node)).is_valid(raise_exception=True)
239+
except AppApiException as e:
240+
raise AppApiException(500, f"{node.properties.get('stepName')}:{e.message}")
208241

209242

210243
def new_instance(flow_obj: Dict, workflow_type: WorkflowType = WorkflowType.APPLICATION):

‎apps/application/workflow/i_node.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ class INode:
4242
# 序列化校验器
4343
serializer_class: Optional[Type[serializers.Serializer]] = None
4444

45-
@staticmethod
46-
def is_valid(data):
47-
INode.serializer_class(data=data).is_valid(raise_exception=True)
45+
@classmethod
46+
def is_valid(cls, data):
47+
if cls.serializer_class:
48+
cls.serializer_class(data=data).is_valid(raise_exception=True)
4849

4950
def __init__(self, node, workflow_manage, get_node_parameters: Callable[[Node], dict]):
5051
self.node = node

‎apps/application/workflow/nodes/ai_chat_node/ai_chat_node.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
from knowledge.models import File
4242
from models_provider.models import Model
4343
from models_provider.tools import get_model_credential, get_model_instance_by_model_workspace_id
44+
from common.exception.app_exception import AppApiException
4445

4546

4647
class AgentCallBack:
@@ -98,6 +99,15 @@ class ChatNodeSerializer(serializers.Serializer):
9899
image_list = serializers.ListField(required=False, label=_("picture"))
99100
vision = serializers.BooleanField(required=False, default=False, label=_("vision"))
100101

102+
def is_valid(self, *, raise_exception=False):
103+
super().is_valid(raise_exception=True)
104+
# reference / default 在运行时才解析,此处只校验自定义模型
105+
if (self.data.get("model_id_type") or "custom") in ("reference", "default"):
106+
return
107+
model_id = self.data.get("model_id")
108+
if not model_id or not QuerySet(Model).filter(id=model_id).exists():
109+
raise AppApiException(500, _("The model of the node does not exist"))
110+
101111

102112
def _get_default_model_params_setting(model_id):
103113
model = QuerySet(Model).filter(id=model_id).first()
@@ -639,7 +649,7 @@ def _get_reference_content(self, fields):
639649
def get_details(self, index: int = 0, position: dict = None, old_details: dict = None, **kwargs):
640650
details = super().get_details(index, position, old_details, **kwargs)
641651
aggregation = AggregationManager()
642-
for m in self.data.get("messages"):
652+
for m in self.data.get("messages") or []:
643653
aggregation.aggregate(m)
644654
messages = aggregation.get_contents()
645655
details.update(

‎apps/application/workflow/nodes/start_node/start_node.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class ApplicationSerializer(serializers.Serializer):
3636

3737

3838
class StarNode(INode):
39-
serializer_class = ApplicationSerializer
4039
supported_workflow_type_list = [WorkflowType.APPLICATION]
4140
type = "start-node"
4241

0 commit comments

Comments
 (0)