From df940686e98b0daeaee4a9a7975765b250dbb3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=91=9E=E6=96=8C?= Date: Fri, 21 Feb 2025 11:00:56 +0800 Subject: [PATCH] Variable assign (#2346) * feat: Support variable assign * feat: Workfloat support variable assign(#2114) * feat: Support variable assign save input output value * feat: Execution detail support variable assign(#2114) * feat: Support variable assign dict array value config * chore: rename package --------- Co-authored-by: wangdan-fit2cloud --- apps/application/flow/step_node/__init__.py | 7 +- .../variable_assign_node/__init__.py | 3 + .../i_variable_assign_node.py | 27 +++ .../variable_assign_node/impl/__init__.py | 9 + .../impl/base_variable_assign_node.py | 59 +++++ ui/src/assets/icon_assigner.svg | 5 + .../ai-chat/ExecutionDetailDialog.vue | 27 +++ ui/src/enums/workflow.ts | 3 +- .../lang/en-US/views/application-workflow.ts | 28 +-- .../lang/zh-CN/views/application-workflow.ts | 19 +- .../zh-Hant/views/application-workflow.ts | 10 +- ui/src/workflow/common/NodeCascader.vue | 9 +- ui/src/workflow/common/data.ts | 19 +- .../icons/variable-assign-node-icon.vue | 6 + .../workflow/nodes/condition-node/index.vue | 4 +- ui/src/workflow/nodes/reranker-node/index.vue | 2 +- .../nodes/variable-assign-node/index.ts | 14 ++ .../nodes/variable-assign-node/index.vue | 201 ++++++++++++++++++ 18 files changed, 420 insertions(+), 32 deletions(-) create mode 100644 apps/application/flow/step_node/variable_assign_node/__init__.py create mode 100644 apps/application/flow/step_node/variable_assign_node/i_variable_assign_node.py create mode 100644 apps/application/flow/step_node/variable_assign_node/impl/__init__.py create mode 100644 apps/application/flow/step_node/variable_assign_node/impl/base_variable_assign_node.py create mode 100644 ui/src/assets/icon_assigner.svg create mode 100644 ui/src/workflow/icons/variable-assign-node-icon.vue create mode 100644 ui/src/workflow/nodes/variable-assign-node/index.ts create mode 100644 ui/src/workflow/nodes/variable-assign-node/index.vue diff --git a/apps/application/flow/step_node/__init__.py b/apps/application/flow/step_node/__init__.py index 5e992079b..f3602901a 100644 --- a/apps/application/flow/step_node/__init__.py +++ b/apps/application/flow/step_node/__init__.py @@ -24,11 +24,14 @@ from .search_dataset_node import * from .speech_to_text_step_node import BaseSpeechToTextNode from .start_node import * from .text_to_speech_step_node.impl.base_text_to_speech_node import BaseTextToSpeechNode +from .variable_assign_node import BaseVariableAssignNode -node_list = [BaseStartStepNode, BaseChatNode, BaseSearchDatasetNode, BaseQuestionNode, BaseConditionNode, BaseReplyNode, +node_list = [BaseStartStepNode, BaseChatNode, BaseSearchDatasetNode, BaseQuestionNode, + BaseConditionNode, BaseReplyNode, BaseFunctionNodeNode, BaseFunctionLibNodeNode, BaseRerankerNode, BaseApplicationNode, BaseDocumentExtractNode, - BaseImageUnderstandNode, BaseFormNode, BaseSpeechToTextNode, BaseTextToSpeechNode,BaseImageGenerateNode] + BaseImageUnderstandNode, BaseFormNode, BaseSpeechToTextNode, BaseTextToSpeechNode, + BaseImageGenerateNode, BaseVariableAssignNode] def get_node(node_type): diff --git a/apps/application/flow/step_node/variable_assign_node/__init__.py b/apps/application/flow/step_node/variable_assign_node/__init__.py new file mode 100644 index 000000000..2d231e606 --- /dev/null +++ b/apps/application/flow/step_node/variable_assign_node/__init__.py @@ -0,0 +1,3 @@ +# coding=utf-8 + +from .impl import * \ No newline at end of file diff --git a/apps/application/flow/step_node/variable_assign_node/i_variable_assign_node.py b/apps/application/flow/step_node/variable_assign_node/i_variable_assign_node.py new file mode 100644 index 000000000..e4594183f --- /dev/null +++ b/apps/application/flow/step_node/variable_assign_node/i_variable_assign_node.py @@ -0,0 +1,27 @@ +# coding=utf-8 + +from typing import Type + +from django.utils.translation import gettext_lazy as _ +from rest_framework import serializers + +from application.flow.i_step_node import INode, NodeResult +from common.util.field_message import ErrMessage + + +class VariableAssignNodeParamsSerializer(serializers.Serializer): + variable_list = serializers.ListField(required=True, + error_messages=ErrMessage.list(_("Reference Field"))) + + +class IVariableAssignNode(INode): + type = 'variable-assign-node' + + def get_node_params_serializer_class(self) -> Type[serializers.Serializer]: + return VariableAssignNodeParamsSerializer + + def _run(self): + return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data) + + def execute(self, variable_list, stream, **kwargs) -> NodeResult: + pass diff --git a/apps/application/flow/step_node/variable_assign_node/impl/__init__.py b/apps/application/flow/step_node/variable_assign_node/impl/__init__.py new file mode 100644 index 000000000..7585cdd8f --- /dev/null +++ b/apps/application/flow/step_node/variable_assign_node/impl/__init__.py @@ -0,0 +1,9 @@ +# coding=utf-8 +""" + @project: maxkb + @Author:虎 + @file: __init__.py + @date:2024/6/11 17:49 + @desc: +""" +from .base_variable_assign_node import * \ No newline at end of file diff --git a/apps/application/flow/step_node/variable_assign_node/impl/base_variable_assign_node.py b/apps/application/flow/step_node/variable_assign_node/impl/base_variable_assign_node.py new file mode 100644 index 000000000..1eebcf3b9 --- /dev/null +++ b/apps/application/flow/step_node/variable_assign_node/impl/base_variable_assign_node.py @@ -0,0 +1,59 @@ +# coding=utf-8 +import json +from typing import List + +from application.flow.i_step_node import NodeResult +from application.flow.step_node.variable_assign_node.i_variable_assign_node import IVariableAssignNode + + +class BaseVariableAssignNode(IVariableAssignNode): + def save_context(self, details, workflow_manage): + self.context['variable_list'] = details.get('variable_list') + self.context['result_list'] = details.get('result_list') + + def execute(self, variable_list, stream, **kwargs) -> NodeResult: + # + result_list = [] + for variable in variable_list: + if 'fields' not in variable: + continue + if 'global' == variable['fields'][0]: + result = { + 'name': variable['name'], + 'input_value': self.get_reference_content(variable['fields']), + } + if variable['source'] == 'custom': + if variable['type'] in ['dict', 'array']: + if isinstance(variable['value'], dict) or isinstance(variable['value'], list): + val = variable['value'] + else: + val = json.loads(variable['value']) + self.workflow_manage.context[variable['fields'][1]] = val + result['output_value'] = variable['value'] = val + else: + self.workflow_manage.context[variable['fields'][1]] = variable['value'] + result['output_value'] = variable['value'] + else: + reference = self.get_reference_content(variable['reference']) + self.workflow_manage.context[variable['fields'][1]] = reference + result['output_value'] = reference + result_list.append(result) + + return NodeResult({'variable_list': variable_list, 'result_list': result_list}, {}) + + def get_reference_content(self, fields: List[str]): + return str(self.workflow_manage.get_reference_field( + fields[0], + fields[1:])) + + def get_details(self, index: int, **kwargs): + return { + 'name': self.node.properties.get('stepName'), + "index": index, + 'run_time': self.context.get('run_time'), + 'type': self.node.type, + 'variable_list': self.context.get('variable_list'), + 'result_list': self.context.get('result_list'), + 'status': self.status, + 'err_message': self.err_message + } diff --git a/ui/src/assets/icon_assigner.svg b/ui/src/assets/icon_assigner.svg new file mode 100644 index 000000000..269f075c3 --- /dev/null +++ b/ui/src/assets/icon_assigner.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ui/src/components/ai-chat/ExecutionDetailDialog.vue b/ui/src/components/ai-chat/ExecutionDetailDialog.vue index 52c208441..636af52f3 100644 --- a/ui/src/components/ai-chat/ExecutionDetailDialog.vue +++ b/ui/src/components/ai-chat/ExecutionDetailDialog.vue @@ -59,13 +59,16 @@
{{ $t('common.param.inputParam') }}
+
{{ $t('chat.paragraphSource.question') }}: + {{ item.question || '-' }}
+
{{ f.label }}: {{ f.value }}
@@ -604,6 +607,30 @@
+ + +