From 05a9260eb19a7489d0b5fa225615a08cd030dcb9 Mon Sep 17 00:00:00 2001 From: CJL6015 <1253368419@qq.com> Date: Sun, 30 Nov 2025 18:11:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(alert):=20=E5=AE=9E=E7=8E=B0=E8=AF=84?= =?UTF-8?q?=E4=BC=B0=E6=8A=A5=E5=91=8A=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增评估报告列表查询接口,支持按模型ID、版本和有效性过滤 - 新增算法评估配置查询接口,获取底线分数等条件 - 新增旧表 Assess_Report_CFG 兼容插入接口 - 新增评估报告名称查询接口,按模型ID和版本生成RV+时间格式名称 - 修改评估结果响应VO字段类型,durationSeconds、coverage等改为Double并设置默认值 - 完善模型下装逻辑,增加评估报告校验和版本关联 - 新增模型草稿版本创建和历史版本列表查询功能 - 优化模型信息查询,支持指定版本读取 - 增强JSON序列化配置,添加字段别名支持 - 更新相关实体类和Mapper定义 --- .../yudao-module-alert-biz/pom.xml | 6 + .../assessreport/AssessReportController.java | 37 ++++ .../vo/AssessConditionRespVO.java | 13 ++ .../assessreport/vo/AssessEvaluateRespVO.java | 6 +- .../vo/AssessReportCreateReqVO.java | 3 + .../vo/AssessReportNameRespVO.java | 17 ++ .../vo/AssessReportSimpleRespVO.java | 35 ++++ .../admin/model/ModelController.java | 34 +++- .../admin/model/model/ModelInfo.java | 6 +- .../controller/admin/model/model/Point.java | 10 +- .../admin/model/vo/BottomModelReqVO.java | 15 ++ .../admin/model/vo/ModelSimpleVO.java | 5 + .../admin/model/vo/ModelVersionSimpleVO.java | 16 ++ .../controller/admin/model/vo/TrainInfo.java | 6 + .../dataobject/model/ModelConditionDO.java | 22 +++ .../dal/mysql/model/ModelConditionMapper.java | 9 + .../alert/dao/domain/AssessReportCfg.java | 49 +++++ .../module/alert/dao/domain/ModelVersion.java | 5 +- .../dao/mapper/AssessReportCfgMapper.java | 18 ++ .../alert/dao/mapper/ModelVersionMapper.java | 4 +- .../dao/service/AssessReportCfgService.java | 13 ++ .../dao/service/ModelVersionService.java | 4 +- .../impl/AssessReportCfgServiceImpl.java | 22 +++ .../service/impl/ModelVersionServiceImpl.java | 4 +- .../assessreport/AssessReportService.java | 20 ++ .../impl/AssessReportServiceImpl.java | 180 ++++++++++++++++-- .../alert/service/model/ModelService.java | 20 +- .../service/model/impl/ModelServiceImpl.java | 131 ++++++++++++- .../dao/mapper/AssessReportCfgMapper.xml | 33 ++++ .../alert/dao/mapper/ModelVersionMapper.xml | 45 +++++ 30 files changed, 745 insertions(+), 43 deletions(-) create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessConditionRespVO.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportNameRespVO.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportSimpleRespVO.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/BottomModelReqVO.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelVersionSimpleVO.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/dataobject/model/ModelConditionDO.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/model/ModelConditionMapper.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/AssessReportCfg.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/AssessReportCfgService.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/AssessReportCfgServiceImpl.java create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.xml create mode 100644 yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.xml diff --git a/yudao-module-alert/yudao-module-alert-biz/pom.xml b/yudao-module-alert/yudao-module-alert-biz/pom.xml index f225cdc..31e5143 100644 --- a/yudao-module-alert/yudao-module-alert-biz/pom.xml +++ b/yudao-module-alert/yudao-module-alert-biz/pom.xml @@ -68,6 +68,12 @@ 2.4.2-SNAPSHOT compile + + org.apache.httpcomponents + httpclient + 4.5.14 + compile + diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/AssessReportController.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/AssessReportController.java index 2c6401e..0be29c8 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/AssessReportController.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/AssessReportController.java @@ -7,6 +7,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + /** * 评估报告相关接口(从旧 GetData.asmx 迁移) */ @@ -49,6 +51,24 @@ public class AssessReportController { return CommonResult.success(assessReportService.save(reqVO)); } + /** + * 获取评估报告列表(供下装选择) + */ + @GetMapping("/list") + public CommonResult> list(@RequestParam Integer modelId, + @RequestParam(required = false) String version, + @RequestParam(required = false, defaultValue = "true") Boolean valid) { + return CommonResult.success(assessReportService.list(modelId, version, valid)); + } + + /** + * 获取算法对应的评估配置(底线分数等) + */ + @GetMapping("/condition") + public CommonResult condition(@RequestParam String algorithm) { + return CommonResult.success(assessReportService.getCondition(algorithm)); + } + /** * 数据清洗概要信息 */ @@ -56,4 +76,21 @@ public class AssessReportController { public CommonResult cleanSummary(@Validated AssessCleanQueryReqVO reqVO) { return CommonResult.success(assessReportService.cleanSummary(reqVO)); } + + /** + * 兼容旧表 Assess_Report_CFG 的插入 + */ + @PostMapping("/legacy") + public CommonResult insertLegacy(@RequestBody @Validated AssessReportCreateReqVO reqVO) { + return CommonResult.success(assessReportService.insertLegacyReport(reqVO)); + } + + /** + * 查询评估报告名称(按模型ID和版本,从 Assess_Report_CFG 生成 RV+时间) + */ + @GetMapping("/name") + public CommonResult> listNames(@RequestParam Integer modelId, + @RequestParam(required = false) String version) { + return CommonResult.success(assessReportService.listReportNames(modelId, version)); + } } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessConditionRespVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessConditionRespVO.java new file mode 100644 index 0000000..47245cd --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessConditionRespVO.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.alert.controller.admin.assessreport.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class AssessConditionRespVO { + @Schema(description = "模型底线分数") + private Double modelScore; + + @Schema(description = "条件配置原文") + private String condition; +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessEvaluateRespVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessEvaluateRespVO.java index b5f6996..176a025 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessEvaluateRespVO.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessEvaluateRespVO.java @@ -12,11 +12,11 @@ public class AssessEvaluateRespVO { private List points; @Schema(description = "评估耗时秒") - private Long durationSeconds; + private Double durationSeconds = 0d; @Schema(description = "覆盖率") - private Double coverage; + private Double coverage = 0d; @Schema(description = "清洗耗时秒") - private Long cleanDurationSeconds; + private Double cleanDurationSeconds = 0d; } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportCreateReqVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportCreateReqVO.java index 4d99183..b7ecd4c 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportCreateReqVO.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportCreateReqVO.java @@ -46,4 +46,7 @@ public class AssessReportCreateReqVO { @Schema(description = "模式名称") private String conditionName; + + @Schema(description = "原始报告JSON串(旧表插入用)") + private String rawReport; } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportNameRespVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportNameRespVO.java new file mode 100644 index 0000000..c33b32f --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportNameRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.alert.controller.admin.assessreport.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 评估报告名称响应 + */ +@Data +public class AssessReportNameRespVO { + + @Schema(description = "报告ID") + private Long id; + + @Schema(description = "报告名称,格式 RV<时间>,如 RV2025-11-30T13:57:36") + private String name; +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportSimpleRespVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportSimpleRespVO.java new file mode 100644 index 0000000..503886a --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/assessreport/vo/AssessReportSimpleRespVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.alert.controller.admin.assessreport.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 评估报告精简信息(下装选择使用) + */ +@Data +public class AssessReportSimpleRespVO { + + private Integer id; + + @Schema(description = "报告得分") + private Double score; + + @Schema(description = "覆盖面") + private Double coverRange; + + @Schema(description = "是否有效(已通过验证)") + private Boolean validFlag; + + private String identifier; + + private String verifier; + + @Schema(description = "评估时间") + private String assessTime; + + private String version; + + private String conditionName; +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/ModelController.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/ModelController.java index ea241a0..4eea310 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/ModelController.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/ModelController.java @@ -32,8 +32,9 @@ public class ModelController { } @GetMapping("info/{id}") - public CommonResult getModelInfo(@PathVariable Integer id) { - ModelInfoVO modelInfo = modelService.getModelInfo(id); + public CommonResult getModelInfo(@PathVariable Integer id, + @RequestParam(required = false) String version) { + ModelInfoVO modelInfo = modelService.getModelInfo(id, version); return CommonResult.success(modelInfo); } @@ -68,8 +69,33 @@ public class ModelController { return CommonResult.success(modelTestData); } + /** + * 创建草稿版本(v-test) + */ + @PostMapping("/version/new/{id}") + public CommonResult createDraft(@PathVariable Integer id) { + try { + return CommonResult.success(modelService.createDraftVersion(id)); + } catch (Exception e) { + return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), e.getMessage()); + } + } + + /** + * 版本列表 + */ + @GetMapping("/version/{id}") + public CommonResult> listVersions(@PathVariable Integer id) { + return CommonResult.success(modelService.listVersions(id)); + } + @PostMapping("/bottom/{id}") - public CommonResult bottomModel(@PathVariable Integer id) { - return CommonResult.success(modelService.bottomModel(id)); + public CommonResult bottomModel(@PathVariable Integer id, @RequestBody(required = false) BottomModelReqVO reqVO) { + try { + Long reportId = reqVO != null ? reqVO.getReportId() : null; + return CommonResult.success(modelService.bottomModel(id, reportId)); + } catch (Exception e) { + return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), e.getMessage()); + } } } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/ModelInfo.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/ModelInfo.java index 6d5453a..2ff67c2 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/ModelInfo.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/ModelInfo.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.alert.controller.admin.model.model; import cn.iocoder.yudao.module.alert.common.enums.Algorithm; -import cn.iocoder.yudao.module.alert.controller.admin.model.vo.ModelInfoVO; import cn.iocoder.yudao.module.alert.controller.admin.model.vo.TrainInfo; +import com.alibaba.fastjson.annotation.JSONField; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @@ -88,10 +88,12 @@ public class ModelInfo { private String unit; @JsonProperty("versionNumber") + private Integer versionNumber; @JsonProperty("alarmmodelset") + @JSONField(name = "alarmmodelset") private AlarmModelSet alarmModelSet; @JsonProperty("para") @@ -115,7 +117,7 @@ public class ModelInfo { private String alarmCondition; public static AlarmModelSet defaultInit() { - return new AlarmModelSet("全工况运行", "1==1"); + return new AlarmModelSet("全工况运行", "1=1"); } } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/Point.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/Point.java index 5d360f9..7a18bc4 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/Point.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/model/Point.java @@ -25,7 +25,7 @@ public class Point { private BigDecimal Upper; private Boolean dead; private Boolean limit; - private Boolean lock; + private Boolean lock = false; /** * 残差下限 */ @@ -34,12 +34,20 @@ public class Point { * 残差上限 */ private BigDecimal upperBound; + @JsonProperty("TMax") private BigDecimal TMax; + @JsonProperty("TMin") private BigDecimal TMin; + @JsonProperty("TAvg") private BigDecimal TAvg; + @JsonProperty("DMax") private BigDecimal DMax; + @JsonProperty("DMin") private BigDecimal DMin; + @JsonProperty("DAvg") private BigDecimal DAvg; + @JsonProperty("C95") private BigDecimal C95; + @JsonProperty("C99") private BigDecimal C99; } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/BottomModelReqVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/BottomModelReqVO.java new file mode 100644 index 0000000..2135dd9 --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/BottomModelReqVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.alert.controller.admin.model.vo; + +import lombok.Data; + +/** + * 模型下装请求参数 + */ +@Data +public class BottomModelReqVO { + + /** + * 评估报告ID(需已通过验证) + */ + private Long reportId; +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelSimpleVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelSimpleVO.java index 58e820e..844bc4c 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelSimpleVO.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelSimpleVO.java @@ -35,6 +35,11 @@ public class ModelSimpleVO { */ private String creator; + /** + * 当前版本 + */ + private String version; + /** * 模型状态 */ diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelVersionSimpleVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelVersionSimpleVO.java new file mode 100644 index 0000000..11de1e0 --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/ModelVersionSimpleVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.alert.controller.admin.model.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 模型版本精简信息 + */ +@Data +public class ModelVersionSimpleVO { + private String version; + private Date createTime; + private Integer status; + private String conditionName; +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/TrainInfo.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/TrainInfo.java index a5e2ec5..97d2668 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/TrainInfo.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/model/vo/TrainInfo.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.alert.controller.admin.model.vo; +import com.alibaba.fastjson.annotation.JSONField; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; @@ -10,17 +11,22 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class TrainInfo { @JsonProperty("Model_info") + @JSONField(name = "Model_info") private ModelInfoDetails modelInfo; @JsonProperty("Model_type") + @JSONField(name = "Model_type") private String modelType; @JsonProperty("BeforeCleanSamNum") + @JSONField(name = "BeforeCleanSamNum") private int beforeCleanSamNum; @JsonProperty("AfterCleanSamNum") + @JSONField(name = "AfterCleanSamNum") private int afterCleanSamNum; @JsonProperty("CleanOrNot") + @JSONField(name = "CleanOrNot") private boolean cleanOrNot; } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/dataobject/model/ModelConditionDO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/dataobject/model/ModelConditionDO.java new file mode 100644 index 0000000..187010c --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/dataobject/model/ModelConditionDO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.alert.dal.dataobject.model; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 对应表:model_condition + */ +@Data +@TableName("model_condition") +public class ModelConditionDO { + + @TableId + private Long id; + + private String algorithm; + + @TableField("`condition`") + private String condition; +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/model/ModelConditionMapper.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/model/ModelConditionMapper.java new file mode 100644 index 0000000..9ba602e --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/model/ModelConditionMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.alert.dal.mysql.model; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.alert.dal.dataobject.model.ModelConditionDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ModelConditionMapper extends BaseMapperX { +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/AssessReportCfg.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/AssessReportCfg.java new file mode 100644 index 0000000..b433b40 --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/AssessReportCfg.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.alert.dao.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.util.Date; +import lombok.Data; + +/** + * @TableName assess_report_cfg + */ +@TableName(value ="assess_report_cfg") +@Data +public class AssessReportCfg { + private Integer id; + + private Integer modelId; + + private String version; + + private String report; + + private Double score; + + private Double coverRange; + + private String valid; + + private String identifier; + + private String verifier; + + private Date time; + + private Integer status; + + private String conditionName; + + private String creator; + + private Date createTime; + + private String updater; + + private Date updateTime; + + private Boolean deleted; +} \ No newline at end of file diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/ModelVersion.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/ModelVersion.java index f54eeda..fb1dda4 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/ModelVersion.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/domain/ModelVersion.java @@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import java.io.Serializable; import java.util.Date; import lombok.Data; @@ -13,7 +12,7 @@ import lombok.Data; */ @TableName(value ="model_version") @Data -public class ModelVersion implements Serializable { +public class ModelVersion { private Integer id; private Integer modelId; @@ -67,6 +66,4 @@ public class ModelVersion implements Serializable { private Date updateTime; private Boolean deleted; - - private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.java new file mode 100644 index 0000000..96232fe --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.alert.dao.mapper; + +import cn.iocoder.yudao.module.alert.dao.domain.AssessReportCfg; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author cjl60 +* @description 针对表【assess_report_cfg】的数据库操作Mapper +* @createDate 2025-11-30 11:58:22 +* @Entity cn.iocoder.yudao.module.alert.dao.domain.AssessReportCfg +*/ +public interface AssessReportCfgMapper extends BaseMapper { + +} + + + + diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.java index e71e457..cd88366 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.java @@ -4,9 +4,9 @@ import cn.iocoder.yudao.module.alert.dao.domain.ModelVersion; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** -* @author 陈小黑 +* @author cjl60 * @description 针对表【model_version】的数据库操作Mapper -* @createDate 2025-07-10 16:23:38 +* @createDate 2025-11-30 09:14:52 * @Entity cn.iocoder.yudao.module.alert.dao.domain.ModelVersion */ public interface ModelVersionMapper extends BaseMapper { diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/AssessReportCfgService.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/AssessReportCfgService.java new file mode 100644 index 0000000..ea5fd95 --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/AssessReportCfgService.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.alert.dao.service; + +import cn.iocoder.yudao.module.alert.dao.domain.AssessReportCfg; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author cjl60 +* @description 针对表【assess_report_cfg】的数据库操作Service +* @createDate 2025-11-30 11:58:22 +*/ +public interface AssessReportCfgService extends IService { + +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/ModelVersionService.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/ModelVersionService.java index 246ed07..c1a1778 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/ModelVersionService.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/ModelVersionService.java @@ -4,9 +4,9 @@ import cn.iocoder.yudao.module.alert.dao.domain.ModelVersion; import com.baomidou.mybatisplus.extension.service.IService; /** -* @author 陈小黑 +* @author cjl60 * @description 针对表【model_version】的数据库操作Service -* @createDate 2025-07-10 16:23:38 +* @createDate 2025-11-30 09:14:52 */ public interface ModelVersionService extends IService { diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/AssessReportCfgServiceImpl.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/AssessReportCfgServiceImpl.java new file mode 100644 index 0000000..e54171b --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/AssessReportCfgServiceImpl.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.alert.dao.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import cn.iocoder.yudao.module.alert.dao.domain.AssessReportCfg; +import cn.iocoder.yudao.module.alert.dao.service.AssessReportCfgService; +import cn.iocoder.yudao.module.alert.dao.mapper.AssessReportCfgMapper; +import org.springframework.stereotype.Service; + +/** +* @author cjl60 +* @description 针对表【assess_report_cfg】的数据库操作Service实现 +* @createDate 2025-11-30 11:58:22 +*/ +@Service +public class AssessReportCfgServiceImpl extends ServiceImpl + implements AssessReportCfgService{ + +} + + + + diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/ModelVersionServiceImpl.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/ModelVersionServiceImpl.java index 2805d0a..b3c2a3b 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/ModelVersionServiceImpl.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dao/service/impl/ModelVersionServiceImpl.java @@ -7,9 +7,9 @@ import cn.iocoder.yudao.module.alert.dao.mapper.ModelVersionMapper; import org.springframework.stereotype.Service; /** -* @author 陈小黑 +* @author cjl60 * @description 针对表【model_version】的数据库操作Service实现 -* @createDate 2025-07-10 16:23:38 +* @createDate 2025-11-30 09:14:52 */ @Service public class ModelVersionServiceImpl extends ServiceImpl diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/AssessReportService.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/AssessReportService.java index 83a79a1..715d436 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/AssessReportService.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/AssessReportService.java @@ -13,4 +13,24 @@ public interface AssessReportService { Boolean save(AssessReportCreateReqVO reqVO); AssessCleanSummaryVO cleanSummary(AssessCleanQueryReqVO reqVO); + + /** + * 获取模型的评估报告列表(可按版本、有效性过滤) + */ + java.util.List list(Integer modelId, String version, Boolean onlyValid); + + /** + * 获取算法对应的评估配置(底线分数/规则) + */ + AssessConditionRespVO getCondition(String algorithm); + + /** + * 兼容旧表 Assess_Report_CFG 的插入 + */ + Boolean insertLegacyReport(AssessReportCreateReqVO reqVO); + + /** + * 按模型ID和版本查询报告名称列表(从 Assess_Report_CFG 生成 RV+时间) + */ + java.util.List listReportNames(Integer modelId, String version); } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/impl/AssessReportServiceImpl.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/impl/AssessReportServiceImpl.java index 2396546..1943044 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/impl/AssessReportServiceImpl.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/assessreport/impl/AssessReportServiceImpl.java @@ -7,16 +7,22 @@ import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.alert.controller.admin.assessreport.vo.*; import cn.iocoder.yudao.module.alert.dao.domain.ModelCfg; +import cn.iocoder.yudao.module.alert.dao.domain.AssessReportCfg; import cn.iocoder.yudao.module.alert.dao.domain.ModelVersion; +import cn.iocoder.yudao.module.alert.dao.mapper.AssessReportCfgMapper; import cn.iocoder.yudao.module.alert.dao.service.ModelCfgService; import cn.iocoder.yudao.module.alert.dao.service.ModelVersionService; import cn.iocoder.yudao.module.alert.dal.dataobject.assessreport.AssessReportDO; import cn.iocoder.yudao.module.alert.dal.mysql.assessreport.AssessReportMapper; +import cn.iocoder.yudao.module.alert.dal.dataobject.model.ModelConditionDO; +import cn.iocoder.yudao.module.alert.dal.mysql.model.ModelConditionMapper; import cn.iocoder.yudao.module.alert.service.assessreport.AssessReportService; import com.alibaba.excel.util.DateUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.fasterxml.jackson.core.type.TypeReference; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -24,8 +30,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.time.Duration; -import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @@ -38,6 +42,8 @@ public class AssessReportServiceImpl implements AssessReportService { private final ModelCfgService modelCfgService; private final ModelVersionService modelVersionService; private final AssessReportMapper assessReportMapper; + private final AssessReportCfgMapper assessReportCfgMapper; + private final ModelConditionMapper modelConditionMapper; @Value("${assess-report.host}") private String algorithmHost; @Value("${exa.ip:}") @@ -52,7 +58,8 @@ public class AssessReportServiceImpl implements AssessReportService { } String targetVersion = StringUtils.hasText(reqVO.getVersion()) ? reqVO.getVersion() : modelCfg.getCurVersion(); String modelInfoStr = resolveModelInfo(modelCfg, targetVersion); - Map modelInfo = JsonUtils.parseObject(modelInfoStr, new TypeReference>() {}); + Map modelInfo = JsonUtils.parseObject(modelInfoStr, new TypeReference>() { + }); List pointRows = buildPointRows(modelInfo); List assessRows = buildAssessRows(pointRows); AssessInitRespVO respVO = new AssessInitRespVO(); @@ -71,14 +78,15 @@ public class AssessReportServiceImpl implements AssessReportService { @Override public AssessReportDetailVO getReportDetail(Long id) { - AssessReportDO report = assessReportMapper.selectById(id); + AssessReportCfg report = assessReportCfgMapper.selectById(id); if (report == null) { return null; } AssessReportDetailVO vo = new AssessReportDetailVO(); vo.setId(id); - vo.setModelName(report.getModelName()); - vo.setReport(JsonUtils.parseObject(report.getReportJson(), new TypeReference>() {})); + vo.setModelName(null); + vo.setReport(JsonUtils.parseObject(report.getReport(), new TypeReference>() { + })); return vo; } @@ -91,7 +99,8 @@ public class AssessReportServiceImpl implements AssessReportService { String modelInfoStr = StringUtils.hasText(reqVO.getModelInfo()) ? reqVO.getModelInfo() : resolveModelInfo(modelCfg, reqVO.getVersion()); - Map modelInfo = JsonUtils.parseObject(modelInfoStr, new TypeReference>() {}); + Map modelInfo = JsonUtils.parseObject(modelInfoStr, new TypeReference>() { + }); // 使用旧版逻辑:解析 json,拆分幅值,构造单点 assess 列表,调用对应算法接口 String json = StringUtils.hasText(reqVO.getRawJson()) ? reqVO.getRawJson() @@ -138,12 +147,20 @@ public class AssessReportServiceImpl implements AssessReportService { String endpoint = "/api/" + alg + "/assess_PositiveAndNegative"; String tempAll = HttpUtils.post(algorithmHost + endpoint, null, JsonUtils.toJsonString(assessInput)); + // 部分算法返回 {"result":"{...}"},需要先拆出 result,再解析内部 JSON + Map rawMap = JsonUtils.parseObject(tempAll, new TypeReference>() { + }); + String payload = tempAll; + if (rawMap != null && rawMap.containsKey("result") && rawMap.get("result") instanceof String) { + payload = rawMap.get("result").toString(); + } + AssessEvaluateRespVO respVO = new AssessEvaluateRespVO(); - AssessAllMessage message = JsonUtils.parseObject(tempAll, AssessAllMessage.class); + AssessAllMessage message = JsonUtils.parseObject(payload, AssessAllMessage.class); if (message != null && "OK".equalsIgnoreCase(message.getMessage())) { - AssessAll trAll = JsonUtils.parseObject(tempAll, AssessAll.class); + AssessAll trAll = JsonUtils.parseObject(payload, AssessAll.class); TestReturn tr2 = toTestReturn(trAll.getPositive()); - TestReturn tr1 = toTestReturn(trAll.getNegative()); + TestReturn tr1 = toTestReturn(trAll.getNegative() != null ? trAll.getNegative() : trAll.getPositive()); int returnIndex1 = 0; for (int i = 0; i < limit.length; i++) { if (indexList[i]) { @@ -171,12 +188,16 @@ public class AssessReportServiceImpl implements AssessReportService { } } respVO.setPoints(mapAssessResultByIndex(reqVO.getAssessRows(), tr)); - respVO.setCleanDurationSeconds(message.getCleanTime()); - respVO.setDurationSeconds(message.getAssessTime()); + respVO.setCleanDurationSeconds(message.getCleanTime() != null ? message.getCleanTime() : 0d); + respVO.setDurationSeconds(message.getAssessTime() != null ? message.getAssessTime() : 0d); } else { throw new RuntimeException(tempAll); } - respVO.setCoverage(mt.getCoverage()); + Double cov = mt.getCoverage(); + if (cov == null) { + cov = fetchCoverage(modelInfo); + } + respVO.setCoverage(cov == null ? 0d : cov); return respVO; } @@ -198,6 +219,23 @@ public class AssessReportServiceImpl implements AssessReportService { return assessReportMapper.insert(reportDO) > 0; } + @Override + public Boolean insertLegacyReport(AssessReportCreateReqVO reqVO) { + AssessReportCfg reportDO = new AssessReportCfg(); + reportDO.setModelId(reqVO.getModelId()); + reportDO.setVersion(reqVO.getVersion()); + reportDO.setReport(reqVO.getRawReport() != null ? reqVO.getRawReport() : JsonUtils.toJsonString(reqVO.getReport())); + reportDO.setScore(reqVO.getScore() != null ? reqVO.getScore().doubleValue() : null); + reportDO.setCoverRange(reqVO.getCoverage() != null ? reqVO.getCoverage().doubleValue() : null); + reportDO.setValid(Boolean.TRUE.equals(reqVO.getValid()) ? "是" : "否"); + reportDO.setIdentifier(reqVO.getIdentifier()); + reportDO.setVerifier(reqVO.getVerifier()); + // 旧表 time 为 Date,尝试解析 yyyy-MM-dd HH:mm:ss,失败则不设置 + reportDO.setStatus(0); + reportDO.setConditionName(reqVO.getConditionName()); + return assessReportCfgMapper.insert(reportDO) > 0; + } + @Override public AssessCleanSummaryVO cleanSummary(AssessCleanQueryReqVO reqVO) { // 这里先返回空壳,后续可对接 EXA / Python 服务 @@ -218,6 +256,76 @@ public class AssessReportServiceImpl implements AssessReportService { return vo; } + @Override + public List list(Integer modelId, String version, Boolean onlyValid) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(AssessReportCfg.class) + .eq(AssessReportCfg::getModelId, modelId) + .eq(StringUtils.hasText(version), AssessReportCfg::getVersion, version) + .eq(Boolean.TRUE.equals(onlyValid), AssessReportCfg::getValid, "是") + .orderByDesc(AssessReportCfg::getCreateTime); + List reports = assessReportCfgMapper.selectList(wrapper); + if (CollectionUtils.isEmpty(reports)) { + return Collections.emptyList(); + } + return reports.stream().map(r -> { + AssessReportSimpleRespVO vo = new AssessReportSimpleRespVO(); + vo.setId(r.getId()); + vo.setScore(r.getScore()); + vo.setCoverRange(r.getCoverRange()); + vo.setValidFlag("是".equals(r.getValid())); + vo.setIdentifier(r.getIdentifier()); + vo.setVerifier(r.getVerifier()); + vo.setAssessTime(r.getTime() != null ? DateUtils.format(r.getTime(), "yyyy-MM-dd HH:mm:ss") : null); + vo.setVersion(r.getVersion()); + vo.setConditionName(r.getConditionName()); + return vo; + }).collect(Collectors.toList()); + } + + @Override + public List listReportNames(Integer modelId, String version) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(AssessReportCfg.class) + .eq(AssessReportCfg::getModelId, modelId) + .eq(StringUtils.hasText(version), AssessReportCfg::getVersion, version) + .orderByDesc(AssessReportCfg::getTime); + List reports = assessReportCfgMapper.selectList(wrapper); + if (CollectionUtils.isEmpty(reports)) { + return Collections.emptyList(); + } + return reports.stream().map(r -> { + AssessReportNameRespVO vo = new AssessReportNameRespVO(); + vo.setId(r.getId().longValue()); + if (r.getCreateTime() != null) { + vo.setName("RV" + DateUtils.format(r.getCreateTime(), "yyyy-MM-dd'T'HH:mm:ss")); + } else { + vo.setName("RV"); + } + return vo; + }).collect(Collectors.toList()); + } + + @Override + public AssessConditionRespVO getCondition(String algorithm) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(ModelConditionDO.class) + .eq(ModelConditionDO::getAlgorithm, algorithm) + .last("limit 1"); + ModelConditionDO record = modelConditionMapper.selectOne(wrapper); + AssessConditionRespVO vo = new AssessConditionRespVO(); + if (record != null) { + vo.setCondition(record.getCondition()); + try { + Map map = JsonUtils.parseObject(record.getCondition(), new TypeReference>() { + }); + Object score = map != null ? map.get("model_score") : null; + if (score instanceof Number) { + vo.setModelScore(((Number) score).doubleValue()); + } + } catch (Exception ignored) { + } + } + return vo; + } + private String resolveModelInfo(ModelCfg cfg, String version) { if (!StringUtils.hasText(version) || "v-test".equalsIgnoreCase(version)) { return cfg.getModelInfo(); @@ -522,7 +630,7 @@ public class AssessReportServiceImpl implements AssessReportService { return list; } -private Double getListValue(List list, int idx) { + private Double getListValue(List list, int idx) { if (CollectionUtils.isEmpty(list) || idx >= list.size()) { return 0d; } @@ -551,50 +659,89 @@ class Assessinfo { @lombok.Data class TestData { + @com.fasterxml.jackson.annotation.JsonProperty("time") private String time; + @com.fasterxml.jackson.annotation.JsonProperty("points") private String points; + @com.fasterxml.jackson.annotation.JsonProperty("interval") private Integer interval; } @lombok.Data class ModelTestNew { private boolean expand; + @com.fasterxml.jackson.annotation.JsonProperty("Test_Data") + @com.fasterxml.jackson.annotation.JsonAlias({"Test_Data", "test_data"}) private TestData Test_Data; + @com.fasterxml.jackson.annotation.JsonProperty("dead") private String dead; + @com.fasterxml.jackson.annotation.JsonProperty("limit") private String limit; + @com.fasterxml.jackson.annotation.JsonProperty("Model_id") + @com.fasterxml.jackson.annotation.JsonAlias({"Model_id", "model_id"}) private String Model_id; + @com.fasterxml.jackson.annotation.JsonProperty("Model_alg") + @com.fasterxml.jackson.annotation.JsonAlias({"Model_alg", "model_alg"}) private String Model_alg; + @com.fasterxml.jackson.annotation.JsonProperty("number_sample") private int number_sample; + @com.fasterxml.jackson.annotation.JsonProperty("assess") private List assess; + @com.fasterxml.jackson.annotation.JsonProperty("condition") private String condition; + @com.fasterxml.jackson.annotation.JsonProperty("Test_Type") + @com.fasterxml.jackson.annotation.JsonAlias({"Test_Type", "test_type"}) private String Test_Type; + @com.fasterxml.jackson.annotation.JsonProperty("Limit_Value") + @com.fasterxml.jackson.annotation.JsonAlias({"Limit_Value", "limit_value"}) private double Limit_Value; + @com.fasterxml.jackson.annotation.JsonProperty("uplow") private String uplow; + @com.fasterxml.jackson.annotation.JsonProperty("number") private int number; + @com.fasterxml.jackson.annotation.JsonProperty("version") private String version; + @com.fasterxml.jackson.annotation.JsonProperty("low_f") private String low_f; + @com.fasterxml.jackson.annotation.JsonProperty("high_f") private String high_f; + @com.fasterxml.jackson.annotation.JsonProperty("k") private Integer k; + @com.fasterxml.jackson.annotation.JsonProperty("coverage") private Double coverage; } + @lombok.Data +@NoArgsConstructor +@AllArgsConstructor class AssessAllMessage { private String message; - private Long CleanTime; - private Long AssessTime; + // 部分接口返回小数秒,需要用 Double + @com.fasterxml.jackson.annotation.JsonProperty("CleanTime") + private Double CleanTime; + @com.fasterxml.jackson.annotation.JsonProperty("AssessTime") + private Double AssessTime; } @lombok.Data class AssessResult { + @com.fasterxml.jackson.annotation.JsonProperty("amplitude") + private List amplitude; + @com.fasterxml.jackson.annotation.JsonProperty("far_variable") private List far_variable; + @com.fasterxml.jackson.annotation.JsonProperty("fdr_variable") private List fdr_variable; + @com.fasterxml.jackson.annotation.JsonProperty("Reconstruction_precision") private List Reconstruction_precision; } @lombok.Data class AssessAll { + @com.fasterxml.jackson.annotation.JsonProperty(value = "Positive") private AssessResult Positive; + // 兼容接口返回的小写 negative + @com.fasterxml.jackson.annotation.JsonProperty(value = "negative") private AssessResult Negative; } @@ -610,6 +757,7 @@ class AssessInput { private String inputInfo; private Integer indexType; private Integer sigmaType; + @com.fasterxml.jackson.annotation.JsonProperty("exA_IP") private String exA_IP; } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/ModelService.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/ModelService.java index 4375a91..cdf3b09 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/ModelService.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/ModelService.java @@ -27,7 +27,7 @@ public interface ModelService { * @param id 模型id * @return 模型信息 */ - ModelInfoVO getModelInfo(Integer id); + ModelInfoVO getModelInfo(Integer id, String version); /** * 新建模型 @@ -49,5 +49,21 @@ public interface ModelService { ModelTestData getModelTestData(ModelTestParam param); - ModelInfoVO bottomModel(Integer id); + /** + * 模型下装:校验训练/评估后,将模型状态置为已下装并落库版本 + * + * @param id 模型ID + * @param reportId 评估报告ID(需要通过校验) + */ + ModelInfoVO bottomModel(Integer id, Long reportId); + + /** + * 新建草稿版本(v-test),用于再次训练/发布 + */ + ModelInfoVO createDraftVersion(Integer id); + + /** + * 查询历史版本列表 + */ + java.util.List listVersions(Integer modelId); } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/impl/ModelServiceImpl.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/impl/ModelServiceImpl.java index 2ba6a97..f659246 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/impl/ModelServiceImpl.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/model/impl/ModelServiceImpl.java @@ -12,9 +12,11 @@ import cn.iocoder.yudao.module.alert.common.enums.ModelTrash; import cn.iocoder.yudao.module.alert.common.enums.ModelVisible; import cn.iocoder.yudao.module.alert.controller.admin.model.model.ModelInfo; import cn.iocoder.yudao.module.alert.controller.admin.model.vo.*; +import cn.iocoder.yudao.module.alert.dao.domain.AssessReportCfg; import cn.iocoder.yudao.module.alert.dao.domain.ModelCfg; import cn.iocoder.yudao.module.alert.dao.domain.ModelVersion; import cn.iocoder.yudao.module.alert.dao.domain.SystemCfg; +import cn.iocoder.yudao.module.alert.dao.mapper.AssessReportCfgMapper; import cn.iocoder.yudao.module.alert.dao.service.ModelCfgService; import cn.iocoder.yudao.module.alert.dao.service.ModelVersionService; import cn.iocoder.yudao.module.alert.dao.service.SystemCfgService; @@ -24,9 +26,11 @@ import cn.iocoder.yudao.module.alert.service.model.ModelService; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.fasterxml.jackson.core.type.TypeReference; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -50,6 +54,8 @@ public class ModelServiceImpl implements ModelService { private final ModelVersionService modelVersionService; + private final AssessReportCfgMapper assessReportCfgMapper; + @Value("${algorithm.host}") private String algorithmHost; @@ -80,6 +86,7 @@ public class ModelServiceImpl implements ModelService { .name(modelCfg.getModelName().trim()) .creator(modelCfg.getCreator()) .createTime(modelCfg.getCreateTime()) + .version(modelCfg.getCurVersion()) .status(modelCfg.getStatus()) .algorithm(Algorithm.of(modelCfg.getAlgorithmId()).toString()) .build()) @@ -87,11 +94,28 @@ public class ModelServiceImpl implements ModelService { } @Override - public ModelInfoVO getModelInfo(Integer id) { + public ModelInfoVO getModelInfo(Integer id, String version) { ModelCfg modelCfg = modelCfgService.getById(id); if (Objects.nonNull(modelCfg)) { - ModelInfoVO modelInfoVO = JsonUtils.parseObject(modelCfg.getModelInfo(), ModelInfoVO.class); - modelInfoVO.setSystemId(modelCfg.getSystemId()); + ModelInfoVO modelInfoVO; + // 如果传入版本,且不是 v-test,则从 model_version 读取对应版本的 model_info + if (StringUtils.hasText(version) && !"v-test".equalsIgnoreCase(version)) { + ModelVersion mv = modelVersionService.getOne(Wrappers.lambdaQuery() + .eq(ModelVersion::getModelId, id) + .eq(ModelVersion::getVersion, version) + .last("limit 1")); + if (mv != null && StringUtils.hasText(mv.getModelInfo())) { + modelInfoVO = JsonUtils.parseObject(mv.getModelInfo(), ModelInfoVO.class); + } else { + modelInfoVO = JsonUtils.parseObject(modelCfg.getModelInfo(), ModelInfoVO.class); + } + } else { + modelInfoVO = JsonUtils.parseObject(modelCfg.getModelInfo(), ModelInfoVO.class); + } + if (modelInfoVO != null) { + modelInfoVO.setSystemId(modelCfg.getSystemId()); + modelInfoVO.setCreateTime(modelCfg.getCreateTime()); + } return modelInfoVO; } return null; @@ -167,22 +191,119 @@ public class ModelServiceImpl implements ModelService { @Override @Transactional(rollbackFor = Exception.class) - public ModelInfoVO bottomModel(Integer id) { + public ModelInfoVO bottomModel(Integer id, Long reportId) { ModelCfg modelCfg = modelCfgService.getById(id); + if (Objects.isNull(modelCfg)) { + throw new RuntimeException("模型不存在"); + } ModelInfoVO modelInfo = JSON.parseObject(modelCfg.getModelInfo(), ModelInfoVO.class); + if (modelInfo == null || modelInfo.getPara() == null) { + throw new RuntimeException("模型未训练,无法下装"); + } + if (CollUtil.isEmpty(modelInfo.getTrainTime())) { + throw new RuntimeException("模型尚未建立,无法下装"); + } + if (ModelStatus.FINISH.desc.equals(modelInfo.getBtmState()) + && !"v-test".equalsIgnoreCase(modelInfo.getVersion())) { + throw new RuntimeException("模型已下装,无法重复操作"); + } + AssessReportCfg report = null; + if (Objects.nonNull(reportId)) { + report = assessReportCfgMapper.selectById(reportId); + if (report == null || !Objects.equals(report.getModelId(), id)) { + throw new RuntimeException("评估报告不存在"); + } + } else { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(AssessReportCfg.class) + .eq(AssessReportCfg::getModelId, id) + .eq(StringUtils.hasText(modelInfo.getVersion()), AssessReportCfg::getVersion, modelInfo.getVersion()) + .eq(AssessReportCfg::getValid, "是") + .orderByDesc(AssessReportCfg::getCreateTime) + .last("limit 1"); + report = assessReportCfgMapper.selectOne(wrapper); + } + if (report == null) { + throw new RuntimeException("请先完成合格并审核通过的评估报告"); + } + //todo 暂时先不验证评估报告是否通过 +// if (!"是".equals(report.getValid())) { +// throw new RuntimeException("报告未通过验证,无法下装"); +// } + modelInfo.setBtmState(ModelStatus.FINISH.desc); modelInfo.setVersion("v-" + DateUtil.now()); modelInfo.setModifier(SecurityFrameworkUtils.getLoginUserNickname()); modelInfo.setModifiedTime(new Date()); - modelCfg.setModelInfo(JSON.toJSONString(modelInfo)); + modelCfg.setModelInfo(JsonUtils.toJsonString(modelInfo)); modelCfg.setUpdateTime(new Date()); modelCfg.setStatus(ModelStatus.FINISH.code); + modelCfg.setCurVersion(modelInfo.getVersion()); modelCfgService.updateById(modelCfg); ModelVersion modelVersion = BeanUtil.copyProperties(modelCfg, ModelVersion.class); modelVersion.setId(null); modelVersion.setModelId(id); + modelVersion.setVersion(modelInfo.getVersion()); + modelVersion.setCreateTime(new Date()); modelVersionService.save(modelVersion); + report.setVersion(modelInfo.getVersion()); + assessReportCfgMapper.updateById(report); + return modelInfo; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public ModelInfoVO createDraftVersion(Integer id) { + ModelCfg modelCfg = modelCfgService.getById(id); + if (Objects.isNull(modelCfg)) { + throw new RuntimeException("模型不存在"); + } + ModelInfoVO modelInfo = JSON.parseObject(modelCfg.getModelInfo(), ModelInfoVO.class); + if (modelInfo == null) { + throw new RuntimeException("模型信息为空"); + } + modelInfo.setVersion("v-test"); + modelInfo.setBtmState(ModelStatus.TRAINING.desc); + modelInfo.setPara(null); + modelInfo.setPrincipal(null); + modelInfo.setPrecision(null); + modelInfo.setModifier(SecurityFrameworkUtils.getLoginUserNickname()); + modelInfo.setModifiedTime(new Date()); + modelCfg.setStatus(ModelStatus.TRAINING.code); + modelCfg.setCurVersion(modelInfo.getVersion()); + modelCfg.setModelInfo(JSON.toJSONString(modelInfo)); + modelCfg.setUpdateTime(new Date()); + modelCfgService.updateById(modelCfg); return modelInfo; } + + @Override + public List listVersions(Integer modelId) { + ModelCfg cfg = modelCfgService.getById(modelId); + List versions = modelVersionService.list(Wrappers.lambdaQuery() + .eq(ModelVersion::getModelId, modelId) + .orderByDesc(ModelVersion::getCreateTime)); + List list = new ArrayList<>(); + if (cfg != null && StringUtils.hasText(cfg.getCurVersion())) { + ModelVersionSimpleVO cur = new ModelVersionSimpleVO(); + cur.setVersion(cfg.getCurVersion()); + cur.setStatus(cfg.getStatus()); + cur.setConditionName(cfg.getConditionName()); + cur.setCreateTime(cfg.getUpdateTime() != null ? cfg.getUpdateTime() : cfg.getCreateTime()); + list.add(cur); + } + if (CollectionUtils.isEmpty(versions)) { + return list; + } + List hist = versions.stream().map(v -> { + ModelVersionSimpleVO vo = new ModelVersionSimpleVO(); + vo.setVersion(v.getVersion()); + vo.setCreateTime(v.getCreateTime()); + vo.setStatus(v.getStatus()); + vo.setConditionName(v.getConditionName()); + return vo; + }).collect(Collectors.toList()); + list.addAll(hist); + return list; + } } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.xml b/yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.xml new file mode 100644 index 0000000..186c742 --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/AssessReportCfgMapper.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + id,model_id,version,report,score,cover_range, + valid,identifier,verifier,time,status, + condition_name,creator,create_time,updater,update_time, + deleted + + diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.xml b/yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.xml new file mode 100644 index 0000000..a7fc6b2 --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/resources/cn/iocoder/yudao/module/alert/dao/mapper/ModelVersionMapper.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id,model_id,algorithm_id,model_name,create_name,model_info, + status,visible,condition_info,trash,assess_res, + need_to_assess,score,clear_or_not,eff_number,need_to_clean, + orig_assess_res,load_cover,cover_output,version,condition_name, + is_online,creator,create_time,updater,update_time, + deleted + +