You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fu-hsi-service/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java

916 lines
49 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.supervision.police.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.deepoove.poi.XWPFTemplate;
import com.supervision.common.constant.IndexRuleConstants;
import com.supervision.common.domain.R;
import com.supervision.common.utils.StringUtils;
import com.supervision.constant.JudgeResultEnum;
import com.supervision.neo4j.dto.ResultDTO;
import com.supervision.neo4j.utils.Neo4jUtils;
import com.supervision.police.domain.*;
import com.supervision.police.dto.*;
import com.supervision.police.dto.caseScore.CaseScore;
import com.supervision.police.dto.caseScore.CaseScoreDetailBuilder;
import com.supervision.police.dto.caseScore.CaseScoreDetailDTO;
import com.supervision.police.dto.indexRule.IndexRule;
import com.supervision.police.dto.indexRule.Operand;
import com.supervision.police.dto.indexRule.OperandUnit;
import com.supervision.police.dto.indexRule.RuleCondition;
import com.supervision.police.mapper.*;
import com.supervision.police.mybatis.RowSqlMapper;
import com.supervision.police.service.*;
import com.supervision.utils.CalculationUtil;
import com.supervision.utils.DifyApiUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Result;
import org.neo4j.driver.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static com.supervision.common.constant.IndexRuleConstants.*;
import static com.supervision.common.constant.NotePromptConstants.TYPE_STRUCTURAL_REASONING;
@Slf4j
@Service
@RequiredArgsConstructor
public class ModelServiceImpl implements ModelService {
private final ResourceLoader resourceLoader;
private final Driver driver;
private final ModelCaseMapper modelCaseMapper;
private final ModelAtomicIndexMapper modelAtomicIndexMapper;
private final ModelAtomicResultMapper modelAtomicResultMapper;
private final ModelIndexMapper modelIndexMapper;
private final ModelIndexResultMapper modelIndexResultMapper;
private final CasePersonMapper casePersonMapper;
private final CaseEvidenceService caseEvidenceService;
private final ModelAtomicResultService modelAtomicResultService;
private final RowSqlMapper rowSqlMapper;
private final ModelIndexService modelIndexService;
private final CaseStatusManageService caseStatusManageService;
private final ModelIndexAtomicRelationService modelIndexAtomicRelationService;
private final NoteRecordService noteRecordService;
@Autowired
private NotePromptService notePromptService;
@Autowired
private EvidenceDirectoryService evidenceDirectoryService;
private final EvidenceCategoryService evidenceCategoryService;
private final CaseEvidencePropertyService caseEvidencePropertyService;
private final DifyApiUtil difyApiUtil;
@Autowired
private ModelCaseService modelCaseService;
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
public R<?> analyseCase(AnalyseCaseDTO analyseCaseDTO) {
ModelCase modelCase = modelCaseMapper.selectById(analyseCaseDTO.getCaseId());
// 获取案件行为人ID
CasePerson casePerson = casePersonMapper.selectOne(new LambdaQueryWrapper<CasePerson>()
.eq(CasePerson::getCaseId, analyseCaseDTO.getCaseId())
.eq(CasePerson::getCaseActorFlag, 1)
.eq(CasePerson::getRoleCode, "1")
.eq(StrUtil.isNotEmpty(analyseCaseDTO.getLawActorName()), CasePerson::getName, analyseCaseDTO.getLawActorName()));
if (ObjectUtil.isEmpty(casePerson)) {
throw new RuntimeException("未找到的行为人" + analyseCaseDTO.getLawActorName());
}
// 首先将原先的值进行赋值,设置到pre_result
modelIndexResultMapper.updatePreResult(analyseCaseDTO.getCaseId());
//原子指标
List<ModelAtomicIndex> atomicIndices = modelAtomicIndexMapper.selectByCaseType(modelCase.getCaseType());
// 存放原子指标的结果,key:原子指标ID,value:(key大指标ID,value:结果)
Map<String, Map<String, String>> atomicResultMap = new HashMap<>();
for (ModelAtomicIndex atomicIndex : atomicIndices) {
//原子指标结果
ModelAtomicResult result = new ModelAtomicResult();
result.setCasePersonId(casePerson.getId());
result.setCaseId(analyseCaseDTO.getCaseId());
result.setAtomicId(atomicIndex.getId());
//查询语句
String ql = atomicIndex.getQueryLang();
//原子指标结果表
try {
//查询图谱 index_source: 1人工定义 2数据库查询 3图谱生成 4大模型
if ("1".equals(atomicIndex.getIndexSource())) {
// list
manuallyDefinedCase(analyseCaseDTO, result, atomicIndex);
} else if ("2".equals(atomicIndex.getIndexSource()) && StringUtils.isNotEmpty(ql)) {
//
analyseDataBaseCase(analyseCaseDTO, result, ql, casePerson.getName());
} else if ("3".equals(atomicIndex.getIndexSource()) && StringUtils.isNotEmpty(ql)) {
// 使用知识图谱进行计算
analyseGraphCase(analyseCaseDTO, result, ql, casePerson.getName());
} else if ("4".equals(atomicIndex.getIndexSource())) {
//
} else if ("5".equals(atomicIndex.getIndexSource())) {
// todo: 结构化推理
//analyseStructuredInference(analyseCaseDTO, result);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
// 根据原子指标ID查model_index_atomic_relation表所有的指标ID
List<ModelIndexAtomicRelation> relationList = modelIndexAtomicRelationService.lambdaQuery().eq(ModelIndexAtomicRelation::getAtomicIndexId, atomicIndex.getId()).list();
for (ModelIndexAtomicRelation relation : relationList) {
// 保存或更新原子指标结果表
ModelAtomicResult exist = modelAtomicResultMapper.selectByCaseIdAndAtomicId(analyseCaseDTO.getCaseId(), casePerson.getId(), relation.getModelIndexId(), atomicIndex.getId());
result.setIndexId(relation.getModelIndexId());
if (exist == null) {
result.setId(null);
modelAtomicResultMapper.insert(result);
} else {
result.setId(exist.getId());
modelAtomicResultMapper.updateById(result);
}
Map<String, String> indexMap = atomicResultMap.computeIfAbsent(
result.getAtomicId(),
k -> new HashMap<>() // 如果不存在则创建一个新的 HashMap
);
indexMap.put(relation.getModelIndexId(), result.getAtomicResult());
}
}
// 最终计算得分
calculateFinalScore(analyseCaseDTO, modelCase, atomicResultMap);
caseStatusManageService.whenAnalyseCaseSuccess(analyseCaseDTO.getCaseId(), modelCase.getTotalScore());
// 计算完成之后,把所有的笔录上传到模型
difyApiUtil.syncCaseFileToDifyKnowledgeBase(modelCase, modelCaseService.listCaseFileIds(analyseCaseDTO.getCaseId()));
return R.ok();
}
@Override
public R<?> analyseCaseNew(AnalyseCaseDTO analyseCaseDTO) {
log.info("数据准备阶段");
String caseId = analyseCaseDTO.getCaseId();
Map<String, Integer> typeScoreMap = new HashMap<>();
ModelCase modelCase = modelCaseMapper.selectById(caseId);
if (modelCase == null) {
log.error("未找到案件信息:【{}】", caseId);
return R.fail("未找到案件信息");
}
CasePerson casePerson = casePersonMapper.selectOne(new LambdaQueryWrapper<CasePerson>()
.eq(CasePerson::getCaseId, analyseCaseDTO.getCaseId())
.eq(CasePerson::getCaseActorFlag, 1)
.eq(CasePerson::getRoleCode, "1")
.eq(StrUtil.isNotEmpty(analyseCaseDTO.getLawActorName()), CasePerson::getName, analyseCaseDTO.getLawActorName()));
if (ObjectUtil.isEmpty(casePerson)) {
log.error("未找到的行为人:【{}】", analyseCaseDTO.getLawActorName());
return R.fail("未找到的行为人");
}
List<ModelIndex> modelIndices = modelIndexService.list(new LambdaQueryWrapper<ModelIndex>().eq(ModelIndex::getDataStatus, "1").eq(ModelIndex::getCaseType, modelCase.getCaseType()));
if (modelIndices.isEmpty()) {
log.error("未找到指标信息:【{}】", modelCase.getCaseType());
return R.fail("未找到指标信息");
}
List<ModelAtomicIndex> atomicIndices = modelAtomicIndexMapper.selectByCaseType(modelCase.getCaseType());
if (atomicIndices.isEmpty()) {
log.error("未找到原子指标信息:【{}】", modelCase.getCaseType());
return R.fail("未找到原子指标信息");
}
List<NotePrompt> notePrompts = notePromptService.list(new LambdaQueryWrapper<NotePrompt>().eq(NotePrompt::getType, TYPE_STRUCTURAL_REASONING));
if (notePrompts.isEmpty()) {
log.error("未找到提示词信息:【{}】", TYPE_STRUCTURAL_REASONING);
return R.fail("未找到提示词信息");
}
// 查询提示词对应的属性
for (NotePrompt notePrompt : notePrompts) {
notePrompt.setExtractAttributes(caseEvidencePropertyService.findExtractAttributes(notePrompt.getEvidenceCategoryId()));
}
List<EvidenceDirectory> evidenceDirectories = evidenceDirectoryService.list(new LambdaQueryWrapper<EvidenceDirectory>().eq(EvidenceDirectory::getCaseId, caseId));
if (evidenceDirectories.isEmpty()) {
log.error("未找到证据目录信息:【{}】", caseId);
return R.fail("未找到证据目录信息");
}
List<CaseEvidence> caseEvidences = caseEvidenceService.list(new LambdaQueryWrapper<CaseEvidence>().eq(CaseEvidence::getCaseId, caseId));
caseEvidenceService.redoExtractAttributes(caseId, caseEvidences);
List<ModelIndexAtomicRelation> modelIndexAtomicRelations = modelIndexAtomicRelationService.list();
if (modelIndexAtomicRelations.isEmpty()) {
log.error("未找到指标原子关系信息");
return R.fail("未找到指标原子关系信息");
}
List<ModelAtomicResult> modelAtomicResultList = modelAtomicResultService.lambdaQuery().eq(ModelAtomicResult::getCaseId, caseId).list();
log.info("开始计算指标结果");
// 遍历指标集合,处理每个指标的判断逻辑,得出结果
modelIndices.forEach(modelIndex -> {
log.info("开始计算指标【{}】ID:{}", modelIndex.getId(), modelIndex.getName());
IndexRule indexRule = modelIndex.getIndexRule();
Set<Boolean> ruleConditionGroupResultList = new HashSet<>();
if (indexRule != null) {
indexRule.getRuleConditionGroupList().forEach(ruleConditionGroup -> {
Set<Boolean> ruleConditionResultSet = new HashSet<>();
ruleConditionGroup.getRuleConditionList().forEach(ruleCondition -> {
Set<Boolean> operandUnitResultSet = new HashSet<>();
// 得到当前指标要求的存在关系(存在或不存在)
boolean relationSymbol = IndexRuleConstants.EVALUATE_RESULT_EXIST.equals(ruleCondition.getRelationalSymbol());
ModelAtomicIndex modelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(ruleCondition.getAtomicIndexId())).findAny().orElse(null);
if (modelAtomicIndex == null && !OPERAND_TYPE_STRUCTURE.equals(ruleCondition.getIndexSource())) {
log.error("原子指标不存在,跳出当前循环。原子指标ID:{}", ruleCondition.getAtomicIndexId());
return;
}
// 定义原子指标结果共有属性
ModelAtomicResult result = new ModelAtomicResult();
result.setIndexId(modelIndex.getId());
result.setCasePersonId(casePerson.getId());
result.setCaseId(analyseCaseDTO.getCaseId());
result.setAtomicId(ruleCondition.getAtomicIndexId());
result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
ModelAtomicResult exist = modelAtomicResultMapper.selectByCaseIdAndAtomicId(caseId, casePerson.getId(), modelIndex.getId(), ruleCondition.getAtomicIndexId());
if (exist != null) {
result.setId(exist.getId());
}
switch (ruleCondition.getIndexSource()) {
case OPERAND_TYPE_MANUAL:
operandUnitResultSet.add(relationSymbol == manualIndexAnalysis(ruleCondition.getAtomicIndexId(), caseId));
break;
case OPERAND_TYPE_DB:
operandUnitResultSet.add(relationSymbol == dbIndexAnalysis(caseId, modelAtomicIndex, evidenceDirectories, result));
break;
case OPERAND_TYPE_GRAPH:
operandUnitResultSet.add(relationSymbol == graphIndexAnalysis(casePerson.getName(), modelAtomicIndex.getQueryLang(), analyseCaseDTO.getCaseId(), ruleCondition, result));
break;
case OPERAND_TYPE_STRUCTURE:
if (ruleCondition.getOperandUnitList().isEmpty()) {
log.info("结构化查询条件为空,直接设置为不存在并更新原子指标结果");
result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
modelAtomicResultService.saveOrUpdate(result);
}
ruleCondition.getOperandUnitList().forEach(operandUnit -> operandUnitResultSet.add(structureIndexAnalysis(operandUnit, ruleCondition.getAtomicIndexId(), atomicIndices, notePrompts, evidenceDirectories, caseEvidences, result)));
break;
default:
break;
}
ruleConditionResultSet.add(CalculationUtil.calculateBooleanSet(operandUnitResultSet, ruleCondition.getLogic()));
});
ruleConditionGroupResultList.add(CalculationUtil.calculateBooleanSet(ruleConditionResultSet, ruleConditionGroup.getRowLogic()));
});
} else {
log.error("指标规则不存在,跳出当前循环。指标ID:{}", modelIndex.getId());
return;
}
// 计算指标结果并保存
boolean result = CalculationUtil.calculateBooleanSet(ruleConditionGroupResultList, indexRule.getGroupLogic());
ModelIndexResult modelIndexResult = new ModelIndexResult();
modelIndexResult.setCaseId(caseId);
modelIndexResult.setIndexId(modelIndex.getId());
modelIndexResult.setAtomicIds(modelIndexAtomicRelations.stream().filter(relation -> relation.getModelIndexId().equals(modelIndex.getId())).map(ModelIndexAtomicRelation::getAtomicIndexId).collect(Collectors.joining(",")));
ModelIndexResult exist = modelIndexResultMapper.selectByCaseIdAndIndexId(analyseCaseDTO.getCaseId(), modelIndex.getId());
if (exist != null) {
modelIndexResult.setId(exist.getId());
}
modelIndexResult.setIndexResult(result ? "true" : "false");
// 先清除掉与指标失去关联的原子指标对应的结果
removeAtomicResultWithNoReference(modelIndex.getId(), modelIndexAtomicRelations, modelAtomicResultList);
if (exist == null) {
modelIndexResultMapper.insert(modelIndexResult);
} else {
modelIndexResultMapper.updateById(modelIndexResult);
}
if (result) {
Integer score = typeScoreMap.getOrDefault(modelIndex.getIndexType(), 0);
log.info("指标ID:{},指标类型:{},得分:{}分", modelIndex.getId(), modelIndex.getIndexType(), modelIndex.getIndexScore());
typeScoreMap.put(modelIndex.getIndexType(), score + modelIndex.getIndexScore());
log.info("当前类型总分:{}分", typeScoreMap.get(modelIndex.getIndexType()));
}
});
Integer gx = typeScoreMap.getOrDefault("1", 0);
Integer rz = typeScoreMap.getOrDefault("2", 0);
Integer cz = typeScoreMap.getOrDefault("3", 0);
int max = Integer.max(gx + rz, gx + cz);
modelCase.setTotalScore(max);
log.info("更新案件得分情况。最终得分:{}分(共性+入罪/共性+出罪 取最大值)。入罪:{}分。出罪:{}分。共性:{}分。", max, rz, cz, gx);
caseStatusManageService.whenAnalyseCaseSuccess(analyseCaseDTO.getCaseId(), modelCase.getTotalScore());
difyApiUtil.syncCaseFileToDifyKnowledgeBase(modelCase, modelCaseService.listCaseFileIds(caseId));
return R.ok();
}
private void removeAtomicResultWithNoReference(String modelIndexId, List<ModelIndexAtomicRelation> modelIndexAtomicRelations,
List<ModelAtomicResult> modelAtomicResultList) {
List<String> atomicIds = modelIndexAtomicRelations.stream()
.filter(relation -> StrUtil.equals(relation.getModelIndexId(), modelIndexId))
.map(ModelIndexAtomicRelation::getAtomicIndexId).toList();
List<ModelAtomicResult> modelAtomicResults = modelAtomicResultList.stream()
.filter(atomicResult -> StrUtil.equals(atomicResult.getIndexId(), modelIndexId)
&& !atomicIds.contains(atomicResult.getAtomicId())).toList();
for (ModelAtomicResult modelAtomicResult : modelAtomicResults) {
log.info("删除无引用的原子指标结果指标id:{},原子指标ID{}", modelIndexId,modelAtomicResult.getAtomicId());
modelAtomicResultMapper.deleteById(modelAtomicResult.getId());
}
}
/**
* 人工定义指标分析
*
* @param atomicIndexId 原子指标ID
* @param caseId 案件ID
*/
private boolean manualIndexAnalysis(String atomicIndexId, String caseId) {
boolean flag = false;
List<ModelAtomicResult> modelAtomicResults = modelAtomicResultMapper.selectList(
new LambdaQueryWrapper<ModelAtomicResult>().eq(ModelAtomicResult::getCaseId, caseId)
.eq(ModelAtomicResult::getAtomicId, atomicIndexId));
if (modelAtomicResults != null && !modelAtomicResults.isEmpty()) {
ModelAtomicResult modelAtomicResult = CollUtil.getFirst(modelAtomicResults);
flag = EVALUATE_RESULT_EXIST.equals(modelAtomicResult.getAtomicResult());
}
return flag;
}
/**
* 数据库查询指标分析
*
* @param caseId 案件ID
* @param modelAtomicIndex 原子指标
* @param evidenceDirectories 证据目录
* @param atomicResult 原子指标结果
* @return
*/
private boolean dbIndexAnalysis(String caseId, ModelAtomicIndex modelAtomicIndex, List<EvidenceDirectory> evidenceDirectories, ModelAtomicResult atomicResult) {
Map<String, Object> params = new HashMap<>();
params.put("caseId", caseId);
List<Map> mapList = rowSqlMapper.selectList(modelAtomicIndex.getQueryLang(), params, Map.class);
boolean flag = false;
if (mapList != null && !mapList.isEmpty()) {
flag = evidenceDirectories.stream().anyMatch(evidenceDirectory -> StrUtil.equals(evidenceDirectory.getCategoryId(), modelAtomicIndex.getCategoryId()));
String evidenceIds = mapList.stream().map(map -> map.get("id").toString()).collect(Collectors.joining(","));
atomicResult.setEvidenceId(evidenceIds);
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
}
modelAtomicResultService.saveOrUpdate(atomicResult);
return flag;
}
/**
* 图谱查询指标分析
*
* @param casePersonName 行为人
* @param queryLang 查询语句
* @param caseId 案件ID
* @param ruleCondition 规则条件
* @param atomicResult 原子指标结果
* @return 是否存在
*/
private boolean graphIndexAnalysis(String casePersonName, String queryLang, String caseId, RuleCondition ruleCondition, ModelAtomicResult atomicResult) {
boolean flag = false;
Session session = driver.session();
//图谱
Map<String, Object> params = new HashMap<>();
// 行为人
params.put("lawActor", casePersonName);
// 案号
params.put("caseId", caseId);
Result run;
try {
run = session.run(queryLang, params);
} catch (Exception e) {
log.error("图数据库查询出现错误,查询语句{},参数{}", queryLang, JSONUtil.toJsonStr(params), e);
return flag;
}
List<ResultDTO> res = Neo4jUtils.getResultDTOList(run);
int count = 0;
if (!res.isEmpty()) {
// 进行遍历,如果有存在的,就设置为有
for (ResultDTO resultDTO : res) {
if (StringUtils.isNotEmpty(resultDTO.getRelId())) {
//存在关系
count++;
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
atomicResult.setRecordId(resultDTO.getRecordId());
// 在退出循环之前先合并相关文本分片id
String recordSplitIdJoin = res.stream().filter(r ->
StringUtils.isNotEmpty(r.getRelId())
&& StringUtils.isNotEmpty(r.getRecordSplitId()))
.map(ResultDTO::getRecordSplitId).collect(Collectors.joining(","));
atomicResult.setRecordSplitId(recordSplitIdJoin);
}
}
}
if (StringUtils.isNotEmpty(ruleCondition.getOperator()) && StringUtils.isNotEmpty(ruleCondition.getValue()) && CalculationUtil.evaluateExpression(String.valueOf(count), ruleCondition.getOperator(), ruleCondition.getValue())) {
flag = true;
}
modelAtomicResultService.saveOrUpdate(atomicResult);
return flag;
}
/**
* 结构化查询指标分析
*
* @param operandUnit 操作单元
* @param modelAtomicIndexId 原子指标ID
* @param atomicIndices 原子指标集合
* @param notePrompts 提示词集合
* @param evidenceDirectories 证据目录集合
* @param caseEvidences 证据集合
* @param atomicResult 原子指标结果
* @return 是否存在
*/
private boolean structureIndexAnalysis(OperandUnit operandUnit, String modelAtomicIndexId, List<ModelAtomicIndex> atomicIndices, List<NotePrompt> notePrompts, List<EvidenceDirectory> evidenceDirectories, List<CaseEvidence> caseEvidences, ModelAtomicResult atomicResult) {
Operand left = operandUnit.getLeftOperand();
String operator = operandUnit.getOperator();
Operand right = operandUnit.getRightOperand();
boolean flag = false;
ModelAtomicIndex modelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(modelAtomicIndexId)).findAny().orElse(null);
if (modelAtomicIndex == null) {
log.error("原子指标不存在。原子指标ID:{}", modelAtomicIndexId);
atomicResult.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return flag;
}
List<CaseEvidence> evidences = getEvidencesByPromptId(modelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(",")));
ModelAtomicIndex rightModelAtomicIndex = null;
if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
log.info("右操作数为结构化查询,提前查好对应的原子指标");
rightModelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(left.getAtomicIndexId())).findAny().orElse(null);
if (rightModelAtomicIndex == null || StringUtils.isEmpty(rightModelAtomicIndex.getPromptId())) {
log.error("原子指标不存在。原子指标ID:{}", left.getAtomicIndexId());
atomicResult.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return flag;
}
}
if (!evidences.isEmpty()) {
log.info("聚合类型为【{}】,右操作数操作类型为:【{}】", AGGREGATE_TYPE_SUM.equals(left.getAggregateType()) ? "求和" : AGGREGATE_TYPE_COUNT.equals(left.getAggregateType()) ? "计数" : "任一", OPERAND_TYPE_STRUCTURE.equals(right.getOperandType()) ? "结构化查询" : "值");
switch (left.getAggregateType()) {
case AGGREGATE_TYPE_SUM:
if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
log.info("左操作数总和:【{}】,操作符:【{}】,右操作数:【{}】", getSumFromEvidences(left.getPropertyKey(), evidences), operator, right.getValue());
List<CaseEvidence> rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
if (CalculationUtil.evaluateExpression(String.valueOf(getSumFromEvidences(left.getPropertyKey(), evidences)), operator, String.valueOf(getSumFromEvidences(right.getPropertyKey(), rightEvidences)))) {
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return true;
}
} else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) {
log.info("左操作数总和:【{}】,操作符:【{}】,右操作数:【{}】", getSumFromEvidences(left.getPropertyKey(), evidences), operator, right.getValue());
if (CalculationUtil.evaluateExpression(String.valueOf(getSumFromEvidences(left.getPropertyKey(), evidences)), operator, right.getValue())) {
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return true;
}
}
break;
case AGGREGATE_TYPE_COUNT:
if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
log.info("左操作数数量:【{}】,操作符:【{}】,右操作数:【{}】", evidences.size(), operator, right.getValue());
List<CaseEvidence> rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
if (CalculationUtil.evaluateExpression(String.valueOf(evidences.size()), operator, String.valueOf(rightEvidences.size()))) {
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return true;
}
} else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) {
log.info("左操作数数量:【{}】,操作符:【{}】,右操作数:【{}】", evidences.size(), operator, right.getValue());
if (CalculationUtil.evaluateExpression(String.valueOf(evidences.size()), operator, right.getValue())) {
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return true;
}
}
break;
case AGGREGATE_TYPE_ANY:
if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) {
List<CaseEvidence> rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts);
Set<String> leftValueSet = getValueSetFromEvidences(left, evidences);
Set<String> rightValueSet = getValueSetFromEvidences(right, rightEvidences);
log.info("左操作数值集合:【{}】,操作符:【{}】,右操作数:【{}】", leftValueSet, operator, right.getValue());
// 使用CalculationUtil.evaluateExpression方法遍历比较leftValueSet和rightValueSet的任一值一旦有一个满足返回true则return true
if (leftValueSet.stream().anyMatch(leftValue -> rightValueSet.stream().anyMatch(rightValue -> CalculationUtil.evaluateExpression(leftValue, operator, rightValue)))) {
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return true;
}
} else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) {
Set<String> leftValueSet = getValueSetFromEvidences(left, evidences);
log.info("左操作数值集合:【{}】,操作符:【{}】,右操作数:【{}】", leftValueSet, operator, right.getValue());
if (leftValueSet.stream().anyMatch(leftValue -> CalculationUtil.evaluateExpression(leftValue, operator, right.getValue()))) {
atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
return true;
}
}
break;
default:
atomicResult.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
break;
}
atomicResult.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
} else {
log.error("证据不存在。提示词ID:{}", modelAtomicIndex.getPromptId());
atomicResult.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
modelAtomicResultService.saveOrUpdate(atomicResult);
}
return flag;
}
private Double getSumFromEvidences(String propertyKey, List<CaseEvidence> evidences) {
AtomicReference<Double> sum = new AtomicReference<>(0.0);
if (evidences != null && !evidences.isEmpty()) {
evidences.forEach(e -> {
List<NotePromptExtractAttributesDto> properties = e.getProperty();
if (properties != null && !properties.isEmpty()) {
properties.forEach(p -> {
if (p.getAttrName().equals(propertyKey)) {
if (StringUtils.isNotEmpty(p.getAttrValue())) {
sum.updateAndGet(v -> v + NumberUtil.parseDouble(p.getAttrValue()));
}
}
});
}
});
}
return sum.get();
}
private Set<String> getValueSetFromEvidences(Operand operand, List<CaseEvidence> evidences) {
Set<String> valueSet = new HashSet<>();
evidences.forEach(e -> {
List<NotePromptExtractAttributesDto> properties = e.getProperty();
if (properties != null && !properties.isEmpty()) {
properties.forEach(p -> {
if (p.getAttrName().equals(operand.getPropertyKey())) {
if (StringUtils.isNotEmpty(p.getAttrValue())) {
valueSet.add(p.getAttrValue());
}
}
});
}
});
return valueSet;
}
/**
* 根据原子指标ID获取证据集合
*
* @param promptId 提示词ID
* @param caseEvidences 全量案件证据集合
* @param evidenceDirectories 证据目录集合
* @param notePrompts 提示词集合
* @return 证据集合
*/
private static List<CaseEvidence> getEvidencesByPromptId(String promptId, List<CaseEvidence> caseEvidences, List<EvidenceDirectory> evidenceDirectories, List<NotePrompt> notePrompts) {
List<CaseEvidence> evidences = new ArrayList<>();
NotePrompt notePrompt = notePrompts.stream().filter(n -> n.getId().equals(promptId)).findAny().orElse(null);
if (notePrompt == null) {
log.error("提示词不存在。提示词ID:{}", promptId);
return evidences;
}
List<EvidenceDirectory> directories = evidenceDirectories.stream().filter(e -> e.getCategoryId().equals(notePrompt.getEvidenceCategoryId())).toList();
List<String> directoryIds = directories.stream().map(EvidenceDirectory::getId).toList();
evidences = caseEvidences.stream().filter(e -> directoryIds.contains(e.getDirectoryId())).toList();
return evidences;
}
/**
* 手动定义原子指标处理
*
* @param analyseCaseDTO 案件信息
* @param result 原子指标结果
* @param atomicIndex 原子指标
*/
private void manuallyDefinedCase(AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult result, ModelAtomicIndex atomicIndex) {
List<ModelAtomicResult> modelAtomicResults = modelAtomicResultMapper.selectList(
new LambdaQueryWrapper<ModelAtomicResult>().eq(ModelAtomicResult::getCaseId, analyseCaseDTO.getCaseId())
.eq(ModelAtomicResult::getAtomicId, atomicIndex.getId()));
if (CollUtil.isEmpty(modelAtomicResults)) {
log.info("manuallyDefinedCase:根据caseId:{},atomicId:{}未找到原子指标结果", analyseCaseDTO.getCaseId(), atomicIndex.getId());
return;
}
if (CollUtil.size(modelAtomicResults) > 0) {
log.warn("manuallyDefinedCase:根据caseId:{},atomicId:{}找到多个原子指标结果", analyseCaseDTO.getCaseId(), atomicIndex.getId());
}
ModelAtomicResult modelAtomicResult = CollUtil.getFirst(modelAtomicResults);
result.setAtomicResult(modelAtomicResult.getAtomicResult());
}
@Override
public CaseScoreDetailDTO caseScoreDetail(String caseId) {
Assert.notEmpty(caseId, "案件id不能为空");
CaseScoreDetailBuilder caseScoreDetailBuilder = new CaseScoreDetailBuilder()
.setOllamaChatClient(null)
.setMapper(modelCaseMapper, casePersonMapper, modelAtomicIndexMapper,
modelIndexResultMapper, modelIndexMapper, modelAtomicResultMapper);
caseScoreDetailBuilder.loadCaseScoreDetail(caseId);
List<EvidenceDirectoryDTO> evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId);
List<EvidenceCategoryDTO> evidenceCategoryDTOS = evidenceCategoryService.listCategoryTree(caseScoreDetailBuilder.getCaseType());
caseScoreDetailBuilder.setEvidence(new EvidenceDirectoryDTO(evidenceDirectoryDTOS), new EvidenceCategoryDTO(evidenceCategoryDTOS));
return caseScoreDetailBuilder.build();
}
@Override
public CaseScore caseScoreByCaseId(String caseId) {
CaseScoreDetailBuilder caseScoreDetailBuilder = new CaseScoreDetailBuilder()
.setOllamaChatClient(null)
.setMapper(modelCaseMapper, casePersonMapper, modelAtomicIndexMapper,
modelIndexResultMapper, modelIndexMapper, modelAtomicResultMapper);
caseScoreDetailBuilder.loadCaseScoreDetail(caseId);
CaseScore caseScore = new CaseScore();
caseScore.setCommonScore(caseScoreDetailBuilder.getCommonScore());
caseScore.setCrimeScore(caseScoreDetailBuilder.getCrimeScore());
caseScore.setCrimeOutScore(caseScoreDetailBuilder.getCrimeOutScore());
return caseScore;
}
@Override
public CaseStatus getCaseDateStatus(String caseId) {
Assert.notEmpty(caseId, "案件id不能为空");
ModelCase modelCase = modelCaseMapper.selectById(caseId);
Assert.notNull(modelCase, "案件不存在");
return new CaseStatus(modelCase.getCaseDataStatus(), modelCase.getCaseAnalysisStatus());
}
@Override
public void exportCaseScoreDetail(String caseId, HttpServletResponse response) {
CaseScoreDetailDTO caseScoreDetailDTO = caseScoreDetail(caseId);
caseScoreDetailDTO.buildDesc();
// 加载模板
Resource resource = resourceLoader.getResource("classpath:template/case_detail.docx");
InputStream inputStream = null;
try {
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(caseScoreDetailDTO.getCaseName() + ".docx", StandardCharsets.UTF_8));
inputStream = resource.getInputStream();
XWPFTemplate template = XWPFTemplate.compile(inputStream).render(caseScoreDetailDTO);
template.writeAndClose(response.getOutputStream());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error("exportCaseScoreDetail: inputStream.close() error", e);
}
}
}
}
/**
* 最终计算得分
*/
private void calculateFinalScore(AnalyseCaseDTO analyseCaseDTO, ModelCase modelCase, Map<String, Map<String, String>> atomicResultMap) {
// 根据案件类型获取所有的指标
List<ModelIndex> modelIndices = modelIndexService.list(new LambdaQueryWrapper<ModelIndex>().eq(ModelIndex::getDataStatus, "1").eq(ModelIndex::getCaseType, modelCase.getCaseType()));
Map<String, Integer> typeScoreMap = new HashMap<>();
for (ModelIndex modelIndex : modelIndices) {
ModelIndexResult result = new ModelIndexResult();
result.setCaseId(analyseCaseDTO.getCaseId());
result.setIndexId(modelIndex.getId());
Set<String> atomicIds = new HashSet<>();
// 判断逻辑是否为空,如果不为空,就根据判断逻辑进行判断
if (StringUtils.isNotEmpty(modelIndex.getJudgeLogic())) {
List<JudgeLogic> judgeLogics = JSONUtil.toList(modelIndex.getJudgeLogic(), JudgeLogic.class);
if (CollUtil.isNotEmpty(judgeLogics)) {
boolean finalJudgeResult = false;
// 遍历组
for (int i = 0; i < judgeLogics.size(); i++) {
// 组内结果
boolean innerGroupJudge = false;
JudgeLogic logic = judgeLogics.get(i);
// 获取组之间的的判断逻辑
String rowLogic = logic.getRowLogic();
// 首先对组内进行判断,判断组内的结果
List<AtomicData> atomicData = logic.getAtomicData();
for (int j = 0; j < atomicData.size(); j++) {
AtomicData data = atomicData.get(j);
atomicIds.add(data.getAtomicIndex());
// 先找到原子指标对应的大指标的结果
Map<String, String> atomicIndexMap = atomicResultMap.get(data.getAtomicIndex());
String atomicIndexResult;
if (CollUtil.isEmpty(atomicIndexMap)) {
atomicIndexResult = JudgeResultEnum.UNKNOWN.getCode();
} else {
// 这里可能不存在,如果未找到,就默认为false
atomicIndexResult = atomicIndexMap.getOrDefault(modelIndex.getId(), JudgeResultEnum.UNKNOWN.getCode());
}
String relationalSymbol = data.getRelationalSymbol();
JudgeResultEnum instance = JudgeResultEnum.getInstance(relationalSymbol);
boolean ato = StrUtil.equals(atomicIndexResult, instance.getCode());
if (j == 0) {
innerGroupJudge = ato;
} else {
if ("1".equals(rowLogic)) {
innerGroupJudge = innerGroupJudge && ato;
} else if ("2".equals(rowLogic)) {
innerGroupJudge = innerGroupJudge || ato;
}
}
}
// 组间进行判断
String groupLogic = logic.getGroupLogic();
if (i == 0) {
finalJudgeResult = innerGroupJudge;
} else {
// 如果组间判断为1 与,则进行与操作
if ("1".equals(groupLogic)) {
finalJudgeResult = finalJudgeResult && innerGroupJudge;
// 如果组间判断为或,则进行或操作
} else if ("2".equals(groupLogic)) {
finalJudgeResult = finalJudgeResult || innerGroupJudge;
}
}
}
result.setIndexResult(finalJudgeResult ? "true" : "false");
result.setAtomicIds(StringUtils.join(atomicIds, ","));
}
}
// 最后保存结果
ModelIndexResult exist = modelIndexResultMapper.selectByCaseIdAndIndexId(analyseCaseDTO.getCaseId(), modelIndex.getId());
if (exist == null) {
modelIndexResultMapper.insert(result);
} else {
result.setId(exist.getId());
modelIndexResultMapper.updateById(result);
}
if ("true".equals(result.getIndexResult())) {
Integer orDefault = typeScoreMap.getOrDefault(modelIndex.getIndexType(), 0);
typeScoreMap.put(modelIndex.getIndexType(), orDefault + modelIndex.getIndexScore());
}
}
// 计算分数 共性+入罪/共性+出罪 取最大值
Integer gx = typeScoreMap.getOrDefault("1", 0);
Integer rz = typeScoreMap.getOrDefault("2", 0);
Integer cz = typeScoreMap.getOrDefault("3", 0);
int max = Integer.max(gx + rz, gx + cz);
modelCase.setTotalScore(max);
modelCaseMapper.updateById(modelCase);
}
private void analyseGraphCase(AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult result, String ql, String caseActorName) {
Session session = driver.session();
//图谱
int i = 1;
Map<String, Object> params = new HashMap<>();
// 行为人
params.put("lawActor", caseActorName);
// 案号
params.put("caseId", analyseCaseDTO.getCaseId());
// 参数中是否传了受害人
String lawPartys = analyseCaseDTO.getLawParty();
// 如果有受害人的话就进行分割
String[] split = StringUtils.isEmpty(lawPartys) ? new String[0] : lawPartys.split(",");
if (ql.contains("$lawParty") && split.length > 1) {
i = split.length;
}
// 只有有符合的,就认为符合,不进行遍历了
judge:
for (int j = 0; j < i; j++) {
if (split.length > 0) {
params.put("lawParty", split[j]);
}
Result run;
try {
run = session.run(ql, params);
} catch (Exception e) {
result.setAtomicResult("-1");
log.error("图数据库查询出现错误,查询语句{},参数{}", ql, JSONUtil.toJsonStr(params), e);
return;
}
List<ResultDTO> res = Neo4jUtils.getResultDTOList(run);
if (res.isEmpty()) {
result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
} else {
// 设置为0,不存在
result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode());
// 进行遍历,如果有存在的,就设置为有
for (ResultDTO resultDTO : res) {
if (StringUtils.isNotEmpty(resultDTO.getRelId())) {
//存在关系
result.setAtomicResult(JudgeResultEnum.EXIST.getCode());
result.setRecordId(resultDTO.getRecordId());
// 在退出循环之前先合并相关文本分片id
String recordSplitIdJoin = res.stream().filter(r ->
StringUtils.isNotEmpty(r.getRelId())
&& StringUtils.isNotEmpty(r.getRecordSplitId()))
.map(ResultDTO::getRecordSplitId).collect(Collectors.joining(","));
result.setRecordSplitId(recordSplitIdJoin);
// 如果只要存在,就不进行校验了,直接跳出循环
break judge;
}
}
}
}
}
/**
* 分析数据库类型的原子信息
*
* @param analyseCaseDTO
* @param result
* @param sql
*/
private void analyseDataBaseCase(AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult result, String sql, String caseActorName) {
Map<String, Object> params = new HashMap<>();
params.put("caseId", result.getCaseId());
params.put("evidenceName", analyseCaseDTO.getEvidenceName());
params.put("provider", null);
params.put("party_a", caseActorName);
params.put("party_b", analyseCaseDTO.getLawParty());
boolean success = false;
if (modelIndexService.checkSql(sql)) {
success = parseResult(rowSqlMapper.selectList(sql, params, Map.class));
}
result.setAtomicResult(success ? JudgeResultEnum.EXIST.getCode() : JudgeResultEnum.NOT_EXIST.getCode());
}
/**
* 执行结果分析:
* 1. 如果查询出的结果只有一行判断列数是否大于1如果大于1返回真如果=1继续判断值是否大于0如果大于0返回真如果=0返回假
* 2. 如果查询出的结果大于一行,则返回真
*
* @param mapList 查询结果
* @return
*/
private boolean parseResult(List<Map> mapList) {
if (CollUtil.isEmpty(mapList)) {
return false;
}
if (CollUtil.size(mapList) > 1) {
return true;
}
Map firstRow = CollUtil.getFirst(mapList);
if (firstRow.size() == 1 && CollUtil.size(firstRow.values()) == 1) {
Object first = CollUtil.getFirst(firstRow.values());
if (NumberUtil.isNumber(first.toString())) {
return NumberUtil.parseInt(first.toString()) > 0;
}
}
return true;
}
}