diff --git a/src/main/java/com/supervision/common/constant/IndexRuleConstants.java b/src/main/java/com/supervision/common/constant/IndexRuleConstants.java index 424a5c4..093b3a0 100644 --- a/src/main/java/com/supervision/common/constant/IndexRuleConstants.java +++ b/src/main/java/com/supervision/common/constant/IndexRuleConstants.java @@ -1,5 +1,8 @@ package com.supervision.common.constant; +import java.util.List; +import java.util.Map; + public class IndexRuleConstants { /** * 操作数类型(数据来源) @@ -47,9 +50,9 @@ public class IndexRuleConstants { /** * 操作数值类型 */ - public static final String VALUE_TYPE_STRING = "0"; - public static final String VALUE_TYPE_NUMBER = "1"; - public static final String VALUE_TYPE_DATE = "2"; + public static final String VALUE_TYPE_STRING = "1"; + public static final String VALUE_TYPE_NUMBER = "2"; + public static final String VALUE_TYPE_DATE = "3"; /** * 操作符 @@ -72,4 +75,23 @@ public class IndexRuleConstants { public static final String EVALUATE_RESULT_EXIST = "3"; public static final String EVALUATE_RESULT_NOT_EXIST = "4"; public static final String EVALUATE_RESULT_UNKNOWN = "5"; + + + public static final Map> VALUE_TYPE_OPERATOR_MAPPING = Map.of( + VALUE_TYPE_STRING, List.of(OPERATOR_CONTAIN), + VALUE_TYPE_NUMBER, List.of(OPERATOR_GT, OPERATOR_GE, OPERATOR_LT, OPERATOR_LE, OPERATOR_EQ, OPERATOR_NE), + VALUE_TYPE_DATE, List.of(OPERATOR_EARLY, OPERATOR_LATE, OPERATOR_EQ, OPERATOR_NE) + ); + + public static final Map> VALUE_TYPE_OPERATOR_DIC_MAPPING = Map.of( + VALUE_TYPE_STRING, List.of(OPERATOR_CONTAIN), + VALUE_TYPE_NUMBER, List.of(OPERATOR_GT, OPERATOR_GE, OPERATOR_LT, OPERATOR_LE, OPERATOR_EQ, OPERATOR_NE), + VALUE_TYPE_DATE, List.of(OPERATOR_EARLY, OPERATOR_LATE, OPERATOR_EQ, OPERATOR_NE) + ); + + public static final Map> VALUE_TYPE_AGGREGATE_MAPPING = Map.of( + VALUE_TYPE_STRING, Map.of(AGGREGATE_TYPE_COUNT,"数量", AGGREGATE_TYPE_ANY,"任一"), + VALUE_TYPE_NUMBER, Map.of(AGGREGATE_TYPE_SUM,"合计", AGGREGATE_TYPE_COUNT,"数量",AGGREGATE_TYPE_ANY,"任一"), + VALUE_TYPE_DATE, Map.of(AGGREGATE_TYPE_ANY,"任一") + ); } diff --git a/src/main/java/com/supervision/police/controller/ModelIndexController.java b/src/main/java/com/supervision/police/controller/ModelIndexController.java index c03b93b..2106cbb 100644 --- a/src/main/java/com/supervision/police/controller/ModelIndexController.java +++ b/src/main/java/com/supervision/police/controller/ModelIndexController.java @@ -5,15 +5,16 @@ import com.supervision.police.domain.ModelAtomicIndex; import com.supervision.police.domain.ModelIndex; import com.supervision.police.dto.CaseAtomicIndexDTO; import com.supervision.police.dto.CaseAtomicResultWrapper; +import com.supervision.police.dto.ValueCalculateScopeDTO; import com.supervision.police.service.ModelIndexService; import com.supervision.police.vo.ModelIndexReqVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Map; /** * 指标表(ModelIndex)表控制层 @@ -131,5 +132,13 @@ public class ModelIndexController { Boolean result = modelIndexService.saveCaseAtomicResult(caseAtomicResultWrapper); return R.ok(result); } + + @Operation(summary = "查询案件原子指标属性操作域") + @PostMapping("/listAtomicIndexAttributeScope") + public R>> listAtomicIndexAttributeScope(@RequestBody List atomicIndexIds) { + + Map> result = modelIndexService.listAtomicIndexAttributeScope(atomicIndexIds); + return R.ok(result); + } } diff --git a/src/main/java/com/supervision/police/domain/ModelAtomicIndex.java b/src/main/java/com/supervision/police/domain/ModelAtomicIndex.java index 625fea2..14f2afa 100644 --- a/src/main/java/com/supervision/police/domain/ModelAtomicIndex.java +++ b/src/main/java/com/supervision/police/domain/ModelAtomicIndex.java @@ -1,7 +1,6 @@ package com.supervision.police.domain; import java.time.LocalDateTime; -import java.util.Date; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; @@ -10,6 +9,7 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.io.Serializable; +import java.util.List; /** * 原子指标表(ModelAtomicIndex)表实体类 @@ -72,11 +72,28 @@ public class ModelAtomicIndex implements Serializable { */ private String promptId; + /** + * 提示词名称 + */ + @TableField(exist = false) + private String promptName; + /** * 属性 多个属性用逗号隔开 */ private String properties; + /** + * 分类id + */ + private String categoryId; + + /** + * 分类路径 + */ + @TableField(exist = false) + private List categoryIdPath; + /** * 笔录类型 */ diff --git a/src/main/java/com/supervision/police/dto/AtomicIndexDTO.java b/src/main/java/com/supervision/police/dto/AtomicIndexDTO.java index a473421..9e74de7 100644 --- a/src/main/java/com/supervision/police/dto/AtomicIndexDTO.java +++ b/src/main/java/com/supervision/police/dto/AtomicIndexDTO.java @@ -39,6 +39,11 @@ public class AtomicIndexDTO { private List recordSegmentationList = new ArrayList<>(); + /** + * 证据结果 + */ + private List evidentResultList; + /** * 原子指标结果 */ diff --git a/src/main/java/com/supervision/police/dto/CaseEvidenceCategoryDTO.java b/src/main/java/com/supervision/police/dto/CaseEvidenceCategoryDTO.java new file mode 100644 index 0000000..c8bbc2b --- /dev/null +++ b/src/main/java/com/supervision/police/dto/CaseEvidenceCategoryDTO.java @@ -0,0 +1,47 @@ +package com.supervision.police.dto; + +import lombok.Data; + +@Data +public class CaseEvidenceCategoryDTO { + + /** + * 案件id + */ + private String caseId; + + /** + * 证据id + */ + private String evidenceId; + + /** + * 证据名称 + */ + private String evidenceName; + + /** + * 证据分类id + */ + private String categoryId; + + /** + * 证据分类名称 + */ + private String categoryName; + + /** + * 证据目录id + */ + private String directoryId; + + /** + * 证据目录名称 + */ + private String directoryName; + + /** + * 证据目录级别 + */ + private int directoryLevel; +} diff --git a/src/main/java/com/supervision/police/dto/EvidenceCategoryDTO.java b/src/main/java/com/supervision/police/dto/EvidenceCategoryDTO.java index 60ba796..b396d6f 100644 --- a/src/main/java/com/supervision/police/dto/EvidenceCategoryDTO.java +++ b/src/main/java/com/supervision/police/dto/EvidenceCategoryDTO.java @@ -2,7 +2,6 @@ package com.supervision.police.dto; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; -import com.supervision.police.domain.EvidenceCategory; import lombok.Data; import java.util.ArrayList; @@ -15,7 +14,7 @@ import java.util.List; public class EvidenceCategoryDTO { /** - * 主键id + * 分类id */ private String id; @@ -50,22 +49,6 @@ public class EvidenceCategoryDTO { private List child; - /** - * 分类层级 - */ - private int level = -1; - - /** - * 分类层级 - */ - private String categoryLevel; - - - /** - * 分类id - */ - private String categoryId; - /** * 是否有关联的提示词 */ @@ -75,36 +58,45 @@ public class EvidenceCategoryDTO { public EvidenceCategoryDTO() { } - public EvidenceCategoryDTO(EvidenceCategory category) { - this.id = category.getId(); - this.categoryName = category.getCategoryName(); - this.iconUrl = category.getIconURl(); - this.parentId = category.getParentId(); - this.child = new ArrayList<>(); + + public EvidenceCategoryDTO(List categoryList){ + this.child = categoryList; + } - /** - * 获取分类的层级 - * - * @param categoryId 分类id - * @param currentLevel 当前层级 - * @return 分类层级 - */ - public int evalLevel(String categoryId, int currentLevel) { - if (StrUtil.isEmpty(categoryId)) { - return -1; + public List listCategoryIdPath(String id){ + if (StrUtil.isEmpty(id)){ + return new ArrayList<>(1); + } + + if (StrUtil.equals(this.id,id)){ + return CollUtil.newArrayList(id); + } + if (CollUtil.isNotEmpty(this.child)){ + for (EvidenceCategoryDTO evidenceCategoryDTO : child) { + List path = evidenceCategoryDTO.listCategoryIdPath(id); + if (CollUtil.isNotEmpty(path)){ + path.add(0,this.id); + return path; + } + } } - if (StrUtil.equals(this.id, categoryId)) { - return currentLevel; + return new ArrayList<>(1); + + } + + public EvidenceCategoryDTO findCategoryById(String categoryId){ + if (StrUtil.equals(this.id,categoryId)){ + return this; } - if (CollUtil.isNotEmpty(this.child)) { + if (CollUtil.isNotEmpty(this.child)){ for (EvidenceCategoryDTO evidenceCategoryDTO : child) { - int level = evidenceCategoryDTO.evalLevel(categoryId, currentLevel + 1); - if (level != -1) { - return level; + EvidenceCategoryDTO categoryDTO = evidenceCategoryDTO.findCategoryById(categoryId); + if (categoryDTO != null){ + return categoryDTO; } } } - return -1; + return null; } } diff --git a/src/main/java/com/supervision/police/dto/EvidenceDirectoryDTO.java b/src/main/java/com/supervision/police/dto/EvidenceDirectoryDTO.java index d5df6c2..dd22c12 100644 --- a/src/main/java/com/supervision/police/dto/EvidenceDirectoryDTO.java +++ b/src/main/java/com/supervision/police/dto/EvidenceDirectoryDTO.java @@ -240,11 +240,35 @@ public class EvidenceDirectoryDTO { this.getChild().removeIf(next -> CollUtil.isEmpty(next.getChild()) && CollUtil.isEmpty(next.getFileInfoList())); } + /** + * 判断分类id对应目录下是否存在有文件 + * @param categoryId 分类id + * @return + */ + public boolean categoryHasFile(String categoryId){ + + if (StrUtil.isEmpty(categoryId)){ + return false; + } + + if (StrUtil.equals(this.categoryId,categoryId)){ + return CollUtil.isNotEmpty(this.fileInfoList); + } + if (CollUtil.isEmpty(this.child)){ + return false; + } + for (EvidenceDirectoryDTO directoryDTO : this.child) { + if (directoryDTO.categoryHasFile(categoryId)){ + return true; + } + } + return false; + } /** - * 重新防止证据信息 + * 重新放置证据信息 */ - public void rePlaceEvidence(){ + public void replaceEvidence(){ if (CollUtil.isNotEmpty(this.fileInfoList) && null != this.evidenceInfo){ for (EvidenceFileDTO evidenceFileDTO : this.fileInfoList) { evidenceFileDTO.setEvidenceInfo(evidenceInfo); @@ -252,7 +276,7 @@ public class EvidenceDirectoryDTO { } if (CollUtil.isNotEmpty(this.child)){ for (EvidenceDirectoryDTO directoryDTO : this.child) { - directoryDTO.rePlaceEvidence(); + directoryDTO.replaceEvidence(); } } } @@ -264,4 +288,22 @@ public class EvidenceDirectoryDTO { return new ArrayList<>(); } } + + public List getDirectoryPath(String directoryId) { + + if (StrUtil.equals(this.id, directoryId)){ + return Arrays.asList(this.id); + } + if (CollUtil.isNotEmpty(this.child)){ + for (EvidenceDirectoryDTO directoryDTO : this.child) { + List directoryPath = directoryDTO.getDirectoryPath(directoryId); + if (CollUtil.isNotEmpty(directoryPath)){ + directoryPath.add(0,this.id); + return directoryPath; + } + } + } + return new ArrayList<>(1); + + } } diff --git a/src/main/java/com/supervision/police/dto/EvidentIndexResultDTO.java b/src/main/java/com/supervision/police/dto/EvidentIndexResultDTO.java new file mode 100644 index 0000000..6ca00e2 --- /dev/null +++ b/src/main/java/com/supervision/police/dto/EvidentIndexResultDTO.java @@ -0,0 +1,69 @@ +package com.supervision.police.dto; + +import cn.hutool.core.util.StrUtil; +import lombok.Data; + +import java.util.List; + +/** + * 证据对应的指标结果 + */ +@Data +public class EvidentIndexResultDTO { + + /** + * 原子指标id + */ + private String atomicIndexId; + + /** + * 指标id + */ + private String indexId; + + private String evidenceId; + + + /** + * 证据名称 + */ + private String evidenceName; + + /** + * 证据所在目录 + */ + private String directoryName; + + + /** + * 证据所在目录id + */ + private String directoryId; + + private String categoryId; + + private String categoryName; + + /** + * 所属目录路径 + */ + private String directoryPath; + + /** + * 提供人 + */ + private String provider; + + /** + * 证据描述 + */ + private String details; + + public void setBelongDirectoryValue(EvidenceDirectoryDTO directory){ + if (StrUtil.isEmpty(this.directoryId) || null == directory){ + return; + } + List path = directory.getDirectoryPath(this.directoryId); + this.directoryPath = StrUtil.join(StrUtil.HTML_GT, path); + } +} diff --git a/src/main/java/com/supervision/police/dto/ValueCalculateScopeDTO.java b/src/main/java/com/supervision/police/dto/ValueCalculateScopeDTO.java new file mode 100644 index 0000000..f154ff6 --- /dev/null +++ b/src/main/java/com/supervision/police/dto/ValueCalculateScopeDTO.java @@ -0,0 +1,38 @@ +package com.supervision.police.dto; + +import cn.hutool.core.lang.Pair; +import lombok.Data; + +import java.util.List; + +/** + * 值域计算范围 + */ +@Data +public class ValueCalculateScopeDTO { + + /** + * 值 + */ + private String value; + + /** + * 值类型 + */ + private String valueType; + + /** + * 值类型描述 + */ + private String valueTypeDesc; + + /** + * 操作符 + */ + private List operatorList; + + /** + * 聚合函数 + */ + private List> aggregateList; +} diff --git a/src/main/java/com/supervision/police/dto/caseScore/AtomicResult.java b/src/main/java/com/supervision/police/dto/caseScore/AtomicResult.java index 1d365e0..4f8f4bc 100644 --- a/src/main/java/com/supervision/police/dto/caseScore/AtomicResult.java +++ b/src/main/java/com/supervision/police/dto/caseScore/AtomicResult.java @@ -3,10 +3,13 @@ package com.supervision.police.dto.caseScore; import cn.hutool.core.util.StrUtil; import com.supervision.police.domain.ModelAtomicIndex; import com.supervision.police.domain.ModelAtomicResult; +import com.supervision.police.dto.CaseEvidenceDetailDTO; +import com.supervision.police.dto.EvidenceDirectoryDTO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.ai.chat.ChatClient; +import java.util.List; import java.util.Objects; /** @@ -24,12 +27,24 @@ public class AtomicResult { @Schema(description = "指标id") private String indexId; + // 参考 IndexRuleConstants @Schema(description = "指标来源 1:人工定义 2:数据库查询 3:图谱生成 4:大模型") private String indexSource; @Schema(description = "原子指标结果 1:真实 2:虚构 3:存在 4:不存在 5:未知") private String judgeResult; + @Schema(description = "分类id") + private String categoryId; + + // 目录信息由分类id决定,一个分类可能对应多个目录 + @Schema(description = "证据目录信息") + private List directoryList; + + // 一个原子指标的结果可能有多个证据计算而来 + @Schema(description = "证据信息") + private List caseEvidenceDetailDTOS; + public AtomicResult() { } @@ -44,6 +59,7 @@ public class AtomicResult { } this.atomicId = modelAtomicIndex.getId(); this.indexId = indexId; + this.categoryId = modelAtomicIndex.getCategoryId(); this.atomicName = modelAtomicIndex.getName(); this.indexSource = modelAtomicIndex.getIndexSource(); this.judgeResult = atomicResult.getAtomicResult(); diff --git a/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailBuilder.java b/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailBuilder.java index 4eb1f82..fb02a35 100644 --- a/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailBuilder.java +++ b/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailBuilder.java @@ -3,9 +3,12 @@ package com.supervision.police.dto.caseScore; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.supervision.common.constant.IndexRuleConstants; import com.supervision.constant.JudgeResultEnum; import com.supervision.constant.ScoreEnum; import com.supervision.police.domain.*; +import com.supervision.police.dto.EvidenceCategoryDTO; +import com.supervision.police.dto.EvidenceDirectoryDTO; import com.supervision.police.mapper.*; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -13,6 +16,7 @@ import org.springframework.ai.ollama.OllamaChatClient; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -29,6 +33,9 @@ public class CaseScoreDetailBuilder { @Schema(description = "案件id") private String caseId; + @Schema(description = "案件类型") + private String caseType; + @Schema(description = "案件名称") private String caseName; @@ -42,6 +49,10 @@ public class CaseScoreDetailBuilder { @Schema(description = "指标结果") private List indexResultList = new ArrayList<>(); + private EvidenceDirectoryDTO evidenceDirectoryDTO; + + private EvidenceCategoryDTO rootEvidenceCategory; + /** * Ollama 客户端 */ @@ -74,6 +85,14 @@ public class CaseScoreDetailBuilder { return this; } + public CaseScoreDetailBuilder setEvidence(EvidenceDirectoryDTO evidenceDirectoryDTO, + EvidenceCategoryDTO rootEvidenceCategory) { + + this.evidenceDirectoryDTO = evidenceDirectoryDTO; + this.rootEvidenceCategory = rootEvidenceCategory; + return this; + } + /** * 共性指标分数 @@ -204,6 +223,11 @@ public class CaseScoreDetailBuilder { return instance == null || !instance.flagIsTrue(); }).filter(result->StrUtil.isNotEmpty(result.getAtomicId())).filter(distinctPredicate(AtomicResult::getAtomicId)).count() ); + + List unusedCategoryIds = this.getUnusedCategoryIds(); + caseScoreDetailDTO.setMissAtomicIndexCount((long) unusedCategoryIds.size()); + caseScoreDetailDTO.setMissCategoryNameList(this.getUnusedCategoryNames(unusedCategoryIds)); + caseScoreDetailDTO.setGuideDesc(this.buildGuideDesc(unusedCategoryIds, rootEvidenceCategory)); return caseScoreDetailDTO; } @@ -236,6 +260,84 @@ public class CaseScoreDetailBuilder { } + /** + * 获取未使用的分类 + */ + public List getUnusedCategoryIds() { + + if (null == this.evidenceDirectoryDTO){ + return new ArrayList<>(); + } + // 结构化推理分类id 分类 + List categoryList = this.indexResultList.stream() + .flatMap(indexResult -> indexResult.getAtomicResults().stream()) + .filter(atomicResult -> StrUtil.equals(IndexRuleConstants.OPERAND_TYPE_STRUCTURE, atomicResult.getIndexSource())) + .map(AtomicResult::getCategoryId).filter(id -> !this.evidenceDirectoryDTO.categoryHasFile(id)).toList(); + + + // 数据库查询分类id + List list = this.indexResultList.stream().flatMap(indexResult -> indexResult.getAtomicResults().stream()) + .filter(atomicResult -> StrUtil.equals(IndexRuleConstants.OPERAND_TYPE_DB, atomicResult.getIndexSource())) + .filter(AtomicResult::resultIsTrue).map(AtomicResult::getCategoryId).toList(); + + List all = new ArrayList<>(categoryList); + all.addAll(list); + return CollUtil.distinct(all); + } + + public List getUnusedCategoryNames(List unusedCategoryIds) { + return unusedCategoryIds.stream().map(id -> rootEvidenceCategory.findCategoryById(id)).map(EvidenceCategoryDTO::getCategoryName).toList(); + } + + /** + * 构建引导描述 + * @param categoryIds 分类id + * @param rootCategory 根分类信息 + * @return + */ + public String buildGuideDesc(List categoryIds, EvidenceCategoryDTO rootCategory) { + + if (CollUtil.isEmpty(categoryIds)) { + return "案件证据均已成功上传,系统已基于现有证据链进行分析和案件预测评分。如果对结果存在疑问或偏差,可核实证据信息是否完整和准确。如有需要,您可以补充更多相关证据以进一步支持案件分析。"; + } + + List> pathIds = categoryIds.stream().map(rootCategory::listCategoryIdPath).toList(); + + // 二级目录 + Map> categoryIdGroup = pathIds.stream().filter(list -> list.size() == 2) + .collect(Collectors.groupingBy(list -> list.get(0), Collectors.mapping(list -> list.get(1), Collectors.toList()))); + + // 只包含一级目录 + List categoryLevelOneIds = pathIds.stream().filter(list -> list.size() == 1) + .flatMap(Collection::stream).filter(id -> !categoryIdGroup.containsKey(id)).distinct().toList(); + + StringBuilder builder = new StringBuilder("为了提升司法定性的准确性,建议您补充以下相关证据:包括但不限于"); + for (Map.Entry> entry : categoryIdGroup.entrySet()) { + String oneLevel = entry.getKey(); + EvidenceCategoryDTO oneLevelCategory = rootCategory.findCategoryById(oneLevel); + if (oneLevelCategory != null) { + builder.append(oneLevelCategory.getCategoryName()).append("("); + for (String secondCategoryId : entry.getValue()) { + EvidenceCategoryDTO secondLevelCategory = rootCategory.findCategoryById(secondCategoryId); + if (secondLevelCategory != null) { + builder.append(secondLevelCategory.getCategoryName()).append("、"); + } + } + builder.deleteCharAt(builder.length() - 1).append("),"); + } + + } + for (String categoryLevelOneId : categoryLevelOneIds) { + EvidenceCategoryDTO oneLevelCategory = rootCategory.findCategoryById(categoryLevelOneId); + if (oneLevelCategory != null) { + builder.append(oneLevelCategory.getCategoryName()).append(","); + } + } + builder.deleteCharAt(builder.length() - 1).append("等,这些证据对于完善证据链至关重要,有助于我们获得最终案件的预测分数。如果您尚未上传任何证据,请尽快提供,以确保案件处理的完整性和准确性。"); + + return builder.toString(); + } + /** * 获取共性指标 * @return @@ -276,6 +378,7 @@ public class CaseScoreDetailBuilder { // 1 设置案件基本信息 ModelCase modelCase = modelCaseMapper.selectById(caseId); this.setCaseId(modelCase.getId()); + this.setCaseType(modelCase.getCaseType()); this.setCaseName(modelCase.getCaseName()); this.setEvaluationTime(modelCase.getCaseAnalysisSuccessTime()); // 2 设置当事人人员信息 diff --git a/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailDTO.java b/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailDTO.java index d6e0580..1ae6b87 100644 --- a/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailDTO.java +++ b/src/main/java/com/supervision/police/dto/caseScore/CaseScoreDetailDTO.java @@ -63,6 +63,15 @@ public class CaseScoreDetailDTO { @Schema(description = "缺失的原子指标数量") private Long missAtomicIndexCount; + @Schema(description = "缺失的分类数量") + private Long missCategoryCount; + + @Schema(description = "缺失的分类名") + private List missCategoryNameList; + + @Schema(description = "导引描述") + private String guideDesc; + // 公共指标描述 private String commonIndexDesc; diff --git a/src/main/java/com/supervision/police/mapper/CaseEvidenceMapper.java b/src/main/java/com/supervision/police/mapper/CaseEvidenceMapper.java index 01de4cd..0c3f272 100644 --- a/src/main/java/com/supervision/police/mapper/CaseEvidenceMapper.java +++ b/src/main/java/com/supervision/police/mapper/CaseEvidenceMapper.java @@ -3,6 +3,7 @@ package com.supervision.police.mapper; import com.supervision.police.domain.CaseEvidence; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.supervision.police.dto.CaseEvidenceDetailDTO; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -14,9 +15,9 @@ import java.util.List; */ public interface CaseEvidenceMapper extends BaseMapper { - List queryEvidenceList(String caseId); + List queryEvidenceList(@Param("caseId") String caseId); - CaseEvidenceDetailDTO queryEvidenceDetail(String evidenceId); + CaseEvidenceDetailDTO queryEvidenceDetail(@Param("evidenceId") String evidenceId); } diff --git a/src/main/java/com/supervision/police/service/ModelAtomicResultService.java b/src/main/java/com/supervision/police/service/ModelAtomicResultService.java index 9a76078..30b6891 100644 --- a/src/main/java/com/supervision/police/service/ModelAtomicResultService.java +++ b/src/main/java/com/supervision/police/service/ModelAtomicResultService.java @@ -2,6 +2,9 @@ package com.supervision.police.service; import com.baomidou.mybatisplus.extension.service.IService; import com.supervision.police.domain.ModelAtomicResult; +import com.supervision.police.dto.EvidentIndexResultDTO; + +import java.util.List; public interface ModelAtomicResultService extends IService { } diff --git a/src/main/java/com/supervision/police/service/ModelIndexService.java b/src/main/java/com/supervision/police/service/ModelIndexService.java index 0b1668a..ee59894 100644 --- a/src/main/java/com/supervision/police/service/ModelIndexService.java +++ b/src/main/java/com/supervision/police/service/ModelIndexService.java @@ -6,9 +6,11 @@ import com.supervision.police.domain.ModelAtomicIndex; import com.supervision.police.domain.ModelIndex; import com.supervision.police.dto.CaseAtomicIndexDTO; import com.supervision.police.dto.CaseAtomicResultWrapper; +import com.supervision.police.dto.ValueCalculateScopeDTO; import com.supervision.police.vo.ModelIndexReqVO; import java.util.List; +import java.util.Map; /** * 指标表(ModelIndex)表服务接口 @@ -52,5 +54,6 @@ public interface ModelIndexService extends IService { */ boolean checkSql(String sql); + Map> listAtomicIndexAttributeScope(List atomicIndexIds); } diff --git a/src/main/java/com/supervision/police/service/impl/CaseEvidenceServiceImpl.java b/src/main/java/com/supervision/police/service/impl/CaseEvidenceServiceImpl.java index 6e8114f..87b8de2 100644 --- a/src/main/java/com/supervision/police/service/impl/CaseEvidenceServiceImpl.java +++ b/src/main/java/com/supervision/police/service/impl/CaseEvidenceServiceImpl.java @@ -686,7 +686,7 @@ public class CaseEvidenceServiceImpl extends ServiceImpl evidenceVerifyDTOS = evidenceDirectoryList.stream() .flatMap(evidenceDirectoryDTO -> evidenceDirectoryDTO.listAllFile().stream()) diff --git a/src/main/java/com/supervision/police/service/impl/LLMExtractServiceImpl.java b/src/main/java/com/supervision/police/service/impl/LLMExtractServiceImpl.java index 57d8f3e..e939209 100644 --- a/src/main/java/com/supervision/police/service/impl/LLMExtractServiceImpl.java +++ b/src/main/java/com/supervision/police/service/impl/LLMExtractServiceImpl.java @@ -140,7 +140,6 @@ public class LLMExtractServiceImpl implements LLMExtractService { for (NotePromptExtractAttributesDto extractAttribute : extractAttributes) { extractAttributesMap.put(extractAttribute.getAttrName(), extractAttribute.getAttrValueType()); } - // extractAttributes.forEach(extractAttribute -> extractAttributesMap.put(extractAttribute.getAttrName(), extractAttribute.getAttrValueType())); extractAttributesMap.forEach((key, value) -> requirementBuilder.append("\"").append(key).append("\"").append(":").append("\"").append(value).append("\"").append("\n")); } requirementBuilder.append("}"); diff --git a/src/main/java/com/supervision/police/service/impl/ModelCaseServiceImpl.java b/src/main/java/com/supervision/police/service/impl/ModelCaseServiceImpl.java index 6c02f2a..7dc3fb6 100644 --- a/src/main/java/com/supervision/police/service/impl/ModelCaseServiceImpl.java +++ b/src/main/java/com/supervision/police/service/impl/ModelCaseServiceImpl.java @@ -63,6 +63,7 @@ public class ModelCaseServiceImpl extends ServiceImpl nodeRecordSpliteMap = nodeRecordSpliteList.stream().collect(Collectors.toMap(NoteRecordSplit::getId, v -> v)); + + // 获取证据目录 + List evidenceDirectoryDTOS = directoryService.listDirectoryTree(caseId); + EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryDTOS); + + + List atomicResultList = modelAtomicResultService.lambdaQuery().eq(ModelAtomicResult::getCaseId, caseId).list(); + List list = atomicResultList.stream().map(ModelAtomicResult::getEvidenceId).filter(Objects::nonNull).map(v -> v.split(",")).flatMap(Arrays::stream).toList(); + List caseEvidenceList = caseEvidenceService.listByIds(list); + for (IndexDetail record : indexDetails) { if (StringUtils.isEmpty(record.getJudgeLogic())) { continue; @@ -423,6 +436,8 @@ public class ModelCaseServiceImpl extends ServiceImpl evidentResult = getEvidentResult(atomicResultList, caseEvidenceList, rootDirectory); + atomic.setEvidentResultList(evidentResult); } record.setChildren(atomics); @@ -430,6 +445,56 @@ public class ModelCaseServiceImpl extends ServiceImpl getEvidentResult(List atomicResultList,List caseEvidenceList,EvidenceDirectoryDTO rootDirectory) { + + ArrayList evidentIndexResultDTOS = new ArrayList<>(); + + for (ModelAtomicResult modelAtomicResult : atomicResultList) { + String evidenceId = modelAtomicResult.getEvidenceId(); + if (StrUtil.isEmpty(evidenceId)){ + continue; + } + List evidenceIdList = Arrays.asList(evidenceId.split(",")); + + for (CaseEvidence caseEvidence : caseEvidenceList) { + if (evidenceIdList.contains(caseEvidence.getId())){ + EvidentIndexResultDTO evidentIndexResultDTO = new EvidentIndexResultDTO(); + evidentIndexResultDTO.setEvidenceId(caseEvidence.getId()); + evidentIndexResultDTO.setEvidenceName(caseEvidence.getEvidenceName()); + evidentIndexResultDTO.setDirectoryId(caseEvidence.getDirectoryId()); + evidentIndexResultDTO.setDetails(modelAtomicResult.getRemark()); + evidentIndexResultDTO.setIndexId(modelAtomicResult.getIndexId()); + evidentIndexResultDTO.setProvider(caseEvidence.getProvider()); + EvidenceDirectoryDTO directory = rootDirectory.findDirectory(caseEvidence.getDirectoryId()); + if (directory != null){ + evidentIndexResultDTO.setDirectoryName(directory.getDirectoryName()); + List directoryPath = rootDirectory.getDirectoryPath(evidentIndexResultDTO.getDirectoryId()); + evidentIndexResultDTO.setDirectoryPath(StrUtil.join(StrUtil.HTML_GT, directoryPath)); + } + evidentIndexResultDTOS.add(evidentIndexResultDTO); + } + } + } + + return evidentIndexResultDTOS; + + } + + + private List filterAtomicResultList(String indexId, String atomicIndexId, + List modelAtomicResultList){ + + if (CollUtil.isEmpty(modelAtomicResultList)){ + return new ArrayList<>(); + } + + return modelAtomicResultList.stream() + .filter(atomic -> StrUtil.equals(atomic.getIndexId(), indexId) + && StrUtil.equals(atomic.getAtomicId(), atomicIndexId)).collect(Collectors.toList()); + + } + private Map parseLogicMap(String judgeLogic) { List judgeLogics = JSONUtil.toList(judgeLogic, JudgeLogic.class); Map resultMap = new HashMap<>(); diff --git a/src/main/java/com/supervision/police/service/impl/ModelIndexServiceImpl.java b/src/main/java/com/supervision/police/service/impl/ModelIndexServiceImpl.java index 884b3fe..299c191 100644 --- a/src/main/java/com/supervision/police/service/impl/ModelIndexServiceImpl.java +++ b/src/main/java/com/supervision/police/service/impl/ModelIndexServiceImpl.java @@ -2,6 +2,7 @@ package com.supervision.police.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.Pair; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; @@ -12,6 +13,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.supervision.common.constant.IndexRuleConstants; +import com.supervision.common.constant.NotePromptConstants; import com.supervision.common.domain.R; import com.supervision.common.utils.IPages; import com.supervision.common.utils.StringUtils; @@ -61,6 +64,10 @@ public class ModelIndexServiceImpl extends ServiceImpl allowedTables; @@ -159,10 +166,13 @@ public class ModelIndexServiceImpl extends ServiceImpl records = iPage.getRecords(); List dicts = comDictionaryService.list(); + String caseType = StrUtil.isNotEmpty(modelAtomicIndex.getCaseType()) ? modelAtomicIndex.getCaseType() : NotePromptConstants.CASE_TYPE_ENGINEERING_CONTRACT_FRAUD; + EvidenceCategoryDTO rootCategory = new EvidenceCategoryDTO(evidenceCategoryService.listCategoryTree(caseType)); for (ModelAtomicIndex index : records) { index.setCaseTypeName(comDictionaryService.getName(dicts, "case_type", index.getCaseType())); index.setIndexSourceName(comDictionaryService.getName(dicts, "index_source", index.getIndexSource())); index.setRecordTypeName(comDictionaryService.getName(dicts, "record_type", index.getRecordType())); + index.setCategoryIdPath(rootCategory.listCategoryIdPath(index.getCategoryId())); } iPage.setRecords(records); return R.ok(IPages.buildDataMap(iPage)); @@ -171,27 +181,37 @@ public class ModelIndexServiceImpl extends ServiceImpl addOrUpdAtomic(ModelAtomicIndex modelAtomicIndex) { - int i = 0; - if (StringUtils.equals("2", modelAtomicIndex.getIndexSource())) { - // 如果查询类型为数据查询,则校验查询语句 - Assert.notEmpty(modelAtomicIndex.getQueryLang(), "查询语言不能为空"); - Assert.isTrue(checkSql(modelAtomicIndex.getQueryLang()), "查询语句不合法"); - } + + saveAtomicIndexPreDo(modelAtomicIndex); + // 校验是否已经存在了相同名称的原子指标 ModelAtomicIndex existIndex = modelAtomicIndexService.lambdaQuery().eq(ModelAtomicIndex::getName, modelAtomicIndex.getName()) .eq(ModelAtomicIndex::getDataStatus, DataStatus.AVAILABLE.getCode()).last("limit 1").one(); + if (ObjectUtil.isNotEmpty(existIndex) && !StringUtils.equals(modelAtomicIndex.getId(), existIndex.getId())){ throw new RuntimeException("已存在相同名称的原子指标"); } - if (StringUtils.isEmpty(modelAtomicIndex.getId())) { - i = modelAtomicIndexService.getMapper().insert(modelAtomicIndex); - } else { - i = modelAtomicIndexService.getMapper().updateById(modelAtomicIndex); - } - if (i > 0) { - return R.okMsg("保存成功"); - } else { - return R.fail("保存失败"); + + boolean success = modelAtomicIndexService.saveOrUpdate(modelAtomicIndex); + return success ? R.okMsg("保存成功") : R.fail("保存失败"); + } + + /** + * 原子指标保存前置处理 + * @param modelAtomicIndex + */ + private void saveAtomicIndexPreDo(ModelAtomicIndex modelAtomicIndex) { + if (StringUtils.equals(IndexRuleConstants.OPERAND_TYPE_DB, modelAtomicIndex.getIndexSource())) { + Assert.notEmpty(modelAtomicIndex.getCategoryId(), "分类不能为空"); + // 如果查询类型为数据查询,则校验查询语句 + Assert.notEmpty(modelAtomicIndex.getQueryLang(), "查询语言不能为空"); + Assert.isTrue(checkSql(modelAtomicIndex.getQueryLang()), "查询语句不合法"); + }else if (StringUtils.equals(IndexRuleConstants.OPERAND_TYPE_LLM, modelAtomicIndex.getIndexSource())){ + Assert.notEmpty(modelAtomicIndex.getPromptId(), "promptId不能为空"); + NotePrompt notePrompt = notePromptService.getBaseMapper().selectById(modelAtomicIndex.getPromptId()); + Assert.notNull(notePrompt, "提示词信息不存在"); + Assert.notEmpty(notePrompt.getEvidenceCategoryId(), "提示词分类为空"); + modelAtomicIndex.setCategoryId(notePrompt.getEvidenceCategoryId()); } } @@ -328,6 +348,64 @@ public class ModelIndexServiceImpl extends ServiceImpl> listAtomicIndexAttributeScope(List atomicIndexIds) { + + if (CollUtil.isEmpty(atomicIndexIds)){ + return Map.of(); + } + Map> result = atomicIndexIds.stream().collect(Collectors.toMap(i -> i, i->List.of())); + List atomicIndexList = modelAtomicIndexService.listByIds(atomicIndexIds); + if (CollUtil.isEmpty(atomicIndexList)){ + return result; + } + List promptIds = atomicIndexList.stream().map(ModelAtomicIndex::getPromptId).filter(StrUtil::isNotEmpty).toList(); + if (CollUtil.isEmpty(promptIds)){ + return result; + } + + List notePrompts = notePromptService.listByIds(promptIds); + Map dicMap = comDictionaryService.getDictionaryMapReverse("prompt_attribute_valuetype"); + + for (Map.Entry> entry : result.entrySet()) { + List scopeDTOList = makeScopes(entry.getKey(), atomicIndexList, notePrompts, dicMap); + if (scopeDTOList != null){ + entry.setValue(scopeDTOList); + } + } + return result; + } + + private List makeScopes(String atomicIndexId, List atomicIndexList, List notePrompts, Map dicMap) { + ModelAtomicIndex modelAtomicIndex = atomicIndexList.stream().filter(i -> StrUtil.equals(atomicIndexId, i.getId())).findFirst().orElse(null); + if (null == modelAtomicIndex || StrUtil.isEmpty(modelAtomicIndex.getPromptId())){ + return null; + } + String properties = modelAtomicIndex.getProperties(); + if (StrUtil.isEmpty(properties)){ + return null; + } + NotePrompt notePromptDTO = notePrompts.stream().filter(i -> StrUtil.equals(modelAtomicIndex.getPromptId(), i.getId())).findFirst().orElse(null); + if (null == notePromptDTO){ + return null; + } + List extractAttributes = notePromptDTO.getExtractAttributes(); + if (CollUtil.isNotEmpty(extractAttributes)) { + return extractAttributes.stream().map(extractAttribute -> { + ValueCalculateScopeDTO valueCalculateScope = new ValueCalculateScopeDTO(); + valueCalculateScope.setValue(extractAttribute.getAttrName()); + valueCalculateScope.setValueType(dicMap.get(extractAttribute.getAttrValueType())); + valueCalculateScope.setValueTypeDesc(extractAttribute.getAttrValueType()); + valueCalculateScope.setOperatorList( + IndexRuleConstants.VALUE_TYPE_OPERATOR_MAPPING.get(valueCalculateScope.getValueType())); + Map map = IndexRuleConstants.VALUE_TYPE_AGGREGATE_MAPPING.get(valueCalculateScope.getValueType()); + valueCalculateScope.setAggregateList(map.entrySet().stream().map(entry -> new Pair<>(entry.getKey(), entry.getValue())).toList()); + return valueCalculateScope; + }).toList(); + } + return null; + } + /** * 清空案件下的评估结果 * diff --git a/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java b/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java index 1ca1a4d..778f954 100644 --- a/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java +++ b/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java @@ -69,6 +69,10 @@ public class ModelServiceImpl implements ModelService { private final CasePersonMapper casePersonMapper; + private final CaseEvidenceService caseEvidenceService; + + private final ModelAtomicResultService modelAtomicResultService; + private final RowSqlMapper rowSqlMapper; private final ModelIndexService modelIndexService; @@ -85,12 +89,6 @@ public class ModelServiceImpl implements ModelService { @Autowired private EvidenceDirectoryService evidenceDirectoryService; - @Autowired - private CaseEvidenceService caseEvidenceService; - - @Autowired - private ModelAtomicResultService modelAtomicResultService; - @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public R analyseCase(AnalyseCaseDTO analyseCaseDTO) { @@ -566,6 +564,7 @@ public class ModelServiceImpl implements ModelService { .setOllamaChatClient(null) .setMapper(modelCaseMapper, casePersonMapper, modelAtomicIndexMapper, modelIndexResultMapper, modelIndexMapper, modelAtomicResultMapper); + caseScoreDetailBuilder.loadCaseScoreDetail(caseId); CaseScore caseScore = new CaseScore(); caseScore.setCommonScore(caseScoreDetailBuilder.getCommonScore()); diff --git a/src/main/resources/mapper/ModelAtomicIndexMapper.xml b/src/main/resources/mapper/ModelAtomicIndexMapper.xml index 401bdfe..1b529f4 100644 --- a/src/main/resources/mapper/ModelAtomicIndexMapper.xml +++ b/src/main/resources/mapper/ModelAtomicIndexMapper.xml @@ -4,30 +4,31 @@