package com.supervision.police.service.impl; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.supervision.police.dto.*; import com.supervision.police.service.*; import com.supervision.police.domain.CaseEvidence; import com.supervision.police.domain.ComDictionary; import com.supervision.police.domain.EvidenceFile; import com.supervision.common.constant.EvidenceConstants; import com.supervision.police.domain.*; import com.supervision.police.mapper.CaseEvidenceMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Map; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor public class CaseEvidenceServiceImpl extends ServiceImpl implements CaseEvidenceService { private final EvidenceFileService evidenceFileService; private final ComDictionaryService comDictionaryService; private final CaseStatusManageService caseStatusManageService; private final FileOcrProcessService fileOcrProcessService; @Autowired private OCREvidenceService ocrEvidenceService; @Autowired private LLMExtractService llmExtractService; @Autowired private EvidenceDirectoryService evidenceDirectoryService; @Autowired private EvidenceCategoryService evidenceCategoryService; @Autowired private NotePromptService notePromptService; @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public String saveEvidence(CaseEvidenceDTO caseEvidenceDTO) { // 必填校验 caseEvidencePersistenceAssert(caseEvidenceDTO); // 保存证据信息 CaseEvidence caseEvidence = caseEvidenceDTO.toCaseEvidence(); super.save(caseEvidence); //保存文件关联信息 caseEvidenceDTO.getFileIdList().forEach(fileId -> { EvidenceFile evidenceFile = new EvidenceFile(); evidenceFile.setFileId(fileId); evidenceFile.setEvidenceId(caseEvidence.getId()); evidenceFileService.save(evidenceFile); }); caseStatusManageService.whenUpdateEvidence(caseEvidence.getCaseId()); return caseEvidence.getId(); } private void caseEvidencePersistenceAssert(CaseEvidenceDTO caseEvidenceDTO) { Assert.notEmpty(caseEvidenceDTO.getCaseId(), "案件id不能为空"); Assert.notEmpty(caseEvidenceDTO.getEvidenceName(), "证据名称不能为空"); Assert.notEmpty(caseEvidenceDTO.getEvidenceType(), "证据类型不能为空"); //Assert.notEmpty(caseEvidenceDTO.getProvider(),"证据提供人不能为空"); Assert.notEmpty(caseEvidenceDTO.getFileIdList(), "文件id不能为空"); } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public String updateEvidence(CaseEvidenceDTO caseEvidenceDTO) { Assert.notEmpty(caseEvidenceDTO.getId(), "证据id不能为空"); caseEvidencePersistenceAssert(caseEvidenceDTO); super.getOptById(caseEvidenceDTO.getId()).orElseThrow(() -> new IllegalArgumentException("证据信息不存在")); // 更新证据信息 CaseEvidence caseEvidence = caseEvidenceDTO.toCaseEvidence(); super.updateById(caseEvidence); // 更新文件关联信息 evidenceFileService.lambdaUpdate().eq(EvidenceFile::getEvidenceId, caseEvidence.getId()).remove(); caseEvidenceDTO.getFileIdList().forEach(fileId -> { EvidenceFile evidenceFile = new EvidenceFile(); evidenceFile.setFileId(fileId); evidenceFile.setEvidenceId(caseEvidence.getId()); evidenceFileService.save(evidenceFile); }); caseStatusManageService.whenUpdateEvidence(caseEvidenceDTO.getCaseId()); // 更新证据属性信息 for (String fileId : caseEvidenceDTO.getFileIdList()) { caseEvidenceDTO.setTitleProperty(); ocrEvidenceService.saveEvidenceProperty(caseEvidence.getId(), fileId, caseEvidenceDTO.getProperty()); } return caseEvidenceDTO.getId(); } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public boolean deleteEvidence(String evidenceId) { CaseEvidence caseEvidence = super.getOptById(evidenceId).orElseThrow(() -> new IllegalArgumentException("证据信息不存在")); boolean remove = super.lambdaUpdate().eq(CaseEvidence::getId, evidenceId).remove(); if (remove) { evidenceFileService.lambdaUpdate().eq(EvidenceFile::getEvidenceId, evidenceId).remove(); caseStatusManageService.whenUpdateEvidence(caseEvidence.getCaseId()); } return remove; } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public List queryEvidenceList(String caseId) { return super.getBaseMapper().queryEvidenceList(caseId); } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public IPage pageListEvidence(String caseId, String evidenceName, Integer pageNum, Integer pageSize) { Assert.notEmpty(caseId, "案件id不能为空"); Page caseEvidencePage = super.lambdaQuery().eq(CaseEvidence::getCaseId, caseId) .like(StrUtil.isNotEmpty(evidenceName), CaseEvidence::getEvidenceName, evidenceName) .orderBy(true, false, CaseEvidence::getUpdateTime) .page(new Page<>(pageNum, pageSize)); if (caseEvidencePage.getTotal() == 0) { return PageDTO.of(pageNum, pageSize, 0); } // 查询文件信息 List evidenceIds = caseEvidencePage.getRecords().stream().map(CaseEvidence::getId).distinct().toList(); List fileInfoList = evidenceFileService.listFileInfo(evidenceIds); Map> evidenceFileMap = fileInfoList.stream().collect(Collectors.groupingBy(EvidenceFileDTO::getEvidenceId)); List recordFileDTOS = fileOcrProcessService.queryFileList(fileInfoList.stream().map(EvidenceFileDTO::getFileId).toList()); // 转换分页结果 //查询字典 List evidenceTypeDic = comDictionaryService.lambdaQuery().eq(ComDictionary::getType, "evidence_type").list(); return caseEvidencePage.convert(caseEvidence -> { CaseEvidenceDetailDTO caseEvidenceDetailDTO = new CaseEvidenceDetailDTO(caseEvidence, evidenceFileMap.get(caseEvidence.getId())); caseEvidenceDetailDTO.setEvidenceTypeDesc( comDictionaryService.getName(evidenceTypeDic, "evidence_type", caseEvidence.getEvidenceType())); caseEvidenceDetailDTO.setContentTypeValue(recordFileDTOS); return caseEvidenceDetailDTO; }); } @Override public CaseEvidenceDetailDTO queryEvidenceDetail(String evidenceId) { return super.getBaseMapper().queryEvidenceDetail(evidenceId); } @Override public void evidenceAnalysis(String evidenceId) { log.info("证据解析开始。证据ID:【{}】", evidenceId); long start = System.currentTimeMillis(); LLMExtractDto llmExtractDto = new LLMExtractDto(); // 查出证据、文件、如果证据 CaseEvidence caseEvidence = getById(evidenceId); if (caseEvidence == null) { log.error("证据不存在"); return; } List evidenceFiles = evidenceFileService.lambdaQuery().eq(EvidenceFile::getEvidenceId, evidenceId).list(); if (evidenceFiles.isEmpty()) { log.error("证据文件不存在"); return; } try { // 根据rank升序排序 evidenceFiles.sort(Comparator.comparing(EvidenceFile::getRank)); log.info("OCR识别开始。证据文件ID:【{}】", evidenceFiles.stream().map(EvidenceFile::getFileId).toList()); long ocrStart = System.currentTimeMillis(); List fileOcrProcesses = fileOcrProcessService.syncSubmitOCR(evidenceFiles.stream().map(EvidenceFile::getFileId).toList()); log.info("OCR识别完成。更新证据处理状态为【OCR识别完成】。耗时:【{}】ms", System.currentTimeMillis() - ocrStart); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_OCR_OK); updateById(caseEvidence); // 遍历OCR结果拼接ocrText并赋值给lLMExtractDto的text StringBuilder ocrText = new StringBuilder(); fileOcrProcesses.forEach(fileOcrProcess -> ocrText.append(fileOcrProcess.getOcrText())); llmExtractDto.setText(ocrText.toString()); log.info("标题提取开始。"); long titleStart = System.currentTimeMillis(); llmExtractDto = llmExtractService.extractTitle(Collections.singletonList(llmExtractDto)).get(0); log.info("标题提取完成。更新证据处理状态为【标题提取完成】。标题:【{}】。耗时:【{}】ms", llmExtractDto.getTitle(), System.currentTimeMillis() - titleStart); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_TITLE_EXTRACT_OK); updateById(caseEvidence); // 根据证据目录id查询提示词 EvidenceDirectory directory = evidenceDirectoryService.getById(caseEvidence.getDirectoryId()); EvidenceCategory category = evidenceCategoryService.getById(directory.getCategoryId()); NotePrompt notePrompt = notePromptService.getById(category.getPromptId()); if (notePrompt != null) { log.info("属性提取开始。"); long attrStart = System.currentTimeMillis(); llmExtractDto.setPrompt(notePrompt.getPrompt()); llmExtractDto.setExtractAttributes(notePrompt.getExtractAttributes()); llmExtractDto = llmExtractService.extractAttribute(Collections.singletonList(llmExtractDto)).get(0); Map map = new HashMap<>(); llmExtractDto.getExtractAttributes().forEach(notePromptExtractAttribute -> map.put(notePromptExtractAttribute.getAttrName(), notePromptExtractAttribute.getAttrValue())); caseEvidence.setProperty(map); log.info("属性提取完成。更新证据处理状态为【属性提取完成】。属性:【{}】。耗时:【{}】", caseEvidence.getProperty(), System.currentTimeMillis() - attrStart); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_ATTR_EXTRACT_OK); updateById(caseEvidence); } else { log.info("没有关联提示词,不提取属性"); } log.info("证据解析完成。更新证据处理状态为【处理成功】。"); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_SUCCESS); updateById(caseEvidence); } catch (Exception e) { log.error("证据解析失败。更新证据处理状态为【处理失败】。"); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_FAILED); updateById(caseEvidence); } finally { log.info("证据解析完成。证据ID:【{}】耗时:【{}】ms", evidenceId, System.currentTimeMillis() - start); } } @Override public List listCategoryTree(String caseType) { Assert.notEmpty(caseType,"案件类型不能为空!"); return evidenceCategoryService.listCategoryTree(caseType); } }