diff --git a/apps/knowledge/serializers/knowledge_workflow.py b/apps/knowledge/serializers/knowledge_workflow.py index b63abce70..8c1803f5e 100644 --- a/apps/knowledge/serializers/knowledge_workflow.py +++ b/apps/knowledge/serializers/knowledge_workflow.py @@ -5,6 +5,7 @@ import pickle from functools import reduce from typing import Dict, List +import requests import uuid_utils.compat as uuid from django.core.cache import cache from django.db import transaction @@ -25,7 +26,9 @@ from common.db.search import page_search from common.exception.app_exception import AppApiException from common.field.common import UploadedFileField from common.result import result +from common.utils.common import bytes_to_uploaded_file from common.utils.common import restricted_loads, generate_uuid +from common.utils.logger import maxkb_logger from common.utils.rsa_util import rsa_long_decrypt from common.utils.tool_code import ToolExecutor from knowledge.models import KnowledgeScope, Knowledge, KnowledgeType, KnowledgeWorkflow, KnowledgeWorkflowVersion @@ -70,6 +73,7 @@ class KnowledgeWorkflowActionListQuerySerializer(serializers.Serializer): user_name = serializers.CharField(required=False, label=_('Name'), allow_blank=True, allow_null=True) state = serializers.CharField(required=False, label=_("State"), allow_blank=True, allow_null=True) + class KBWFInstance: def __init__(self, knowledge_workflow: dict, function_lib_list: List[dict], version: str, tool_list: List[dict]): @@ -81,6 +85,7 @@ class KBWFInstance: def get_tool_list(self): return [*(self.tool_list or []), *(self.function_lib_list or [])] + class KnowledgeWorkflowActionSerializer(serializers.Serializer): workspace_id = serializers.CharField(required=True, label=_('workspace id')) knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id')) @@ -248,6 +253,24 @@ class KnowledgeWorkflowSerializer(serializers.Serializer): knowledge_workflow.save() save_workflow_mapping(instance.get('work_flow', {}), ResourceType.KNOWLEDGE, str(knowledge_id)) + + # 处理 work_flow_template + if instance.get('work_flow_template') is not None: + template_instance = instance.get('work_flow_template') + download_url = template_instance.get('downloadUrl') + # 查找匹配的版本名称 + res = requests.get(download_url, timeout=5) + KnowledgeWorkflowSerializer.Import(data={ + 'user_id': self.data.get('user_id'), + 'workspace_id': self.data.get('workspace_id'), + 'knowledge_id': str(knowledge_id), + }).import_({'file': bytes_to_uploaded_file(res.content, 'file.kbwf')}, is_import_tool=True) + + try: + requests.get(template_instance.get('downloadCallbackUrl'), timeout=5) + except Exception as e: + maxkb_logger.error(f"callback appstore tool download error: {e}") + return {**KnowledgeModelSerializer(knowledge).data, 'document_list': []} class Import(serializers.Serializer): @@ -255,6 +278,7 @@ class KnowledgeWorkflowSerializer(serializers.Serializer): workspace_id = serializers.CharField(required=True, label=_('workspace id')) knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id')) + @transaction.atomic def import_(self, instance: dict, is_import_tool, with_valid=True): if with_valid: self.is_valid() @@ -296,8 +320,10 @@ class KnowledgeWorkflowSerializer(serializers.Serializer): update_tool_map, ) tool_model_list = [self.to_tool(tool, workspace_id, user_id) for tool in tool_list] - KnowledgeWorkflow.objects.filter(workspace_id=workspace_id,knowledge_id=knowledge_id).update( - work_flow=work_flow + KnowledgeWorkflow.objects.filter(workspace_id=workspace_id, knowledge_id=knowledge_id).update_or_create( + knowledge_id=knowledge_id, + workspace_id=workspace_id, + defaults={'work_flow': work_flow} ) if is_import_tool: @@ -373,7 +399,6 @@ class KnowledgeWorkflowSerializer(serializers.Serializer): except Exception as e: return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR) - class Operate(serializers.Serializer): user_id = serializers.UUIDField(required=True, label=_('user id')) workspace_id = serializers.CharField(required=True, label=_('workspace id')) @@ -416,6 +441,23 @@ class KnowledgeWorkflowSerializer(serializers.Serializer): 'work_flow': instance.get('work_flow') }) return self.one() + if instance.get("work_flow_template"): + template_instance = instance.get('work_flow_template') + download_url = template_instance.get('downloadUrl') + # 查找匹配的版本名称 + res = requests.get(download_url, timeout=5) + KnowledgeWorkflowSerializer.Import(data={ + 'user_id': self.data.get('user_id'), + 'workspace_id': self.data.get('workspace_id'), + 'knowledge_id': str(self.data.get('knowledge_id')), + }).import_({'file': bytes_to_uploaded_file(res.content, 'file.kbwf')}, is_import_tool=False) + + try: + requests.get(template_instance.get('downloadCallbackUrl'), timeout=5) + except Exception as e: + maxkb_logger.error(f"callback appstore tool download error: {e}") + + return self.one() def one(self): self.is_valid(raise_exception=True) diff --git a/ui/src/api/tool/store.ts b/ui/src/api/tool/store.ts index 5494770da..9082bb886 100644 --- a/ui/src/api/tool/store.ts +++ b/ui/src/api/tool/store.ts @@ -32,6 +32,20 @@ const getStoreToolList: (param?: any, loading?: Ref) => Promise) => Promise> = ( + param, + loading, +) => { + return get('/workspace/store/knowledge_template', param, loading) +} + +const getStoreAppList: (param?: any, loading?: Ref) => Promise> = ( + param, + loading, +) => { + return get('/workspace/store/application_template', param, loading) +} + /** * 工具商店-添加系统内置 */ @@ -57,6 +71,8 @@ const addStoreTool: ( export default { getInternalToolList, getStoreToolList, + getStoreKBList, + getStoreAppList, addInternalTool, addStoreTool } diff --git a/ui/src/views/knowledge-workflow/index.vue b/ui/src/views/knowledge-workflow/index.vue index 24f1a7d5f..b4404e4bf 100644 --- a/ui/src/views/knowledge-workflow/index.vue +++ b/ui/src/views/knowledge-workflow/index.vue @@ -26,6 +26,13 @@
+ + {{ $t('模版中心') }} + {{ $t('workflow.setting.addComponent') }} @@ -161,6 +168,7 @@ v-click-outside="clickoutsideHistory" @refreshVersion="refreshVersion" /> +
+ diff --git a/ui/src/views/knowledge/template-store/TemplateCard.vue b/ui/src/views/knowledge/template-store/TemplateCard.vue new file mode 100644 index 000000000..6aa8bb999 --- /dev/null +++ b/ui/src/views/knowledge/template-store/TemplateCard.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/ui/src/views/knowledge/template-store/TemplateStoreDialog.vue b/ui/src/views/knowledge/template-store/TemplateStoreDialog.vue new file mode 100644 index 000000000..5408c2f5d --- /dev/null +++ b/ui/src/views/knowledge/template-store/TemplateStoreDialog.vue @@ -0,0 +1,307 @@ + + + + diff --git a/ui/src/views/tool/tool-store/ToolStoreDialog.vue b/ui/src/views/tool/tool-store/ToolStoreDialog.vue index 7c78f3ac7..8899289f1 100644 --- a/ui/src/views/tool/tool-store/ToolStoreDialog.vue +++ b/ui/src/views/tool/tool-store/ToolStoreDialog.vue @@ -164,7 +164,7 @@ async function getList() { return acc }, [] as ToolCategory[]) - categories.value = merged + categories.value = merged.filter((item: any) => item.tools.length > 0) } async function getInternalToolList() {