|
|
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();
|
|
|
|
|
|
}
|
|
|
}
|