fix: 修复编排中引用函数,原函数更新后,编排中未同步更新
This commit is contained in:
parent
eb60a0de2e
commit
eedb1be6d8
@ -13,6 +13,7 @@ from typing import Type, Dict, List
|
||||
from django.core import cache
|
||||
from django.db.models import QuerySet
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError, ErrorDetail
|
||||
|
||||
from application.models import ChatRecord
|
||||
from application.models.api_key_model import ApplicationPublicAccessClient
|
||||
@ -123,12 +124,12 @@ class INode:
|
||||
self.err_message = ''
|
||||
self.node = node
|
||||
self.node_params = node.properties.get('node_data')
|
||||
self.workflow_params = workflow_params
|
||||
self.workflow_manage = workflow_manage
|
||||
self.node_params_serializer = None
|
||||
self.flow_params_serializer = None
|
||||
self.context = {}
|
||||
self.id = node.id
|
||||
self.valid_args(self.node_params, workflow_params)
|
||||
|
||||
def valid_args(self, node_params, flow_params):
|
||||
flow_params_serializer_class = self.get_flow_params_serializer_class()
|
||||
@ -139,6 +140,8 @@ class INode:
|
||||
if node_params_serializer_class is not None:
|
||||
self.node_params_serializer = node_params_serializer_class(data=node_params)
|
||||
self.node_params_serializer.is_valid(raise_exception=True)
|
||||
if self.node.properties.get('status', 200) != 200:
|
||||
raise ValidationError(ErrorDetail(f'节点{self.node.properties.get("stepName")} 不可用'))
|
||||
|
||||
def get_reference_field(self, fields: List[str]):
|
||||
return self.get_field(self.context, fields)
|
||||
|
||||
@ -8,11 +8,13 @@
|
||||
"""
|
||||
from typing import Type
|
||||
|
||||
from django.db.models import QuerySet
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.field.common import ObjectField
|
||||
from common.util.field_message import ErrMessage
|
||||
from function_lib.models.function import FunctionLib
|
||||
|
||||
|
||||
class InputField(serializers.Serializer):
|
||||
@ -27,6 +29,9 @@ class FunctionLibNodeParamsSerializer(serializers.Serializer):
|
||||
|
||||
def is_valid(self, *, raise_exception=False):
|
||||
super().is_valid(raise_exception=True)
|
||||
f_lib = QuerySet(FunctionLib).filter(id=self.data.get('function_lib_id')).first()
|
||||
if f_lib is None:
|
||||
raise Exception('函数库已被删除')
|
||||
|
||||
|
||||
class IFunctionLibNode(INode):
|
||||
|
||||
@ -19,6 +19,7 @@ from application.flow import tools
|
||||
from application.flow.i_step_node import INode, WorkFlowPostHandler, NodeResult
|
||||
from application.flow.step_node import get_node
|
||||
from common.exception.app_exception import AppApiException
|
||||
from function_lib.models.function import FunctionLib
|
||||
from setting.models import Model
|
||||
from setting.models_provider import get_model_credential
|
||||
|
||||
@ -142,6 +143,13 @@ class Flow:
|
||||
model_params_setting = model_params_setting_form.get_default_form_data()
|
||||
node.properties.get('node_data', {})['model_params_setting'] = model_params_setting
|
||||
model_params_setting_form.valid_form(model_params_setting)
|
||||
if node.properties.get('status', 200) != 200:
|
||||
raise ValidationError(ErrorDetail(f'节点{node.properties.get("stepName")} 不可用'))
|
||||
node_list = [node for node in self.nodes if (node.type == 'function-lib-node')]
|
||||
for node in node_list:
|
||||
f_lib = QuerySet(FunctionLib).filter(id=node.properties.get('function_lib_id')).first()
|
||||
if f_lib is None:
|
||||
raise ValidationError(ErrorDetail(f'节点{node.properties.get("stepName")} 函数库不可用'))
|
||||
|
||||
def is_valid_base_node(self):
|
||||
base_node_list = [node for node in self.nodes if node.id == 'base-node']
|
||||
@ -171,6 +179,7 @@ class WorkflowManage:
|
||||
try:
|
||||
while self.has_next_node(self.current_result):
|
||||
self.current_node = self.get_next_node()
|
||||
self.current_node.valid_args(self.current_node.node_params, self.current_node.workflow_params)
|
||||
self.node_context.append(self.current_node)
|
||||
self.current_result = self.current_node.run()
|
||||
result = self.current_result.write_context(self.current_node, self)
|
||||
@ -193,6 +202,7 @@ class WorkflowManage:
|
||||
while self.has_next_node(self.current_result):
|
||||
self.current_node = self.get_next_node()
|
||||
self.node_context.append(self.current_node)
|
||||
self.current_node.valid_args(self.current_node.node_params, self.current_node.workflow_params)
|
||||
self.current_result = self.current_node.run()
|
||||
result = self.current_result.write_context(self.current_node, self)
|
||||
if result is not None:
|
||||
|
||||
@ -80,6 +80,15 @@ class FunctionLibView(APIView):
|
||||
return result.success(
|
||||
FunctionLibSerializer.Operate(data={'user_id': request.user.id, 'id': function_lib_id}).delete())
|
||||
|
||||
@action(methods=['GET'], detail=False)
|
||||
@swagger_auto_schema(operation_summary="获取函数详情",
|
||||
operation_id="获取函数详情",
|
||||
tags=['函数库'])
|
||||
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
|
||||
def get(self, request: Request, function_lib_id: str):
|
||||
return result.success(
|
||||
FunctionLibSerializer.Operate(data={'user_id': request.user.id, 'id': function_lib_id}).one())
|
||||
|
||||
class Page(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
|
||||
@ -83,6 +83,18 @@ const delFunctionLib: (
|
||||
) => Promise<Result<boolean>> = (function_lib_id, loading) => {
|
||||
return del(`${prefix}/${function_lib_id}`, undefined, {}, loading)
|
||||
}
|
||||
/**
|
||||
* 获取函数详情
|
||||
* @param function_lib_id 函数id
|
||||
* @param loading 加载器
|
||||
* @returns 函数详情
|
||||
*/
|
||||
const getFunctionLibById: (
|
||||
function_lib_id: String,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (function_lib_id, loading) => {
|
||||
return get(`${prefix}/${function_lib_id}`, undefined, loading)
|
||||
}
|
||||
|
||||
export default {
|
||||
getFunctionLib,
|
||||
@ -90,5 +102,6 @@ export default {
|
||||
putFunctionLib,
|
||||
postFunctionLibDebug,
|
||||
getAllFunctionLib,
|
||||
delFunctionLib
|
||||
delFunctionLib,
|
||||
getFunctionLibById
|
||||
}
|
||||
|
||||
@ -256,7 +256,14 @@ function clickNodes(item: any, data?: any) {
|
||||
function onmousedown(item: any, data?: any) {
|
||||
if (data) {
|
||||
item['properties']['stepName'] = data.name
|
||||
item['properties']['node_data'] = { ...data, function_lib_id: data.id }
|
||||
item['properties']['node_data'] = {
|
||||
...data,
|
||||
function_lib_id: data.id,
|
||||
input_field_list: data.input_field_list.map((field: any) => ({
|
||||
...field,
|
||||
value: field.source == 'reference' ? [] : ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
workflowRef.value?.onmousedown(item)
|
||||
showPopover.value = false
|
||||
|
||||
@ -60,15 +60,13 @@ const open = (model_id: string, model_setting_data?: any) => {
|
||||
}
|
||||
|
||||
const reset_default = (model_id: string) => {
|
||||
form_data.value = {}
|
||||
modelAPi.getModelParamsForm(model_id, loading).then((ok) => {
|
||||
model_form_field.value = ok.data
|
||||
const model_setting_data = ok.data
|
||||
.map((item) => ({ [item.field]: item.default_value }))
|
||||
.reduce((x, y) => ({ ...x, ...y }), {})
|
||||
// 渲染动态表单
|
||||
dynamicsFormRef.value?.render(model_form_field.value, model_setting_data)
|
||||
emit('refresh', form_data.value)
|
||||
|
||||
emit('refresh', model_setting_data)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,10 @@
|
||||
>
|
||||
<div v-resize="resizeStepContainer">
|
||||
<div class="flex-between mb-16">
|
||||
<div class="flex align-center" style="max-width: 90%">
|
||||
<div
|
||||
class="flex align-center"
|
||||
:style="{ maxWidth: node_status == 200 ? 'calc(100% - 55px)' : 'calc(100% - 85px)' }"
|
||||
>
|
||||
<component :is="iconComponent(`${nodeModel.type}-icon`)" class="mr-8" :size="24" />
|
||||
<h4 v-if="showOperate(nodeModel.type)" style="max-width: 90%">
|
||||
<ReadWrite
|
||||
@ -22,6 +25,7 @@
|
||||
</h4>
|
||||
<h4 v-else>{{ nodeModel.properties.stepName }}</h4>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@mousemove.stop
|
||||
@mousedown.stop
|
||||
@ -29,6 +33,9 @@
|
||||
@click.stop
|
||||
v-if="showOperate(nodeModel.type)"
|
||||
>
|
||||
<el-tag type="danger" v-if="node_status != 200" style="margin-right: 8px"
|
||||
>不可用</el-tag
|
||||
>
|
||||
<el-dropdown :teleported="false" trigger="click">
|
||||
<el-button text>
|
||||
<el-icon class="color-secondary"><MoreFilled /></el-icon>
|
||||
@ -73,7 +80,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { set } from 'lodash'
|
||||
import { iconComponent } from '../icons/utils'
|
||||
import { copyClick } from '@/utils/clipboard'
|
||||
@ -89,8 +96,12 @@ const height = ref<{
|
||||
outputContainerHeight: 0
|
||||
})
|
||||
|
||||
const showEditIcon = ref(false)
|
||||
|
||||
const node_status = computed(() => {
|
||||
if (props.nodeModel.properties.status) {
|
||||
return props.nodeModel.properties.status
|
||||
}
|
||||
return 200
|
||||
})
|
||||
function editName(val: string) {
|
||||
if (val.trim() && val.trim() !== props.nodeModel.properties.stepName) {
|
||||
if (
|
||||
|
||||
@ -138,5 +138,8 @@ export class WorkFlowInstance {
|
||||
throw `${node.properties.stepName} 节点不能连接俩个节点`
|
||||
}
|
||||
}
|
||||
if (node.properties.status && node.properties.status !== 200) {
|
||||
throw `${node.properties.stepName} 节点不可用`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
>
|
||||
<el-card shadow="never" class="card-never mb-16" style="--el-card-padding: 12px">
|
||||
<div v-if="chat_data.input_field_list?.length > 0">
|
||||
<template v-for="(item, index) in chat_data.input_field_list" :key="index">
|
||||
<template v-for="(item, index) in chat_data.input_field_list" :key="item.name">
|
||||
<el-form-item
|
||||
:label="item.name"
|
||||
:prop="'input_field_list.' + index + '.value'"
|
||||
@ -80,7 +80,7 @@ import NodeCascader from '@/workflow/common/NodeCascader.vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { isLastNode } from '@/workflow/common/data'
|
||||
|
||||
import functionLibApi from '@/api/function-lib'
|
||||
const props = defineProps<{ nodeModel: any }>()
|
||||
|
||||
const nodeCascaderRef = ref()
|
||||
@ -112,12 +112,33 @@ const validate = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const update_field = () => {
|
||||
functionLibApi
|
||||
.getFunctionLibById(props.nodeModel.properties.node_data.function_lib_id)
|
||||
.then((ok) => {
|
||||
const old_input_field_list = props.nodeModel.properties.node_data.input_field_list
|
||||
const merge_input_field_list = ok.data.input_field_list.map((item: any) => {
|
||||
const find_field = old_input_field_list.find((old_item: any) => old_item.name == item.name)
|
||||
if (find_field && find_field.source == item.source) {
|
||||
return { ...item, value: JSON.parse(JSON.stringify(find_field.value)) }
|
||||
}
|
||||
return { ...item, value: item.source == 'reference' ? [] : '' }
|
||||
})
|
||||
set(props.nodeModel.properties.node_data, 'input_field_list', merge_input_field_list)
|
||||
set(props.nodeModel.properties, 'status', 200)
|
||||
})
|
||||
.catch((err) => {
|
||||
set(props.nodeModel.properties, 'status', 500)
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (typeof props.nodeModel.properties.node_data?.is_result === 'undefined') {
|
||||
if (isLastNode(props.nodeModel)) {
|
||||
set(props.nodeModel.properties.node_data, 'is_result', true)
|
||||
}
|
||||
}
|
||||
update_field()
|
||||
set(props.nodeModel, 'validate', validate)
|
||||
})
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user