mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
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 <dan.wang@fit2cloud.com>
This commit is contained in:
parent
bb557fd187
commit
df940686e9
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
# coding=utf-8
|
||||
|
||||
from .impl import *
|
||||
|
|
@ -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
|
||||
|
|
@ -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 *
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.98262 2.70361H5.98155C5.17745 2.70361 4.55609 2.95232 4.11749 3.46751C3.71543 3.9294 3.51441 4.56895 3.51441 5.36838V8.69045C3.51441 9.18787 3.40476 9.56094 3.18545 9.80965C2.97469 10.0292 2.6275 10.1764 2.14389 10.2413C1.95529 10.2666 1.81483 10.4233 1.81482 10.6084V11.4085C1.81481 11.5847 1.94968 11.7334 2.12951 11.7554C2.62062 11.8156 2.97261 11.9537 3.18545 12.1902C3.40476 12.4211 3.51441 12.7942 3.51441 13.3094V16.6492C3.51441 17.4309 3.71543 18.0704 4.11749 18.5323C4.55609 19.0297 5.17745 19.2962 5.98155 19.2962H6.98262C7.20691 19.2962 7.38874 19.1195 7.38874 18.9014V18.252C7.38874 18.034 7.20691 17.8572 6.98262 17.8572H6.3105C5.61605 17.8572 5.2871 17.4664 5.2871 16.7203V13.2205C5.2871 12.1546 4.75712 11.4263 3.71543 10.9999C4.75712 10.6268 5.2871 9.88071 5.2871 8.77927V5.29732C5.2871 4.51565 5.61605 4.14259 6.3105 4.14259H6.98262C7.20691 4.14259 7.38874 3.96584 7.38874 3.74781V3.09839C7.38874 2.88036 7.20691 2.70361 6.98262 2.70361ZM16.0185 2.70361H15.0174C14.7931 2.70361 14.6113 2.88036 14.6113 3.09839V3.74781C14.6113 3.96584 14.7931 4.14259 15.0174 4.14259H15.6895C16.3657 4.14259 16.7129 4.51565 16.7129 5.29732V8.77927C16.7129 9.88071 17.2246 10.6268 18.2846 10.9999C17.2246 11.4263 16.7129 12.1546 16.7129 13.2205V16.7203C16.7129 17.4664 16.3657 17.8572 15.6895 17.8572H15.0174C14.7931 17.8572 14.6113 18.034 14.6113 18.252V18.9014C14.6113 19.1195 14.7931 19.2962 15.0174 19.2962H16.0185C16.8226 19.2962 17.4439 19.0297 17.8825 18.5323C18.2846 18.0704 18.4856 17.4309 18.4856 16.6492V13.3094C18.4856 12.7942 18.5953 12.4211 18.8146 12.1902C19.0209 11.961 19.3579 11.8242 19.8257 11.7612L19.8331 11.7602C20.0347 11.7339 20.1852 11.5667 20.1852 11.3689V10.6149C20.1852 10.4263 20.0421 10.2665 19.8499 10.2405C19.3701 10.1756 19.0277 10.0314 18.8328 9.82741C18.5953 9.5787 18.4856 9.18787 18.4856 8.69045V5.36838C18.4856 4.56895 18.2846 3.9294 17.8825 3.46751C17.4439 2.95232 16.8226 2.70361 16.0185 2.70361Z" fill="white"/>
|
||||
<path d="M7.44443 8.68878C7.44443 8.49241 7.60362 8.33323 7.79999 8.33323H14.2C14.3964 8.33323 14.5555 8.49241 14.5555 8.68878V9.75545C14.5555 9.95182 14.3964 10.111 14.2 10.111H7.79999C7.60362 10.111 7.44443 9.95182 7.44443 9.75545V8.68878Z" fill="white"/>
|
||||
<path d="M7.44443 12.2443C7.44443 12.048 7.60362 11.8888 7.79999 11.8888H14.2C14.3964 11.8888 14.5555 12.048 14.5555 12.2443V13.311C14.5555 13.5074 14.3964 13.6666 14.2 13.6666H7.79999C7.60362 13.6666 7.44443 13.5074 7.44443 13.311V12.2443Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -59,13 +59,16 @@
|
|||
<h5 class="p-8-12">
|
||||
{{ $t('common.param.inputParam') }}
|
||||
</h5>
|
||||
|
||||
<div class="p-8-12 border-t-dashed lighter">
|
||||
<div class="mb-8">
|
||||
<span class="color-secondary">
|
||||
{{ $t('chat.paragraphSource.question') }}:</span
|
||||
>
|
||||
|
||||
{{ item.question || '-' }}
|
||||
</div>
|
||||
|
||||
<div v-for="(f, i) in item.global_fields" :key="i" class="mb-8">
|
||||
<span class="color-secondary">{{ f.label }}:</span> {{ f.value }}
|
||||
</div>
|
||||
|
|
@ -604,6 +607,30 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 变量赋值 -->
|
||||
<template v-if="item.type === WorkflowType.VariableAssignNode">
|
||||
<div class="card-never border-r-4">
|
||||
<h5 class="p-8-12">
|
||||
{{ $t('common.param.inputParam') }}
|
||||
</h5>
|
||||
<div class="p-8-12 border-t-dashed lighter">
|
||||
<div v-for="(f, i) in item.result_list" :key="i" class="mb-8">
|
||||
<span class="color-secondary">{{ f.name }}:</span> {{ f.input_value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-never border-r-4">
|
||||
<h5 class="p-8-12">
|
||||
{{ $t('common.param.outputParam') }}
|
||||
</h5>
|
||||
<div class="p-8-12 border-t-dashed lighter">
|
||||
<div v-for="(f, i) in item.result_list" :key="i" class="mb-8">
|
||||
<span class="color-secondary">{{ f.name }}:</span> {{ f.output_value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="card-never border-r-4">
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ export enum WorkflowType {
|
|||
Application = 'application-node',
|
||||
DocumentExtractNode = 'document-extract-node',
|
||||
ImageUnderstandNode = 'image-understand-node',
|
||||
VariableAssignNode = 'variable-assign-node',
|
||||
FormNode = 'form-node',
|
||||
TextToSpeechNode = 'text-to-speech-node',
|
||||
SpeechToTextNode = 'speech-to-text-node',
|
||||
ImageGenerateNode = 'image-generate-node'
|
||||
ImageGenerateNode = 'image-generate-node'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export default {
|
|||
autoSave: 'Auto Save',
|
||||
latestRelease: 'Latest Release',
|
||||
copyParam: 'Copy Parameters',
|
||||
debug: 'Run',
|
||||
debug: 'Run'
|
||||
},
|
||||
tip: {
|
||||
publicSuccess: 'Published successfully',
|
||||
|
|
@ -48,12 +48,13 @@ export default {
|
|||
beautify: 'Auto-Arrange'
|
||||
},
|
||||
variable: {
|
||||
label: 'Variable',
|
||||
global: 'Global Variable',
|
||||
Referencing: 'Referenced Variable',
|
||||
ReferencingRequired: 'Referenced variable is required',
|
||||
ReferencingError: 'Invalid referenced variable',
|
||||
NoReferencing: 'Referenced variable does not exist',
|
||||
fieldMessage: 'Please select a variable'
|
||||
placeholder: 'Please select a variable'
|
||||
},
|
||||
condition: {
|
||||
title: 'Execution Condition',
|
||||
|
|
@ -82,12 +83,11 @@ export default {
|
|||
baseNode: {
|
||||
label: 'Base Information',
|
||||
appName: {
|
||||
label: 'App Name',
|
||||
|
||||
label: 'App Name'
|
||||
},
|
||||
appDescription: {
|
||||
label: 'App Description',
|
||||
},
|
||||
label: 'App Description'
|
||||
},
|
||||
fileUpload: {
|
||||
label: 'File Upload',
|
||||
tooltip: 'When enabled, the Q&A page will display a file upload button.'
|
||||
|
|
@ -114,7 +114,7 @@ export default {
|
|||
If you want the user to see the output of this node, please turn on the switch.`
|
||||
},
|
||||
defaultPrompt: 'Known Information',
|
||||
think: 'Thinking Process',
|
||||
think: 'Thinking Process'
|
||||
},
|
||||
searchDatasetNode: {
|
||||
label: 'Knowledge Retrieval',
|
||||
|
|
@ -188,8 +188,7 @@ export default {
|
|||
label: 'Form Output Content',
|
||||
requiredMessage:
|
||||
'Please set the output content of this node, { form } is a placeholder for the form.',
|
||||
tooltip:
|
||||
'Define the output content of this node. { form } is a placeholder for the form'
|
||||
tooltip: 'Define the output content of this node. { form } is a placeholder for the form'
|
||||
},
|
||||
formAllContent: 'All Form Content',
|
||||
formSetting: 'Form Configuration'
|
||||
|
|
@ -212,6 +211,11 @@ export default {
|
|||
requiredMessage: 'Please select an image'
|
||||
}
|
||||
},
|
||||
variableAssignNode: {
|
||||
label: 'Variable Assign',
|
||||
text: 'Update the value of the global variable',
|
||||
assign: 'Set Value'
|
||||
},
|
||||
imageGenerateNode: {
|
||||
label: 'Image Generation',
|
||||
text: 'Generate images based on provided text content',
|
||||
|
|
@ -222,13 +226,11 @@ export default {
|
|||
},
|
||||
prompt: {
|
||||
label: 'Positive Prompt',
|
||||
tooltip:
|
||||
'Describe elements and visual features you want in the generated image'
|
||||
tooltip: 'Describe elements and visual features you want in the generated image'
|
||||
},
|
||||
negative_prompt: {
|
||||
label: 'Negative Prompt',
|
||||
tooltip:
|
||||
'Describe elements you want to exclude from the generated image',
|
||||
tooltip: 'Describe elements you want to exclude from the generated image',
|
||||
placeholder:
|
||||
'Please describe content you do not want to generate, such as color, bloody content'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export default {
|
|||
autoSave: '自动保存',
|
||||
latestRelease: '最近发布',
|
||||
copyParam: '复制参数',
|
||||
debug: '调试',
|
||||
debug: '调试'
|
||||
},
|
||||
tip: {
|
||||
publicSuccess: '发布成功',
|
||||
|
|
@ -48,12 +48,13 @@ export default {
|
|||
beautify: '一键美化'
|
||||
},
|
||||
variable: {
|
||||
label: '变量',
|
||||
global: '全局变量',
|
||||
Referencing: '引用变量',
|
||||
ReferencingRequired: '引用变量必填',
|
||||
ReferencingError: '引用变量错误',
|
||||
NoReferencing: '不存在的引用变量',
|
||||
fieldMessage: '请选择变量'
|
||||
placeholder: '请选择变量'
|
||||
},
|
||||
condition: {
|
||||
title: '执行条件',
|
||||
|
|
@ -83,12 +84,11 @@ export default {
|
|||
baseNode: {
|
||||
label: '基本信息',
|
||||
appName: {
|
||||
label: '应用名称',
|
||||
|
||||
label: '应用名称'
|
||||
},
|
||||
appDescription: {
|
||||
label: '应用描述',
|
||||
},
|
||||
label: '应用描述'
|
||||
},
|
||||
fileUpload: {
|
||||
label: '文件上传',
|
||||
tooltip: '开启后,问答页面会显示上传文件的按钮。'
|
||||
|
|
@ -115,7 +115,7 @@ export default {
|
|||
如果你想让用户看到该节点的输出内容,请打开开关。`
|
||||
},
|
||||
defaultPrompt: '已知信息',
|
||||
think: '思考过程',
|
||||
think: '思考过程'
|
||||
},
|
||||
searchDatasetNode: {
|
||||
label: '知识库检索',
|
||||
|
|
@ -211,6 +211,11 @@ export default {
|
|||
requiredMessage: '请选择图片'
|
||||
}
|
||||
},
|
||||
variableAssignNode: {
|
||||
label: '变量赋值',
|
||||
text: '更新全局变量的值',
|
||||
assign: '赋值'
|
||||
},
|
||||
imageGenerateNode: {
|
||||
label: '图片生成',
|
||||
text: '根据提供的文本内容生成图片',
|
||||
|
|
|
|||
|
|
@ -48,12 +48,13 @@ export default {
|
|||
beautify: '一鍵美化'
|
||||
},
|
||||
variable: {
|
||||
label: '變量',
|
||||
global: '全局變量',
|
||||
Referencing: '引用變量',
|
||||
ReferencingRequired: '引用變量必填',
|
||||
ReferencingError: '引用變量錯誤',
|
||||
NoReferencing: '不存在的引用變量',
|
||||
fieldMessage: '請選擇變量'
|
||||
placeholder: '請選擇變量'
|
||||
},
|
||||
condition: {
|
||||
title: '執行條件',
|
||||
|
|
@ -114,7 +115,7 @@ export default {
|
|||
如果你想讓用戶看到該節點的輸出內容,請打開開關。`
|
||||
},
|
||||
defaultPrompt: '已知信息',
|
||||
think: '思考過程',
|
||||
think: '思考過程'
|
||||
},
|
||||
searchDatasetNode: {
|
||||
label: '知識庫檢索',
|
||||
|
|
@ -210,6 +211,11 @@ export default {
|
|||
requiredMessage: '請選擇圖片'
|
||||
}
|
||||
},
|
||||
variableAssignNode: {
|
||||
label: '變數賦值',
|
||||
text: '更新全域變數的值',
|
||||
assign: '賦值'
|
||||
},
|
||||
imageGenerateNode: {
|
||||
label: '圖片生成',
|
||||
text: '根據提供的文本內容生成圖片',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { t } from '@/locales'
|
|||
const props = defineProps<{
|
||||
nodeModel: any
|
||||
modelValue: Array<any>
|
||||
global?: Boolean
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const data = computed({
|
||||
|
|
@ -49,7 +50,9 @@ const wheel = (e: any) => {
|
|||
|
||||
function visibleChange(bool: boolean) {
|
||||
if (bool) {
|
||||
options.value = props.nodeModel.get_up_node_field_list(false, true)
|
||||
options.value = props.global
|
||||
? props.nodeModel.get_up_node_field_list(false, true).filter((v) => v.value === 'global')
|
||||
: props.nodeModel.get_up_node_field_list(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +79,9 @@ const validate = () => {
|
|||
}
|
||||
defineExpose({ validate })
|
||||
onMounted(() => {
|
||||
options.value = props.nodeModel.get_up_node_field_list(false, true)
|
||||
options.value = props.global
|
||||
? props.nodeModel.get_up_node_field_list(false, true).filter((v) => v.value === 'global')
|
||||
: props.nodeModel.get_up_node_field_list(false, true)
|
||||
})
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -239,6 +239,19 @@ export const imageUnderstandNode = {
|
|||
}
|
||||
}
|
||||
|
||||
export const variableAssignNode = {
|
||||
type: WorkflowType.VariableAssignNode,
|
||||
text: t('views.applicationWorkflow.nodes.variableAssignNode.text'),
|
||||
label: t('views.applicationWorkflow.nodes.variableAssignNode.label'),
|
||||
height: 252,
|
||||
properties: {
|
||||
stepName: t('views.applicationWorkflow.nodes.variableAssignNode.label'),
|
||||
config: {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const imageGenerateNode = {
|
||||
type: WorkflowType.ImageGenerateNode,
|
||||
text: t('views.applicationWorkflow.nodes.imageGenerateNode.text'),
|
||||
|
|
@ -307,7 +320,8 @@ export const menuNodes = [
|
|||
questionNode,
|
||||
documentExtractNode,
|
||||
speechToTextNode,
|
||||
textToSpeechNode
|
||||
textToSpeechNode,
|
||||
variableAssignNode
|
||||
]
|
||||
|
||||
/**
|
||||
|
|
@ -400,7 +414,8 @@ export const nodeDict: any = {
|
|||
[WorkflowType.ImageUnderstandNode]: imageUnderstandNode,
|
||||
[WorkflowType.TextToSpeechNode]: textToSpeechNode,
|
||||
[WorkflowType.SpeechToTextNode]: speechToTextNode,
|
||||
[WorkflowType.ImageGenerateNode]: imageGenerateNode
|
||||
[WorkflowType.ImageGenerateNode]: imageGenerateNode,
|
||||
[WorkflowType.VariableAssignNode]: variableAssignNode,
|
||||
}
|
||||
export function isWorkFlow(type: string | undefined) {
|
||||
return type === 'WORK_FLOW'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<template>
|
||||
<AppAvatar shape="square">
|
||||
<img src="@/assets/icon_assigner.svg" style="width: 65%" alt="" />
|
||||
</AppAvatar>
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
:rules="{
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: $t('views.applicationWorkflow.variable.fieldMessage'),
|
||||
message: $t('views.applicationWorkflow.variable.placeholder'),
|
||||
trigger: 'change'
|
||||
}"
|
||||
>
|
||||
|
|
@ -57,7 +57,7 @@
|
|||
:nodeModel="nodeModel"
|
||||
class="w-full"
|
||||
:placeholder="
|
||||
$t('views.applicationWorkflow.variable.fieldMessage')
|
||||
$t('views.applicationWorkflow.variable.placeholder')
|
||||
"
|
||||
v-model="condition.field"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
:rules="{
|
||||
type: 'array',
|
||||
required: true,
|
||||
message: $t('views.applicationWorkflow.variable.fieldMessage'),
|
||||
message: $t('views.applicationWorkflow.variable.placeholder'),
|
||||
trigger: 'change'
|
||||
}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import VariableAssignNodeVue from './index.vue'
|
||||
import { AppNode, AppNodeModel } from '@/workflow/common/app-node'
|
||||
|
||||
class VariableAssignNode extends AppNode {
|
||||
constructor(props: any) {
|
||||
super(props, VariableAssignNodeVue)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'variable-assign-node',
|
||||
model: AppNodeModel,
|
||||
view: VariableAssignNode
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
<template>
|
||||
<NodeContainer :nodeModel="nodeModel">
|
||||
<el-form
|
||||
@submit.prevent
|
||||
:model="form_data"
|
||||
label-position="top"
|
||||
require-asterisk-position="right"
|
||||
label-width="auto"
|
||||
ref="replyNodeFormRef"
|
||||
>
|
||||
<template v-for="(item, index) in form_data.variable_list" :key="item.id">
|
||||
<el-card shadow="never" class="card-never mb-8" style="--el-card-padding: 12px">
|
||||
<el-form-item :label="$t('views.applicationWorkflow.variable.label')">
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
<div>
|
||||
{{ $t('views.applicationWorkflow.variable.label') }}
|
||||
<span class="danger">*</span>
|
||||
</div>
|
||||
<el-button text @click="deleteVariable(index)" v-if="index !== 0">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<NodeCascader
|
||||
ref="nodeCascaderRef"
|
||||
:nodeModel="nodeModel"
|
||||
class="w-full"
|
||||
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
|
||||
v-model="item.fields"
|
||||
:global="true"
|
||||
@change="variableChange(item)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex-between">
|
||||
<div>
|
||||
<span
|
||||
>{{ $t('views.applicationWorkflow.nodes.variableAssignNode.assign')
|
||||
}}<span class="danger">*</span></span
|
||||
>
|
||||
</div>
|
||||
<el-select
|
||||
:teleported="false"
|
||||
v-model="item.source"
|
||||
size="small"
|
||||
style="width: 85px"
|
||||
>
|
||||
<el-option
|
||||
:label="$t('views.applicationWorkflow.nodes.replyNode.replyContent.reference')"
|
||||
value="referencing"
|
||||
/>
|
||||
<el-option
|
||||
:label="$t('views.applicationWorkflow.nodes.replyNode.replyContent.custom')"
|
||||
value="custom"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="item.source === 'custom'" class="flex">
|
||||
<el-select v-model="item.type" style="width: 130px;">
|
||||
<el-option v-for="item in typeOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-input
|
||||
class="ml-4"
|
||||
v-model="item.value"
|
||||
:placeholder="$t('common.inputPlaceholder')"
|
||||
show-word-limit
|
||||
clearable
|
||||
@wheel="wheel"
|
||||
></el-input>
|
||||
</div>
|
||||
|
||||
<NodeCascader
|
||||
v-else
|
||||
ref="nodeCascaderRef2"
|
||||
:nodeModel="nodeModel"
|
||||
class="w-full"
|
||||
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
|
||||
v-model="item.reference"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</template>
|
||||
<el-button link type="primary" @click="addVariable">
|
||||
<el-icon class="mr-4">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
{{ $t('common.add') }}
|
||||
</el-button>
|
||||
</el-form>
|
||||
</NodeContainer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { cloneDeep, set } from 'lodash'
|
||||
import NodeContainer from '@/workflow/common/NodeContainer.vue'
|
||||
import NodeCascader from '@/workflow/common/NodeCascader.vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { isLastNode } from '@/workflow/common/data'
|
||||
import { randomId } from '@/utils/utils'
|
||||
|
||||
const props = defineProps<{ nodeModel: any }>()
|
||||
|
||||
const typeOptions = ['string', 'int', 'dict', 'array', 'float']
|
||||
|
||||
const wheel = (e: any) => {
|
||||
if (e.ctrlKey === true) {
|
||||
e.preventDefault()
|
||||
return true
|
||||
} else {
|
||||
e.stopPropagation()
|
||||
return true
|
||||
}
|
||||
}
|
||||
const form = {
|
||||
variable_list: [
|
||||
{
|
||||
id: randomId(),
|
||||
fields: [],
|
||||
value: null,
|
||||
reference: [],
|
||||
type: 'string',
|
||||
source: 'custom',
|
||||
name: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
return props.nodeModel.properties.node_data
|
||||
},
|
||||
set: (value) => {
|
||||
set(props.nodeModel.properties, 'node_data', value)
|
||||
}
|
||||
})
|
||||
|
||||
function submitDialog(val: string) {
|
||||
set(props.nodeModel.properties.node_data, 'content', val)
|
||||
}
|
||||
|
||||
const replyNodeFormRef = ref()
|
||||
const nodeCascaderRef = ref()
|
||||
const validate = async () => {
|
||||
return Promise.all([replyNodeFormRef.value?.validate()]).catch((err: any) => {
|
||||
return Promise.reject({ node: props.nodeModel, errMessage: err })
|
||||
})
|
||||
}
|
||||
|
||||
function addVariable() {
|
||||
const list = cloneDeep(props.nodeModel.properties.node_data.variable_list)
|
||||
const obj = {
|
||||
id: randomId(),
|
||||
fields: [],
|
||||
value: null,
|
||||
reference: [],
|
||||
type: 'string',
|
||||
source: 'custom',
|
||||
name: ''
|
||||
}
|
||||
list.push(obj)
|
||||
set(props.nodeModel.properties.node_data, 'variable_list', list)
|
||||
}
|
||||
|
||||
function deleteVariable(index: number) {
|
||||
const list = cloneDeep(props.nodeModel.properties.node_data.variable_list)
|
||||
list.splice(index, 1)
|
||||
set(props.nodeModel.properties.node_data, 'variable_list', list)
|
||||
}
|
||||
|
||||
function variableChange(item: any) {
|
||||
props.nodeModel.graphModel.nodes.map((node: any) => {
|
||||
if (node.id === 'start-node') {
|
||||
node.properties.config.globalFields.forEach((field: any) => {
|
||||
if (field.value === item.fields[1]) {
|
||||
item.name = field.label
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (typeof props.nodeModel.properties.node_data?.is_result === 'undefined') {
|
||||
if (isLastNode(props.nodeModel)) {
|
||||
set(props.nodeModel.properties.node_data, 'is_result', true)
|
||||
}
|
||||
}
|
||||
|
||||
set(props.nodeModel, 'validate', validate)
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
Loading…
Reference in New Issue