-
Notifications
You must be signed in to change notification settings - Fork 2.8k
fix: [Application, Knowledge Base] Workflow Export Now Supports Exporting Tool Workflows #4978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,7 +55,7 @@ | |
| from system_manage.models.resource_mapping import ResourceMapping | ||
| from system_manage.serializers.resource_mapping_serializers import ResourceMappingSerializer | ||
| from system_manage.serializers.user_resource_permission import UserResourcePermissionSerializer | ||
| from tools.models import Tool, ToolScope, ToolType | ||
| from tools.models import Tool, ToolScope, ToolType, ToolWorkflow | ||
| from tools.serializers.tool import ToolExportModelSerializer | ||
| from trigger.models import TriggerTask, Trigger | ||
| from users.models import User | ||
|
|
@@ -93,6 +93,10 @@ def hand_node(node, update_tool_map): | |
| mcp_tool_id = (node.get('properties', {}).get('node_data', {}).get('mcp_tool_id') or '') | ||
| node.get('properties', {}).get('node_data', {})['mcp_tool_id'] = update_tool_map.get(mcp_tool_id, | ||
| mcp_tool_id) | ||
| if node.get('type') == 'tool-workflow-lib-node': | ||
| tool_lib_id = (node.get('properties', {}).get('node_data', {}).get('tool_lib_id') or '') | ||
| node.get('properties', {}).get('node_data', {})['tool_lib_id'] = update_tool_map.get(tool_lib_id, | ||
| tool_lib_id) | ||
|
|
||
|
|
||
| class MKInstance: | ||
|
|
@@ -628,6 +632,12 @@ def import_(self, instance: dict, is_import_tool, with_valid=True): | |
| if is_import_tool: | ||
| if len(tool_model_list) > 0: | ||
| QuerySet(Tool).bulk_create(tool_model_list) | ||
| QuerySet(ToolWorkflow).bulk_create( | ||
| [ToolWorkflow(workspace_id=workspace_id, | ||
| work_flow=self.reset_workflow(tool.get('work_flow'), update_tool_map), | ||
| tool_id=tool.get('id')) | ||
| for | ||
| tool in tool_list if tool.get('tool_type') == ToolType.WORKFLOW]) | ||
| UserResourcePermissionSerializer(data={ | ||
| 'workspace_id': self.data.get('workspace_id'), | ||
| 'user_id': self.data.get('user_id'), | ||
|
|
@@ -670,6 +680,15 @@ def to_tool(tool, workspace_id, user_id): | |
| folder_id=workspace_id, | ||
| workspace_id=workspace_id) | ||
|
|
||
| @staticmethod | ||
| def reset_workflow(work_flow, update_tool_map): | ||
| for node in work_flow.get('nodes', []): | ||
| hand_node(node, update_tool_map) | ||
| if node.get('type') == 'loop-node': | ||
| for n in node.get('properties', {}).get('node_data', {}).get('loop_body', {}).get('nodes', []): | ||
| hand_node(n, update_tool_map) | ||
| return work_flow | ||
|
|
||
| @staticmethod | ||
| def to_application(application, workspace_id, user_id, update_tool_map, folder_id): | ||
| work_flow = application.get('work_flow') | ||
|
|
@@ -844,13 +863,16 @@ def export(self, with_valid=True): | |
| application_id = self.data.get('application_id') | ||
| application = QuerySet(Application).filter(id=application_id).first() | ||
| from application.flow.tools import get_tool_id_list | ||
| tool_id_list = get_tool_id_list(application.work_flow) | ||
| tool_id_list = get_tool_id_list(application.work_flow, True) | ||
| if len(tool_id_list) > 0: | ||
| tool_list = QuerySet(Tool).filter(id__in=tool_id_list).exclude(scope=ToolScope.SHARED) | ||
| else: | ||
| tool_list = QuerySet(Tool).filter( | ||
| id__in=application.tool_ids + application.mcp_tool_ids + application.skill_tool_ids | ||
| ).exclude(scope=ToolScope.SHARED) | ||
| tw_dict = {tw.tool_id: tw | ||
| for tw in QuerySet(ToolWorkflow).filter( | ||
| tool_id__in=[tool.id for tool in tool_list if tool.tool_type == ToolType.WORKFLOW])} | ||
| # 如果是技能工具,则需要将code字段转换为文件内容的base64字符串 | ||
| for tool in tool_list: | ||
| if tool.tool_type == ToolType.SKILL: | ||
|
|
@@ -862,7 +884,7 @@ def export(self, with_valid=True): | |
| mk_instance = MKInstance(application_dict, | ||
| [], | ||
| 'v2', | ||
| [ToolExportModelSerializer(tool).data for tool in | ||
| [self.to_tool_dict(tool, tw_dict) for tool in | ||
| tool_list]) | ||
| application_pickle = pickle.dumps(mk_instance) | ||
| response = HttpResponse(content_type='text/plain', content=application_pickle) | ||
|
|
@@ -871,6 +893,12 @@ def export(self, with_valid=True): | |
| except Exception as e: | ||
| return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR) | ||
|
|
||
| @staticmethod | ||
| def to_tool_dict(tool, tool_workflow_dict): | ||
| if tool.tool_type == ToolType.WORKFLOW: | ||
| return {**ToolExportModelSerializer(tool).data, 'work_flow': tool_workflow_dict.get(tool.id).work_flow} | ||
| return ToolExportModelSerializer(tool).data | ||
|
|
||
| @staticmethod | ||
| def reset_application_version(application_version, application): | ||
| update_field_dict = { | ||
|
|
@@ -1329,7 +1357,7 @@ def batch_delete(self, instance: Dict, with_valid=True): | |
| from trigger.serializers.trigger import TriggerModelSerializer | ||
|
|
||
| if with_valid: | ||
| BatchSerializer(data=instance).is_valid(model=Application,raise_exception=True) | ||
| BatchSerializer(data=instance).is_valid(model=Application, raise_exception=True) | ||
| self.is_valid(raise_exception=True) | ||
| id_list = instance.get("id_list") | ||
| workspace_id = self.data.get('workspace_id') | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code looks mostly correct but contains a few areas that could be improved:
Here are some specific improvements to suggest: Line Length ImprovementQuerySet(ToolWorkflow).bulk_create([ToolWorkflow(workspace_id=ws_id, work_flow=self.reset_workflow(twf, update_tool_map), tool_id=tw_id)
for tw in tool_list if tw.tool_type == ToolType.WORKFLOW])Correction in Workflow Type Check Inside
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,7 +38,7 @@ | |
| from system_manage.models import AuthTargetType | ||
| from system_manage.models.resource_mapping import ResourceType | ||
| from system_manage.serializers.user_resource_permission import UserResourcePermissionSerializer | ||
| from tools.models import Tool, ToolScope | ||
| from tools.models import Tool, ToolScope, ToolType, ToolWorkflow | ||
| from tools.serializers.tool import ToolExportModelSerializer | ||
| from users.models import User | ||
|
|
||
|
|
@@ -64,6 +64,10 @@ def hand_node(node, update_tool_map): | |
| mcp_tool_id = (node.get('properties', {}).get('node_data', {}).get('mcp_tool_id') or '') | ||
| node.get('properties', {}).get('node_data', {})['mcp_tool_id'] = update_tool_map.get(mcp_tool_id, | ||
| mcp_tool_id) | ||
| if node.get('type') == 'tool-workflow-lib-node': | ||
| tool_lib_id = (node.get('properties', {}).get('node_data', {}).get('tool_lib_id') or '') | ||
| node.get('properties', {}).get('node_data', {})['tool_lib_id'] = update_tool_map.get(tool_lib_id, | ||
| tool_lib_id) | ||
|
|
||
|
|
||
| class KnowledgeWorkflowModelSerializer(serializers.ModelSerializer): | ||
|
|
@@ -356,6 +360,12 @@ def import_(self, instance: dict, is_import_tool, with_valid=True): | |
| if is_import_tool: | ||
| if len(tool_model_list) > 0: | ||
| QuerySet(Tool).bulk_create(tool_model_list) | ||
| QuerySet(ToolWorkflow).bulk_create( | ||
| [ToolWorkflow(workspace_id=workspace_id, | ||
| work_flow=self.reset_workflow(tool.get('work_flow'), update_tool_map), | ||
| tool_id=tool.get('id')) | ||
| for | ||
| tool in tool_list if tool.get('tool_type') == ToolType.WORKFLOW]) | ||
| UserResourcePermissionSerializer(data={ | ||
| 'workspace_id': self.data.get('workspace_id'), | ||
| 'user_id': self.data.get('user_id'), | ||
|
|
@@ -374,6 +384,15 @@ def to_knowledge_workflow(knowledge_workflow, update_tool_map): | |
| hand_node(n, update_tool_map) | ||
| return work_flow | ||
|
|
||
| @staticmethod | ||
| def reset_workflow(work_flow, update_tool_map): | ||
| for node in work_flow.get('nodes', []): | ||
| hand_node(node, update_tool_map) | ||
| if node.get('type') == 'loop-node': | ||
| for n in node.get('properties', {}).get('node_data', {}).get('loop_body', {}).get('nodes', []): | ||
| hand_node(n, update_tool_map) | ||
| return work_flow | ||
|
|
||
| @staticmethod | ||
| def to_tool(tool, workspace_id, user_id): | ||
| return Tool(id=tool.get('id'), | ||
|
|
@@ -402,17 +421,20 @@ def export(self, with_valid=True): | |
| knowledge_workflow = QuerySet(KnowledgeWorkflow).filter(knowledge_id=knowledge_id).first() | ||
| knowledge = QuerySet(Knowledge).filter(id=knowledge_id).first() | ||
| from application.flow.tools import get_tool_id_list | ||
| tool_id_list = get_tool_id_list(knowledge_workflow.work_flow) | ||
| tool_id_list = get_tool_id_list(knowledge_workflow.work_flow, True) | ||
| tool_list = [] | ||
| if len(tool_id_list) > 0: | ||
| tool_list = QuerySet(Tool).filter(id__in=tool_id_list).exclude(scope=ToolScope.SHARED) | ||
| tw_dict = {tw.tool_id: tw | ||
| for tw in QuerySet(ToolWorkflow).filter( | ||
| tool_id__in=[tool.id for tool in tool_list if tool.tool_type == ToolType.WORKFLOW])} | ||
| knowledge_workflow_dict = KnowledgeWorkflowModelSerializer(knowledge_workflow).data | ||
|
|
||
| kbwf_instance = KBWFInstance( | ||
| knowledge_workflow_dict, | ||
| [], | ||
| 'v2', | ||
| [ToolExportModelSerializer(tool).data for tool in tool_list] | ||
| [self.to_tool_dict(tool, tw_dict) for tool in tool_list] | ||
| ) | ||
| knowledge_workflow_pickle = pickle.dumps(kbwf_instance) | ||
| response = HttpResponse(content_type='text/plain', content=knowledge_workflow_pickle) | ||
|
|
@@ -421,6 +443,12 @@ def export(self, with_valid=True): | |
| except Exception as e: | ||
| return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR) | ||
|
|
||
| @staticmethod | ||
| def to_tool_dict(tool, tool_workflow_dict): | ||
| if tool.tool_type == ToolType.WORKFLOW: | ||
| return {**ToolExportModelSerializer(tool).data, 'work_flow': tool_workflow_dict.get(tool.id).work_flow} | ||
| return ToolExportModelSerializer(tool).data | ||
|
|
||
| class Operate(serializers.Serializer): | ||
| user_id = serializers.UUIDField(required=True, label=_('user id')) | ||
| workspace_id = serializers.CharField(required=True, label=_('workspace id')) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your code appears to be generally well-structured, but there are a few areas that could benefit from improvements: Improvements:
Optimizations:
Here's your updated code snippet with some improvements applied: @@ -38,7 +38,7 @@
from system_manage.models import AuthTargetType
from system_manage.models.resource_mapping import ResourceType
from system_manage.serializers.user_resource_permission import UserResourcePermissionSerializer
-from tools.models import Tool, ToolScope
+from tools.models import Tool, ToolScope, ToolType, ToolWorkflow
from tools.serializers.tool import ToolExportModelSerializer
from users.models import User
@@ -64,6 +64,10 @@ def hand_node(node, update_tool_map):
mcp_tool_id = (node.get('properties', {}).get('node_data', {}).get('mcp_tool_id') or '')
node.get('properties', {}).get('node_data', {})['mcp_tool_id'] = update_tool_map.get(mcp_tool_id,
mcp_tool_id)
+ if node.get('type') == 'tool-workflow-lib-node':
+ tool_lib_id = (node.get('properties', {}).get('node_data', {}).get('tool_lib_id') or '')
+ node.get('properties', {}).get('node_data', {})['tool_lib_id'] = update_tool_map.get(tool_lib_id,
+ tool_lib_id)
class KnowledgeWorkflowModelSerializer(serializers.ModelSerializer):
@@ -356,6 +360,12 @@ def import_(self, instance: dict, is_import_tool, with_valid=True):
if is_import_tool:
if len(tool_model_list) > 0:
QuerySet(Tool).bulk_create(tool_model_list)
+ QuerySet(ToolWorkflow).bulk_create(
+ [ToolWorkflow(workspace_id=workspace_id,
+ work_flow=self._reset_workflow(tool.get('work_flow'), update_tool_map),
+ tool_id=tool.get('id'))
+ for tool in tool_list if tool.get('tool_type') == ToolType.WORKFLOW])
+These changes should improve the robustness and maintainability of your codebase. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imports and Variable Naming:
_resultinget_tool_id_list()is misleading because it suggests that this variable will store results, but it ends up being an empty list.save_workflow_mapping(), the comment about filtering out files using a specific key ((str(item.target_type) + str(item.target_id))) may be redundant since the actual filter logic does not include such functionality.Logic of
get_tool_id_list():Improvements for Recursive Handling:
responseto reflect their intended purpose or use more descriptive names.Edge Cases in Functions:
Here’s an optimized version incorporating some suggested changes:
This version uses sets to avoid duplicate entries, which improves efficiency especially when dealing with large datasets. It also outlines general guidelines that could guide further optimizations depending on actual usage patterns and performance needs.