feat: AI工作流优化

This commit is contained in:
Lesan 2025-03-28 15:54:46 +08:00
parent 4bb52bb37d
commit 2aff972600
11 changed files with 64 additions and 70 deletions

View File

@ -63,6 +63,6 @@ public interface ErrorCodeConstants {
// ========== AI 工作流 1-040-011-000 ========== // ========== AI 工作流 1-040-011-000 ==========
ErrorCode WORKFLOW_NOT_EXISTS = new ErrorCode(1_040_011_000, "工作流不存在"); ErrorCode WORKFLOW_NOT_EXISTS = new ErrorCode(1_040_011_000, "工作流不存在");
ErrorCode WORKFLOW_KEY_EXISTS = new ErrorCode(1_040_011_001, "工作流标识已存在"); ErrorCode WORKFLOW_CODE_EXISTS = new ErrorCode(1_040_011_001, "工作流标识已存在");
} }

View File

@ -67,15 +67,6 @@ public class AiWorkflowController {
return success(BeanUtils.toBean(pageResult, AiWorkflowRespVO.class)); return success(BeanUtils.toBean(pageResult, AiWorkflowRespVO.class));
} }
// TODO @lesan要不融合到 updateWorkflow 接口
@PutMapping("/updateWorkflowModel")
@Operation(summary = "更新 AI 工作流模型")
@PreAuthorize("@ss.hasPermission('ai:workflow:update')")
public CommonResult<Boolean> updateWorkflowModel(@Valid @RequestBody AiWorkflowUpdateModelReqVO updateReqVO) {
workflowService.updateWorkflowModel(updateReqVO);
return success(true);
}
@PostMapping("/test") @PostMapping("/test")
@Operation(summary = "测试 AI 工作流") @Operation(summary = "测试 AI 工作流")
@PreAuthorize("@ss.hasPermission('ai:workflow:test')") @PreAuthorize("@ss.hasPermission('ai:workflow:test')")

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo; package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
@ -17,7 +19,11 @@ public class AiWorkflowPageReqVO extends PageParam {
private String name; private String name;
@Schema(description = "标识", example = "FLOW") @Schema(description = "标识", example = "FLOW")
private String definitionKey; private String code;
@Schema(description = "状态", example = "1")
@InEnum(CommonStatusEnum.class)
private Integer status;
@Schema(description = "创建时间") @Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

View File

@ -13,13 +13,19 @@ public class AiWorkflowRespVO {
private Long id; private Long id;
@Schema(description = "工作流标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW") @Schema(description = "工作流标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW")
private String definitionKey; private String code;
@Schema(description = "工作流名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流") @Schema(description = "工作流名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流")
private String name; private String name;
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流")
private String remark;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
@Schema(description = "工作流模型 JSON", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") @Schema(description = "工作流模型 JSON", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
private String model; private String graph;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式") @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
@Schema(description = "管理后台 - AI 工作流新增/修改 Request VO") @Schema(description = "管理后台 - AI 工作流新增/修改 Request VO")
@ -13,10 +14,21 @@ public class AiWorkflowSaveReqVO {
@Schema(description = "工作流标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW") @Schema(description = "工作流标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW")
@NotEmpty(message = "工作流标识不能为空") @NotEmpty(message = "工作流标识不能为空")
private String definitionKey; private String code;
@Schema(description = "工作流名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流") @Schema(description = "工作流名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流")
@NotEmpty(message = "工作流名称不能为空") @NotEmpty(message = "工作流名称不能为空")
private String name; private String name;
@Schema(description = "备注", example = "FLOW")
private String remark;
@Schema(description = "工作流模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
@NotEmpty(message = "工作流模型不能为空")
private String graph;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW")
@NotNull(message = "状态不能为空")
private Integer status;
} }

View File

@ -12,7 +12,7 @@ public class AiWorkflowTestReqVO {
@Schema(description = "工作流模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") @Schema(description = "工作流模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
@NotEmpty(message = "工作流模型不能为空") @NotEmpty(message = "工作流模型不能为空")
private String model; private String graph;
@Schema(description = "参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") @Schema(description = "参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
private Map<String, Object> params; private Map<String, Object> params;

View File

@ -1,18 +0,0 @@
package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
@Schema(description = "管理后台 - AI 工作流修改流程模型 Request VO")
@Data
public class AiWorkflowUpdateModelReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "工作流模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
@NotEmpty(message = "工作流模型不能为空")
private String model;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.dal.dataobject.workflow; package cn.iocoder.yudao.module.ai.dal.dataobject.workflow;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
@ -28,13 +29,23 @@ public class AiWorkflowDO extends BaseDO {
/** /**
* 工作流标识 * 工作流标识
*/ */
// TODO @lesan要不换成 code主要想 bpm 工作流有点区分字段上 private String code;
private String definitionKey;
// TODO @lesangraph 用这个如何发现大家貌似更爱用这个字段哈
/** /**
* 工作流模型 JSON 数据 * 工作流模型 JSON 数据
*/ */
private String model; private String graph;
/**
* 备注
*/
private String remark;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
} }

View File

@ -15,14 +15,16 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface AiWorkflowMapper extends BaseMapperX<AiWorkflowDO> { public interface AiWorkflowMapper extends BaseMapperX<AiWorkflowDO> {
default AiWorkflowDO selectByKey(String key) { default AiWorkflowDO selectByCode(String code) {
return selectOne(AiWorkflowDO::getDefinitionKey, key); return selectOne(AiWorkflowDO::getCode, code);
} }
default PageResult<AiWorkflowDO> selectPage(AiWorkflowPageReqVO pageReqVO) { default PageResult<AiWorkflowDO> selectPage(AiWorkflowPageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<AiWorkflowDO>() return selectPage(pageReqVO, new LambdaQueryWrapperX<AiWorkflowDO>()
.eqIfPresent(AiWorkflowDO::getStatus, pageReqVO.getStatus())
.likeIfPresent(AiWorkflowDO::getName, pageReqVO.getName()) .likeIfPresent(AiWorkflowDO::getName, pageReqVO.getName())
.likeIfPresent(AiWorkflowDO::getDefinitionKey, pageReqVO.getDefinitionKey())); .likeIfPresent(AiWorkflowDO::getCode, pageReqVO.getCode())
.betweenIfPresent(AiWorkflowDO::getCreateTime, pageReqVO.getCreateTime()));
} }
} }

View File

@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowPageReqVO; import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowPageReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowSaveReqVO; import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowSaveReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowTestReqVO; import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowTestReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowUpdateModelReqVO;
import cn.iocoder.yudao.module.ai.dal.dataobject.workflow.AiWorkflowDO; import cn.iocoder.yudao.module.ai.dal.dataobject.workflow.AiWorkflowDO;
import jakarta.validation.Valid; import jakarta.validation.Valid;
@ -53,13 +52,6 @@ public interface AiWorkflowService {
*/ */
PageResult<AiWorkflowDO> getWorkflowPage(AiWorkflowPageReqVO pageReqVO); PageResult<AiWorkflowDO> getWorkflowPage(AiWorkflowPageReqVO pageReqVO);
/**
* 修改工作流模型 JSON 数据
*
* @param updateReqVO 更新数据
*/
void updateWorkflowModel(AiWorkflowUpdateModelReqVO updateReqVO);
/** /**
* 测试 AI 工作流 * 测试 AI 工作流
* *

View File

@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowPageReqVO; import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowPageReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowSaveReqVO; import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowSaveReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowTestReqVO; import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowTestReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.AiWorkflowUpdateModelReqVO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO; import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.workflow.AiWorkflowDO; import cn.iocoder.yudao.module.ai.dal.dataobject.workflow.AiWorkflowDO;
import cn.iocoder.yudao.module.ai.dal.mysql.workflow.AiWorkflowMapper; import cn.iocoder.yudao.module.ai.dal.mysql.workflow.AiWorkflowMapper;
@ -22,7 +21,7 @@ import org.springframework.stereotype.Service;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.WORKFLOW_KEY_EXISTS; import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.WORKFLOW_CODE_EXISTS;
import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.WORKFLOW_NOT_EXISTS; import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.WORKFLOW_NOT_EXISTS;
/** /**
@ -42,16 +41,15 @@ public class AiWorkflowServiceImpl implements AiWorkflowService {
@Override @Override
public Long createWorkflow(AiWorkflowSaveReqVO createReqVO) { public Long createWorkflow(AiWorkflowSaveReqVO createReqVO) {
validateWorkflowForCreateOrUpdate(null, createReqVO.getDefinitionKey()); validateWorkflowForCreateOrUpdate(null, createReqVO.getCode());
AiWorkflowDO workflow = BeanUtils.toBean(createReqVO, AiWorkflowDO.class); AiWorkflowDO workflow = BeanUtils.toBean(createReqVO, AiWorkflowDO.class);
workflow.setModel(StrUtil.EMPTY);
workflowMapper.insert(workflow); workflowMapper.insert(workflow);
return workflow.getId(); return workflow.getId();
} }
@Override @Override
public void updateWorkflow(AiWorkflowSaveReqVO updateReqVO) { public void updateWorkflow(AiWorkflowSaveReqVO updateReqVO) {
validateWorkflowForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getDefinitionKey()); validateWorkflowForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getCode());
AiWorkflowDO workflow = BeanUtils.toBean(updateReqVO, AiWorkflowDO.class); AiWorkflowDO workflow = BeanUtils.toBean(updateReqVO, AiWorkflowDO.class);
workflowMapper.updateById(workflow); workflowMapper.updateById(workflow);
} }
@ -72,22 +70,16 @@ public class AiWorkflowServiceImpl implements AiWorkflowService {
return workflowMapper.selectPage(pageReqVO); return workflowMapper.selectPage(pageReqVO);
} }
@Override
public void updateWorkflowModel(AiWorkflowUpdateModelReqVO updateReqVO) {
validateWorkflowExists(updateReqVO.getId());
workflowMapper.updateById(new AiWorkflowDO().setId(updateReqVO.getId()).setModel(updateReqVO.getModel()));
}
@Override @Override
public Object testWorkflow(AiWorkflowTestReqVO testReqVO) { public Object testWorkflow(AiWorkflowTestReqVO testReqVO) {
Map<String, Object> variables = testReqVO.getParams(); Map<String, Object> variables = testReqVO.getParams();
Tinyflow tinyflow = parseFlowParam(testReqVO.getModel()); Tinyflow tinyflow = parseFlowParam(testReqVO.getGraph());
return tinyflow.toChain().executeForResult(variables); return tinyflow.toChain().executeForResult(variables);
} }
private void validateWorkflowForCreateOrUpdate(Long id, String key) { private void validateWorkflowForCreateOrUpdate(Long id, String code) {
validateWorkflowExists(id); validateWorkflowExists(id);
validateKeyUnique(id, key); validateCodeUnique(id, code);
} }
private void validateWorkflowExists(Long id) { private void validateWorkflowExists(Long id) {
@ -100,27 +92,27 @@ public class AiWorkflowServiceImpl implements AiWorkflowService {
} }
} }
private void validateKeyUnique(Long id, String key) { private void validateCodeUnique(Long id, String code) {
if (StrUtil.isBlank(key)) { if (StrUtil.isBlank(code)) {
return; return;
} }
AiWorkflowDO workflow = workflowMapper.selectByKey(key); AiWorkflowDO workflow = workflowMapper.selectByCode(code);
if (ObjUtil.isNull(workflow)) { if (ObjUtil.isNull(workflow)) {
return; return;
} }
if (ObjUtil.isNull(id)) { if (ObjUtil.isNull(id)) {
throw exception(WORKFLOW_KEY_EXISTS); throw exception(WORKFLOW_CODE_EXISTS);
} }
if (ObjUtil.notEqual(workflow.getId(), id)) { if (ObjUtil.notEqual(workflow.getId(), id)) {
throw exception(WORKFLOW_KEY_EXISTS); throw exception(WORKFLOW_CODE_EXISTS);
} }
} }
private Tinyflow parseFlowParam(String model) { private Tinyflow parseFlowParam(String graph) {
// TODO @lesan可以使用 jackson // TODO @lesan可以使用 jackson
JSONObject json = JSONObject.parseObject(model); JSONObject json = JSONObject.parseObject(graph);
JSONArray nodeArr = json.getJSONArray("nodes"); JSONArray nodeArr = json.getJSONArray("nodes");
Tinyflow tinyflow = new Tinyflow(json.toJSONString()); Tinyflow tinyflow = new Tinyflow(json.toJSONString());
for (int i = 0; i < nodeArr.size(); i++) { for (int i = 0; i < nodeArr.size(); i++) {
JSONObject node = nodeArr.getJSONObject(i); JSONObject node = nodeArr.getJSONObject(i);
switch (node.getString("type")) { switch (node.getString("type")) {