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/OCREvidenceServiceImpl.java

340 lines
14 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.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.supervision.constant.EvidencePropertyName;
import com.supervision.constant.OcrStatusEnum;
import com.supervision.police.domain.EvidenceFile;
import com.supervision.police.domain.FileEvidenceProperty;
import com.supervision.police.domain.FileOcrProcess;
import com.supervision.police.dto.*;
import com.supervision.police.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class OCREvidenceServiceImpl implements OCREvidenceService {
private final FileOcrProcessService ocrProcessService;
private final OCRService ocrService;
private final FileEvidencePropertyService fileEvidencePropertyService;
private final EvidenceFileService evidenceFileService;
private final CaseEvidenceService caseEvidenceService;
private final OcrExtractService ocrExtractService;
private final TimedCache<String, DateTime> timedCache = CacheUtil.newTimedCache(5*60*1000);
@Override
public Boolean submitOrcTask(String fileId) {
Assert.notEmpty(fileId, "文件id不能为空");
((OCREvidenceService)AopContext.currentProxy()).asyncDoOrcTask(null, fileId);
return true;
}
/**
* 识别文件信息 由于识别文件标题需要通过组文件进行上下文分析,所以废弃单个文件识别的方式
* @param evidenceId
* @param fileId
* @return
*/
@Deprecated
@Override
@Transactional(rollbackFor = Exception.class,transactionManager = "dataSourceTransactionManager")
public List<FileEvidenceProperty> doOrcTask(String evidenceId,String fileId) {
List<FileEvidenceProperty> evidencePropertyList = new ArrayList<>();
// 识别文件信息
List<FileOcrProcess> fileOcrProcesses = ocrProcessService.syncSubmitOCR(CollUtil.newArrayList(fileId));
if (CollUtil.isEmpty(fileOcrProcesses)){
log.warn("subOrcTask:文件id:{} 识别失败", fileId);
return evidencePropertyList;
}
for (FileOcrProcess fileOcrProcess : fileOcrProcesses) {
// 调用提取属性接口
fileOcrProcess = ocrProcessService.getById(fileOcrProcess.getId());
if (StrUtil.isEmpty(fileOcrProcess.getOcrText())){
log.warn("subOrcTask:文件id:{}, 对应的ocrText属性为空跳过属性识别...", fileId);
continue;
}
log.debug("subOrcTask:远程接口retrieve开始识别文本...{}", fileOcrProcess.getOcrText());
RetrieveResDTO retrieve = ocrService.retrieve(new RetrieveReqDTO(fileOcrProcess.getOcrText()));
log.info("subOrcTask:文件id:{} 识别结果:{}", fileId, JSONUtil.toJsonStr(retrieve));
if (Integer.valueOf(0).equals(retrieve.getStatus())){
// 保存属性信息
String title = retrieve.getTitle();
if (StrUtil.isNotEmpty(title)){
evidencePropertyList.addAll(this.saveEvidenceProperty(evidenceId, fileId,
Map.of(EvidencePropertyName.TITLE.getName(), retrieve.getTitle())));
if (StrUtil.isNotEmpty(evidenceId)){
evidenceFileService.save(new EvidenceFile(evidenceId,fileId));
}
}else {
log.warn("subOrcTask:文件id:{} 识别结果为空", fileId);
}
}
}
return evidencePropertyList;
}
@Async
@Override
public void asyncDoOrcTask(String evidenceId, String fileId) {
ocrProcessService.syncSubmitOCR(CollUtil.newArrayList(fileId));
}
@Override
@Transactional(rollbackFor = Exception.class,transactionManager = "dataSourceTransactionManager")
public List<FileEvidenceProperty> saveEvidenceProperty(String evidenceId,String fileId ,Map<String, String> propertyMap) {
// 先清空数据
fileEvidencePropertyService.removeByEvidenceAndFileId(evidenceId,fileId);
List<FileEvidenceProperty> fileEvidence = toFileEvidence(evidenceId, fileId, propertyMap);
for (FileEvidenceProperty property : fileEvidence) {
fileEvidencePropertyService.save(property);
}
return fileEvidence;
}
@Override
public List<EvidenceFileOCRDTO> queryFileList(List<String> fileIdList) {
if (CollUtil.isEmpty(fileIdList)){
return new ArrayList<>(1);
}
List<OCREvidencePropertyDTO> ocrEvidencePropertyDTOS = fileEvidencePropertyService.listPrewByFileIdList(fileIdList);
List<EvidenceFileOCRDTO> collect = ocrEvidencePropertyDTOS.stream()
.collect(Collectors.groupingBy(OCREvidencePropertyDTO::getFileId))
.values().stream()
.map(EvidenceFileOCRDTO::new).peek(evidenceFileOCRDTO -> {
if (StrUtil.isEmpty(evidenceFileOCRDTO.getEvidenceType())){
evidenceFileOCRDTO.setEvidenceType("1");// 默认为书证
}
evidenceFileOCRDTO.setEvidenceNameValue();
})
.collect(Collectors.toList());
return sortByIdOrder(fileIdList, collect);
}
@Override
@Transactional(rollbackFor = Exception.class,transactionManager = "dataSourceTransactionManager")
public String saveEvidence(EvidenceFileOCRDTO evidenceFileOCRDTO) {
Assert.notEmpty(evidenceFileOCRDTO.getFileId(), "文件id不能为空");
Assert.notEmpty(evidenceFileOCRDTO.getCaseId(), "案件id不能为空");
Assert.notEmpty(evidenceFileOCRDTO.getEvidenceName(), "案件证据名称不能为空");
Assert.notEmpty(evidenceFileOCRDTO.getEvidenceType(), "案件证据类型不能为空");
//保存证据信息
String evidenceId = caseEvidenceService.saveEvidence(evidenceFileOCRDTO.toCaseEvidenceDTO());
// 保存证据属性
List<FileEvidenceProperty> evidencePropertyList = saveEvidenceProperty(evidenceId,
evidenceFileOCRDTO.getFileId(), evidenceFileOCRDTO.getProperty());
if (CollUtil.isEmpty(evidencePropertyList)){
return null;
}
return CollUtil.getFirst(evidencePropertyList).getEvidenceId();
}
@Override
public Boolean retrieveTitle(List<String> fileIdList) {
if (CollUtil.isEmpty(fileIdList)){
return false;
}
((OCREvidenceService)(AopContext.currentProxy())).asyncRetrieveTitle(fileIdList);
return true;
}
@Override
public Boolean retrieveTitleProcess(List<String> fileIdList) {
if (CollUtil.isEmpty(fileIdList)){
return true;
}
boolean timeOut = processTimeOut(fileIdList);
if (timeOut){
log.info("retrieveTitleProcess:文件识别超时,跳过等待...");
return true;
}
List<FileEvidenceProperty> properties = fileEvidencePropertyService.lambdaQuery().in(FileEvidenceProperty::getFileId, fileIdList).list();
for (String fileId : fileIdList) {
if (!evidencePropertiesExist(fileId, properties)){
return false;
}
}
return true;
}
private boolean processTimeOut(List<String> fileIdList) {
String join = StrUtil.join(",", fileIdList);
if (!timedCache.containsKey(join)){
timedCache.put(join, DateUtil.date());
return false;
}
DateTime dateTime = timedCache.get(join);
return DateUtil.between(dateTime, DateUtil.date(), DateUnit.SECOND) > fileIdList.size() * 20L;
}
@Override
@Transactional(rollbackFor = Exception.class,transactionManager = "dataSourceTransactionManager")
public List<String> batchSaveEvidence(List<EvidenceFileOCRDTO> evidenceFileOCRDTOS) {
List<String> evidenceList = new ArrayList<>();
if (CollUtil.isEmpty(evidenceFileOCRDTOS)){
return evidenceList;
}
for (EvidenceFileOCRDTO evidenceFileOCRDTO : evidenceFileOCRDTOS) {
String evidence = saveEvidence(evidenceFileOCRDTO);
evidenceList.add(evidence);
}
return evidenceList;
}
@Async
@Override
@Transactional(rollbackFor = Exception.class,transactionManager = "dataSourceTransactionManager")
public void asyncRetrieveTitle(List<String> fileIdList) {
doRetrieveTitle(fileIdList);
}
@Override
@Transactional(rollbackFor = Exception.class,transactionManager = "dataSourceTransactionManager")
public void doRetrieveTitle(List<String> fileIdList) {
List<RecordFileDTO> recordFileDTOS = waitingOCRFinish(fileIdList, 30 * fileIdList.size());
if (CollUtil.isEmpty(recordFileDTOS)){
log.warn("doRetrieveTitle:文件id:{} 未查询到文件信息...", StrUtil.join(",", fileIdList));
return;
}
List<OcrExtractDto> dtoList = recordFileDTOS.stream().map(recordFileDTO -> {
OcrExtractDto dto = new OcrExtractDto();
dto.setId(recordFileDTO.getFileId());
dto.setText(recordFileDTO.getOcrText());
return dto;
}).toList();
log.info("doRetrieveTitle,extractTitle参数是{}", JSONUtil.toJsonStr(dtoList));
List<OcrExtractDto> result = ocrExtractService.extractTitle(dtoList);
log.info("doRetrieveTitle,extractTitle返回结果是{}", JSONUtil.toJsonStr(result));
if (CollUtil.isEmpty(result)){
log.warn("retrieveTitle:文件id:{} 提取标题失败", StrUtil.join(",", fileIdList));
}
for (OcrExtractDto dto : result) {
this.saveEvidenceProperty(null, dto.getId(),
Map.of(EvidencePropertyName.TITLE.getName(), dto.getTitle()));
}
}
@Override
@Transactional(transactionManager = "dataSourceTransactionManager",rollbackFor = Exception.class)
public CaseEvidenceDetailDTO queryEvidenceDetail(String evidenceId) {
CaseEvidenceDetailDTO caseEvidenceDetailDTO = caseEvidenceService.queryEvidenceDetail(evidenceId);
if (caseEvidenceDetailDTO == null){
return null;
}
List<FileEvidenceProperty> list = fileEvidencePropertyService.lambdaQuery().eq(FileEvidenceProperty::getEvidenceId, evidenceId).list();
caseEvidenceDetailDTO.setPropertyValue(list);
return caseEvidenceDetailDTO;
}
private List<RecordFileDTO> waitingOCRFinish(List<String> fileIdList, int timeout){
DateTime date = DateUtil.date();
while (true){
List<RecordFileDTO> recordFileDTOS = ocrProcessService.queryFileListWithIdSort(fileIdList);
boolean match = recordFileDTOS.stream().allMatch(recordFileDTO ->
StrUtil.equals(recordFileDTO.getOcrStatus(), OcrStatusEnum.FAIL.getCode())
|| StrUtil.equals(recordFileDTO.getOcrStatus(), OcrStatusEnum.SUCCESS.getCode()));
if (match){
return recordFileDTOS;
}
log.info("waitingOCRFinish:等待文件id:{} 识别完成中...", StrUtil.join(",", fileIdList));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (DateUtil.between(date, DateUtil.date(), DateUnit.SECOND) > timeout){
return null;
}
}
}
private boolean evidencePropertiesExist(String fileId, List<FileEvidenceProperty> properties){
for (FileEvidenceProperty property : properties) {
if (StrUtil.equals(fileId, property.getFileId())){
return true;
}
}
return false;
}
private List<EvidenceFileOCRDTO> sortByIdOrder(List<String> fileIdList, List<EvidenceFileOCRDTO> evidenceFileOCRDTOS){
Map<String, EvidenceFileOCRDTO> fileOCRDTOMap = evidenceFileOCRDTOS.stream()
.collect(Collectors.toMap(EvidenceFileOCRDTO::getFileId, recordFileDTO -> recordFileDTO, (k1, k2) -> k1));
return fileIdList.stream().map(fileId -> {
EvidenceFileOCRDTO evidenceFileOCRDTO = fileOCRDTOMap.get(fileId);
if (Objects.isNull(evidenceFileOCRDTO)) {
evidenceFileOCRDTO = new EvidenceFileOCRDTO();
evidenceFileOCRDTO.setFileId(fileId);
evidenceFileOCRDTO.setOcrStatus(-1);
}
return evidenceFileOCRDTO;
}
).collect(Collectors.toList());
}
private List<FileEvidenceProperty> toFileEvidence(String evidenceId,String fileId ,Map<String, String> propertyMap){
if (StrUtil.isAllEmpty(evidenceId,fileId) || CollUtil.isEmpty(propertyMap)){
log.warn("saveEvidenceProperty:参数为空");
return new ArrayList<>(1);
}
return EvidencePropertyName.getByNames(propertyMap)
.stream().map(evidence ->
new FileEvidenceProperty(evidenceId, fileId, evidence.getName(), propertyMap.get(evidence.getName())))
.toList();
}
}