招标解析算法服务
This commit is contained in:
parent
a808af2289
commit
ecfbcf43bc
|
|
@ -91,6 +91,14 @@ public class AnalysisController extends BaseController {
|
|||
return analysisService.editBidData(dto);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "招标解析", notes = "删除项目数据")
|
||||
@PostMapping("delBidData")
|
||||
@SysLog(title = "招标解析", module = "招标解析->删除项目数据", businessType = OperaType.DELETE, details = "删除项目数据", logType = 1)
|
||||
@RequiresPermissions("analysis:analysis:del")
|
||||
public AjaxResult delProData(@RequestBody AnalysisDto.TemplateDto dto) {
|
||||
return analysisService.delProData(dto);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "测试mq异步消息", notes = "测试mq异步消息")
|
||||
@GetMapping("/testAsyncMq2")
|
||||
public AjaxResult testAsyncMq2() {
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@ public class AnalysisService {
|
|||
@Resource(name = "ValidatorsUtils")
|
||||
private ValidatorsUtils validatorsUtils;
|
||||
|
||||
|
||||
|
||||
@Resource(name = "WordConvertPdfService")
|
||||
private WordConvertPdfService wordConvertPdfService;
|
||||
|
||||
|
|
@ -148,6 +146,8 @@ public class AnalysisService {
|
|||
@Transactional(rollbackFor = Exception.class)
|
||||
public AjaxResult saveData(AnalysisDto.TemplateDto dto) {
|
||||
try {
|
||||
// 异步任务集合
|
||||
List<Map<String,Object>> asyncTaskList = new ArrayList<>();
|
||||
// 校验数据是否合法
|
||||
String validResult = validatorsUtils.valid(dto, AnalysisDto.TemplateDto.ADD.class);
|
||||
if (StringUtils.isNotBlank(validResult)) {
|
||||
|
|
@ -168,12 +168,19 @@ public class AnalysisService {
|
|||
Long id = compositions.get(i).getId();
|
||||
dto.getFiles().get(i).setBusinessId(id);
|
||||
dto.getFiles().get(i).setSourceTable(TableConstants.TB_PRO_COMPOSITION);
|
||||
// 添加异步任务数据
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
map.put("taskId", taskId);
|
||||
map.put("uploadPath", dto.getFiles().get(i).getFilePath());
|
||||
map.put("businessId", dto.getProId());
|
||||
map.put("templateId",dto.getTemplateId());
|
||||
map.put("analysisLabelId",dto.getAnalysisLabelId());
|
||||
asyncTaskList.add(map);
|
||||
}
|
||||
sourceFileService.saveResourceFile(dto.getFiles());
|
||||
// 同步解析规则数据
|
||||
// 执行异步解析任务
|
||||
/*CompletableFuture.runAsync(() -> {
|
||||
}, taskExecutor);*/
|
||||
// 执行异步任务
|
||||
AsyncManager.me().executeSendRabbitMqMessage(asyncTaskList);
|
||||
return AjaxResult.success();
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString(),e);
|
||||
|
|
@ -291,5 +298,43 @@ public class AnalysisService {
|
|||
return AjaxResult.error();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除项目数据
|
||||
* @param dto
|
||||
* @return AjaxResult
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:42
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AjaxResult delProData(AnalysisDto.TemplateDto dto) {
|
||||
try {
|
||||
// 校验数据是否合法
|
||||
String validResult = validatorsUtils.valid(dto, AnalysisDto.TemplateDto.DELETE.class);
|
||||
if (StringUtils.isNotBlank(validResult)) {
|
||||
return AjaxResult.error(validResult);
|
||||
}
|
||||
// 删除项目数据
|
||||
analysisService.delProData(dto);
|
||||
// 删除标段数据
|
||||
analysisService.delBidData(dto);
|
||||
// 删除项目组成文件
|
||||
List<ProComposition> compositions = analysisService.getProComposition(dto);
|
||||
if(CollectionUtils.isNotEmpty(compositions)){
|
||||
for (ProComposition composition : compositions) {
|
||||
sourceFileService.delResourceFileByTable(composition.getId(),TableConstants.TB_PRO_COMPOSITION);
|
||||
}
|
||||
}
|
||||
// 删除模板组成数据
|
||||
analysisService.delProComposition(dto);
|
||||
// 删除项目/标段解析数据
|
||||
analysisService.delProBidAnalysisResult(dto);
|
||||
return AjaxResult.success();
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString(),e);
|
||||
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||
return AjaxResult.error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ ocr:
|
|||
service:
|
||||
url: http://192.168.0.37:9091/extract # ocr 请求地址
|
||||
convertUrl: http://192.168.0.37:10000/extract # word 转pdf 请求地址
|
||||
analysisUrl: http://192.168.0.37:10001/extract # 招标解析算法服务 请求地址
|
||||
processPdfUrl: http://192.168.0.37:10001/process-pdf # 招标解析算法服务 请求地址
|
||||
extractInfoUrl: http://192.168.0.37:10001/extract-info # 招标解析算法服务 请求地址
|
||||
timeout: 30000 # ocr 请求超时时间
|
||||
max-connections: 100
|
||||
|
|
@ -5,7 +5,9 @@ import com.bonus.common.domain.analysis.dto.AnalysisDto;
|
|||
import com.bonus.common.domain.analysis.dto.AnalysisProDto;
|
||||
import com.bonus.common.domain.analysis.po.ProComposition;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisBidVo;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -90,4 +92,49 @@ public interface IASAnalysisMapper {
|
|||
* @date 2025/11/26 15:55
|
||||
*/
|
||||
List<ProComposition> getProComposition(AnalysisDto.TemplateDto dto);
|
||||
|
||||
/**
|
||||
* 获取解析标签项
|
||||
* @param analysisLabelId
|
||||
* @return List<AnalysisLabelItemVo>
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 14:49
|
||||
*/
|
||||
List<AnalysisLabelItemOcrVo> getAnalysisLabels(@Param("analysisLabelId") Long analysisLabelId, @Param("templateId") Long templateId);
|
||||
|
||||
/**
|
||||
* 删除项目数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:51
|
||||
*/
|
||||
void delProData(AnalysisDto.TemplateDto dto);
|
||||
|
||||
/**
|
||||
* 删除标段数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:51
|
||||
*/
|
||||
void delBidData(AnalysisDto.TemplateDto dto);
|
||||
|
||||
/**
|
||||
* 删除模板组成数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:51
|
||||
*/
|
||||
void delProComposition(AnalysisDto.TemplateDto dto);
|
||||
|
||||
/**
|
||||
* 删除项目/标段解析数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:51
|
||||
*/
|
||||
void delProBidAnalysisResult(AnalysisDto.TemplateDto dto);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.bonus.common.domain.analysis.dto.AnalysisDto;
|
|||
import com.bonus.common.domain.analysis.dto.AnalysisProDto;
|
||||
import com.bonus.common.domain.analysis.po.ProComposition;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisBidVo;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisVo;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -88,4 +89,50 @@ public interface IASAnalysisService {
|
|||
* @date 2025/11/26 15:54
|
||||
*/
|
||||
List<ProComposition> getProComposition(AnalysisDto.TemplateDto dto);
|
||||
|
||||
|
||||
/**
|
||||
* 获取解析标签项
|
||||
* @param analysisLabelId
|
||||
* @return List<AnalysisLabelItemVo>
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 14:48
|
||||
*/
|
||||
List<AnalysisLabelItemOcrVo> getAnalysisLabels(Long analysisLabelId, Long templateId);
|
||||
|
||||
/**
|
||||
* 删除项目数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:48
|
||||
*/
|
||||
void delProData(AnalysisDto.TemplateDto dto);
|
||||
|
||||
/**
|
||||
* 删除标段数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:48
|
||||
*/
|
||||
void delBidData(AnalysisDto.TemplateDto dto);
|
||||
|
||||
/**
|
||||
* 删除模板组成数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:48
|
||||
*/
|
||||
void delProComposition(AnalysisDto.TemplateDto dto);
|
||||
|
||||
/**
|
||||
* 删除项目/标段解析数据
|
||||
* @param dto
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 15:48
|
||||
*/
|
||||
void delProBidAnalysisResult(AnalysisDto.TemplateDto dto);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import com.bonus.common.domain.analysis.dto.AnalysisDto;
|
|||
import com.bonus.common.domain.analysis.dto.AnalysisProDto;
|
||||
import com.bonus.common.domain.analysis.po.ProComposition;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisBidVo;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
|
@ -78,4 +78,33 @@ public class ASAnalysisServiceImpl implements IASAnalysisService {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnalysisLabelItemOcrVo> getAnalysisLabels(Long analysisLabelId, Long templateId) {
|
||||
try {
|
||||
return Optional.ofNullable(analysisMapper.getAnalysisLabels(analysisLabelId,templateId)).orElse(new ArrayList());
|
||||
} catch (Exception e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delProData(AnalysisDto.TemplateDto dto) {
|
||||
analysisMapper.delProData(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delBidData(AnalysisDto.TemplateDto dto) {
|
||||
analysisMapper.delBidData(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delProComposition(AnalysisDto.TemplateDto dto) {
|
||||
analysisMapper.delProComposition(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delProBidAnalysisResult(AnalysisDto.TemplateDto dto) {
|
||||
analysisMapper.delProBidAnalysisResult(dto);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,4 +118,38 @@
|
|||
composition_file_name AS compositionFileName
|
||||
FROM tb_pro_composition WHERE pro_id = #{proId} AND composition_type = #{compositionType}
|
||||
</select>
|
||||
|
||||
<!--获取解析标签项-->
|
||||
<select id="getAnalysisLabels" resultType="com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo">
|
||||
SELECT tali.analysis_label_item_id AS id,
|
||||
tali.analysis_name AS searchKeyword,
|
||||
tali.analysis_code AS targetField,
|
||||
tali.parent_id AS parentId,
|
||||
tali.analysis_level AS analysisLevel,
|
||||
tali.analysis_sort AS analysisSort,
|
||||
tars.prompt_word AS description
|
||||
FROM tb_analysis_label_item tali
|
||||
LEFT JOIN tb_analysis_rule_set tars ON tali.analysis_label_item_id = tars.analysis_label_item_id AND tars.template_id = #{templateId}
|
||||
WHERE tali.analysis_label_id = #{analysisLabelId} AND tali.del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!--删除项目数据-->
|
||||
<update id="delProData">
|
||||
UPDATE tb_pro SET del_flag = '1' WHERE pro_id = #{proId}
|
||||
</update>
|
||||
|
||||
<!--删除标段数据-->
|
||||
<update id="delBidData">
|
||||
UPDATE tb_pro_bid SET del_flag = '1' WHERE pro_id = #{proId}
|
||||
</update>
|
||||
|
||||
<!--删除模板组成数据-->
|
||||
<update id="delProComposition">
|
||||
DELETE FROM tb_pro_composition WHERE pro_id = #{proId}
|
||||
</update>
|
||||
|
||||
<!--删除项目/标段解析数据-->
|
||||
<update id="delProBidAnalysisResult">
|
||||
DELETE FROM tb_pro_bid_analysis_result WHERE pro_id = #{proId}
|
||||
</update>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -147,4 +147,5 @@ public class AnalysisBidDto {
|
|||
*/
|
||||
public interface UPDATE {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,11 +50,15 @@ public class AnalysisDto {
|
|||
/**
|
||||
* 项目id
|
||||
* */
|
||||
@NotNull(message = "项目ID不能为空", groups = {DELETE.class})
|
||||
private Long proId;
|
||||
|
||||
@NotNull(message = "模板不能为空", groups = {ADD.class})
|
||||
private Long templateId;
|
||||
|
||||
@NotNull(message = "标签组id不能为空", groups = {ADD.class})
|
||||
private Long analysisLabelId;
|
||||
|
||||
/**文件组成名称*/
|
||||
private String[] uploadType;
|
||||
|
||||
|
|
@ -108,5 +112,11 @@ public class AnalysisDto {
|
|||
public interface ADD {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除条件限制
|
||||
*/
|
||||
public interface DELETE {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
package com.bonus.common.domain.analysis.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* @className:AnalysisLabelItemVo
|
||||
* @author:cwchen
|
||||
* @date:2025-11-29-14:42
|
||||
* @version:1.0
|
||||
* @description:解析标签项
|
||||
*/
|
||||
@Data
|
||||
public class AnalysisLabelItemOcrVo {
|
||||
|
||||
|
||||
/**
|
||||
* 配置id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
|
||||
/**
|
||||
* 解析名称
|
||||
*/
|
||||
private String searchKeyword;
|
||||
|
||||
/**
|
||||
* 解析编码
|
||||
*/
|
||||
private String targetField;
|
||||
|
||||
/**
|
||||
* 父节点
|
||||
*/
|
||||
private String parentId;
|
||||
|
||||
/**
|
||||
* 层级
|
||||
*/
|
||||
private Integer analysisLevel;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer analysisSort;
|
||||
|
||||
/**
|
||||
* 提示词
|
||||
* */
|
||||
private String description;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.bonus.common.domain.ocr.dto;
|
||||
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @className:AnalysisOcrRequest
|
||||
* @author:cwchen
|
||||
* @date:2025-11-29-13:33
|
||||
* @version:1.0
|
||||
* @description: 招标解析orc请求
|
||||
*/
|
||||
@Data
|
||||
public class AnalysisOcrRequest {
|
||||
|
||||
@JsonProperty("file")
|
||||
private File file; // 文件对象
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type; // 文件类型
|
||||
|
||||
@JsonProperty("fields_json")
|
||||
private String fields_json;
|
||||
|
||||
@JsonProperty("analysisType")
|
||||
private String analysisType; // 招标解析类型 1.招标解析一次处理 2.招标解析二次处理
|
||||
|
||||
private String gpus = "2";
|
||||
|
||||
private String doc_folder_path;
|
||||
private String cover_keys;
|
||||
private List<AnalysisLabelItemOcrVo> extraction_items;
|
||||
|
||||
public AnalysisOcrRequest(String doc_folder_path, String cover_keys, List<AnalysisLabelItemOcrVo> extraction_items) {
|
||||
this.doc_folder_path = doc_folder_path;
|
||||
this.cover_keys = cover_keys;
|
||||
this.extraction_items = extraction_items;
|
||||
}
|
||||
|
||||
public AnalysisOcrRequest(File file, String type, String fields_json, String analysisType) {
|
||||
this.file = file;
|
||||
this.type = type;
|
||||
this.fields_json = fields_json;
|
||||
this.analysisType = analysisType;
|
||||
}
|
||||
|
||||
public AnalysisOcrRequest() {
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,21 @@ public class RabbitMqMessage implements Serializable {
|
|||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 业务id
|
||||
* */
|
||||
private Long businessId;
|
||||
|
||||
/**
|
||||
* 标签组id
|
||||
* */
|
||||
private Long analysisLabelId;
|
||||
|
||||
/**
|
||||
* 模板id
|
||||
* */
|
||||
private Long templateId;
|
||||
|
||||
/**
|
||||
* 消息名称/任务类型
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -26,4 +26,10 @@ public class SelectVo {
|
|||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private String uploadType;
|
||||
|
||||
/**
|
||||
* 解析标签组id
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private String analysisLabelId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.bonus.ocr.service;
|
||||
|
||||
import com.bonus.common.domain.ocr.dto.OcrRequest;
|
||||
import com.bonus.common.domain.ocr.dto.AnalysisOcrRequest;
|
||||
import com.bonus.common.domain.ocr.vo.AnalysisResponse;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.HttpEntity;
|
||||
|
|
@ -9,6 +10,7 @@ import org.apache.http.client.config.RequestConfig;
|
|||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.entity.mime.content.FileBody;
|
||||
|
|
@ -20,10 +22,10 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @className: 招标解析算法服务
|
||||
* @className: 招标解析算法服务 - 处理pdf文件
|
||||
* @author: cwchen
|
||||
* @date: 2025-10-16-10:35
|
||||
* @version: 1.0
|
||||
|
|
@ -35,11 +37,14 @@ public class AnalysisOcrService {
|
|||
|
||||
private static final String UTF_8 = "UTF-8";
|
||||
private static final String FILE_PART_NAME = "file";
|
||||
private static final String TYPE_PART_NAME = "type";
|
||||
private static final String FIELDS_JSON_PART_NAME = "fields_json";
|
||||
private static final String GPUS = "gpus";
|
||||
|
||||
@Value("${ocr.service.processPdfUrl}")
|
||||
private String processPdfUrl;
|
||||
|
||||
@Value("${ocr.service.extractInfoUrl}")
|
||||
private String extractInfoUrl;
|
||||
|
||||
@Value("${ocr.service.analysisUrl}")
|
||||
private String ocrServiceUrl;
|
||||
|
||||
@Value("${ocr.service.timeout}")
|
||||
private int timeout;
|
||||
|
|
@ -63,45 +68,65 @@ public class AnalysisOcrService {
|
|||
/**
|
||||
* 调用招标解析服务
|
||||
*
|
||||
* @param ocrRequest 招标解析请求参数
|
||||
* @param analysisOcrRequest 招标解析请求参数
|
||||
* @return OCR响应结果
|
||||
* @throws IOException 当招标解析算法服务调用失败时抛出
|
||||
*/
|
||||
public AnalysisResponse callOcrService(OcrRequest ocrRequest) throws IOException {
|
||||
validateOcrRequest(ocrRequest);
|
||||
public AnalysisResponse callOcrService(AnalysisOcrRequest analysisOcrRequest) throws IOException {
|
||||
if (Objects.equals(analysisOcrRequest.getAnalysisType(), "1")) {
|
||||
// 招标解析一次处理
|
||||
validateAnalysisOcrRequest(analysisOcrRequest);
|
||||
} else {
|
||||
// 招标解析二次处理
|
||||
validateAnalysisOcrRequest2(analysisOcrRequest);
|
||||
}
|
||||
|
||||
|
||||
HttpPost httpPost = null;
|
||||
try {
|
||||
httpPost = createHttpPost(ocrRequest);
|
||||
return executeOcrRequest(httpPost);
|
||||
// 一次解析处理
|
||||
if (Objects.equals(analysisOcrRequest.getAnalysisType(), "1")) {
|
||||
httpPost = createHttpPost(analysisOcrRequest);
|
||||
} else {
|
||||
// 二次解析处理
|
||||
httpPost = createHttpPost2(analysisOcrRequest);
|
||||
}
|
||||
return executeAnalysisOcrRequest(httpPost);
|
||||
} catch (IOException e) {
|
||||
log.error("调用招标解析算法服务失败", e);
|
||||
return null;
|
||||
} finally {
|
||||
cleanupResources(ocrRequest, httpPost);
|
||||
cleanupResources(analysisOcrRequest, httpPost);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证招标解析算法请求参数
|
||||
* 验证招标解析算法一次请求参数
|
||||
*/
|
||||
private void validateOcrRequest(OcrRequest ocrRequest) {
|
||||
if (ocrRequest == null) {
|
||||
private void validateAnalysisOcrRequest(AnalysisOcrRequest analysisOcrRequest) {
|
||||
if (analysisOcrRequest == null) {
|
||||
throw new IllegalArgumentException("招标解析算法请求参数不能为空");
|
||||
}
|
||||
if (ocrRequest.getFile() == null || !ocrRequest.getFile().exists()) {
|
||||
if (analysisOcrRequest.getFile() == null || !analysisOcrRequest.getFile().exists()) {
|
||||
throw new IllegalArgumentException("招标解析文件不能为空或文件不存在");
|
||||
}
|
||||
if (ocrRequest.getType() == null || ocrRequest.getType().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("招标解析类型不能为空");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证招标解析算法二次请求参数
|
||||
*/
|
||||
private void validateAnalysisOcrRequest2(AnalysisOcrRequest analysisOcrRequest) {
|
||||
if (analysisOcrRequest == null) {
|
||||
throw new IllegalArgumentException("招标解析算法请求参数不能为空");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建HTTP POST请求
|
||||
*/
|
||||
private HttpPost createHttpPost(OcrRequest ocrRequest) {
|
||||
HttpPost httpPost = new HttpPost(ocrServiceUrl);
|
||||
private HttpPost createHttpPost(AnalysisOcrRequest analysisOcrRequest) {
|
||||
HttpPost httpPost = new HttpPost(processPdfUrl);
|
||||
|
||||
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||
builder.setCharset(StandardCharsets.UTF_8);
|
||||
|
|
@ -109,32 +134,51 @@ public class AnalysisOcrService {
|
|||
|
||||
// 添加文件字段
|
||||
builder.addPart(FILE_PART_NAME,
|
||||
new FileBody(ocrRequest.getFile(),
|
||||
new FileBody(analysisOcrRequest.getFile(),
|
||||
ContentType.MULTIPART_FORM_DATA,
|
||||
ocrRequest.getFile().getName()));
|
||||
|
||||
// 添加类型字段
|
||||
builder.addTextBody(TYPE_PART_NAME,
|
||||
ocrRequest.getType(),
|
||||
analysisOcrRequest.getFile().getName()));
|
||||
// 添加GPUS字段
|
||||
builder.addTextBody(GPUS,
|
||||
analysisOcrRequest.getGpus(),
|
||||
ContentType.TEXT_PLAIN.withCharset(UTF_8));
|
||||
|
||||
// 添加解析内容字段
|
||||
if (ocrRequest.getFields_json() != null) {
|
||||
builder.addTextBody(FIELDS_JSON_PART_NAME,
|
||||
ocrRequest.getFields_json(),
|
||||
ContentType.TEXT_PLAIN.withCharset(UTF_8));
|
||||
}
|
||||
|
||||
httpPost.setEntity(builder.build());
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
|
||||
return httpPost;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建HTTP POST请求2
|
||||
*/
|
||||
private HttpPost createHttpPost2(AnalysisOcrRequest analysisOcrRequest) {
|
||||
HttpPost httpPost = new HttpPost(extractInfoUrl);
|
||||
|
||||
try {
|
||||
// 将请求对象转换为JSON字符串
|
||||
String jsonRequest = convertToJson(analysisOcrRequest);
|
||||
// 设置请求体为JSON
|
||||
StringEntity entity = new StringEntity(jsonRequest, ContentType.APPLICATION_JSON);
|
||||
httpPost.setEntity(entity);
|
||||
// 设置请求头
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("创建HTTP POST请求失败", e);
|
||||
}
|
||||
return httpPost;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求对象转换为JSON字符串
|
||||
*/
|
||||
private String convertToJson(AnalysisOcrRequest request) throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
return objectMapper.writeValueAsString(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行招标解析算法请求
|
||||
*/
|
||||
private AnalysisResponse executeOcrRequest(HttpPost httpPost) throws IOException {
|
||||
private AnalysisResponse executeAnalysisOcrRequest(HttpPost httpPost) throws IOException {
|
||||
log.info("开始调用招标解析算法服务");
|
||||
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
|
|
@ -182,58 +226,34 @@ public class AnalysisOcrService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理OCR识别结果
|
||||
*/
|
||||
private void handleOcrResult(AnalysisResponse AnalysisResponse) {
|
||||
if (AnalysisResponse.isSuccess()) {
|
||||
log.info("OCR识别成功");
|
||||
logOcrResults(AnalysisResponse);
|
||||
} else {
|
||||
log.warn("OCR识别失败", AnalysisResponse.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录OCR识别结果
|
||||
*/
|
||||
private void logOcrResults(AnalysisResponse AnalysisResponse) {
|
||||
Optional.ofNullable(AnalysisResponse.getData())
|
||||
.ifPresent(data -> {
|
||||
if (log.isInfoEnabled()) {
|
||||
data.forEach((key, value) ->
|
||||
log.info("识别结果 - key: {}, value: {}", key, value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理资源
|
||||
*/
|
||||
private void cleanupResources(OcrRequest ocrRequest, HttpPost httpPost) {
|
||||
private void cleanupResources(AnalysisOcrRequest analysisOcrRequest, HttpPost httpPost) {
|
||||
// 清理HTTP连接
|
||||
if (httpPost != null) {
|
||||
httpPost.releaseConnection();
|
||||
}
|
||||
|
||||
// 清理临时文件
|
||||
cleanupTempFile(ocrRequest);
|
||||
if (Objects.equals(analysisOcrRequest.getAnalysisType(), "1")) {
|
||||
// 清理临时文件
|
||||
cleanupTempFile(analysisOcrRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理临时文件
|
||||
*/
|
||||
private void cleanupTempFile(OcrRequest ocrRequest) {
|
||||
if (ocrRequest.getFile() != null && ocrRequest.getFile().exists()) {
|
||||
private void cleanupTempFile(AnalysisOcrRequest analysisOcrRequest) {
|
||||
if (analysisOcrRequest.getFile() != null && analysisOcrRequest.getFile().exists()) {
|
||||
try {
|
||||
boolean deleted = ocrRequest.getFile().delete();
|
||||
boolean deleted = analysisOcrRequest.getFile().delete();
|
||||
if (!deleted) {
|
||||
log.warn("临时文件删除失败: {}", ocrRequest.getFile().getAbsolutePath());
|
||||
log.warn("临时文件删除失败: {}", analysisOcrRequest.getFile().getAbsolutePath());
|
||||
} else {
|
||||
log.debug("临时文件已删除: {}", ocrRequest.getFile().getAbsolutePath());
|
||||
log.debug("临时文件已删除: {}", analysisOcrRequest.getFile().getAbsolutePath());
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
log.error("删除临时文件时发生安全异常: {}", ocrRequest.getFile().getAbsolutePath(), e);
|
||||
log.error("删除临时文件时发生安全异常: {}", analysisOcrRequest.getFile().getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@
|
|||
<groupId>com.bonus</groupId>
|
||||
<artifactId>bonus-file</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.bonus</groupId>
|
||||
<artifactId>bonus-analysis</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.bonus.rabbitmq.consumer;
|
||||
|
||||
import com.bonus.common.domain.ocr.dto.OcrRequest;
|
||||
import com.bonus.analysis.service.IASAnalysisService;
|
||||
import com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo;
|
||||
import com.bonus.common.domain.ocr.dto.AnalysisOcrRequest;
|
||||
import com.bonus.common.domain.ocr.vo.AnalysisResponse;
|
||||
import com.bonus.common.domain.rabbitmq.dto.RabbitMqMessage;
|
||||
import com.bonus.common.utils.FileUtil;
|
||||
|
|
@ -10,6 +12,7 @@ import com.bonus.ocr.service.AnalysisOcrService;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
|
@ -18,7 +21,9 @@ import javax.annotation.Resource;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @className:RabbitMQConsumerService
|
||||
|
|
@ -42,6 +47,11 @@ public class RabbitMQConsumerService {
|
|||
@Resource(name = "AnalysisOcrService")
|
||||
private AnalysisOcrService analysisOcrService;
|
||||
|
||||
@Resource(name = "IASAnalysisService")
|
||||
private IASAnalysisService analysisService;
|
||||
|
||||
|
||||
|
||||
@RabbitListener(
|
||||
queues = "myQueue",
|
||||
containerFactory = "multiConsumerFactory" // 使用上面配置的工厂,保证按顺序消费
|
||||
|
|
@ -100,7 +110,18 @@ public class RabbitMQConsumerService {
|
|||
String uploadPath = message.getUploadPath();
|
||||
File fileFromMinio = getFileFromMinio(uploadPath);
|
||||
AnalysisResponse ocrResponse = performAnalysisRecognition(fileFromMinio);
|
||||
|
||||
String folderPath = Optional.ofNullable(ocrResponse)
|
||||
.map(AnalysisResponse::getData)
|
||||
.map(data -> data.get("folder_path"))
|
||||
.filter(Objects::nonNull)
|
||||
.map(Object::toString)
|
||||
.orElse(null);
|
||||
if(StringUtils.isNotBlank(folderPath)) {
|
||||
// 一次处理解析成功后执行二次处理
|
||||
performAnalysisRecognition2(message, folderPath);
|
||||
}else{
|
||||
// 解析失败
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -131,8 +152,8 @@ public class RabbitMQConsumerService {
|
|||
*/
|
||||
private AnalysisResponse performAnalysisRecognition(File file) {
|
||||
try {
|
||||
OcrRequest ocrRequest = buildOcrRequest(file);
|
||||
AnalysisResponse ocrResponse = analysisOcrService.callOcrService(ocrRequest);
|
||||
AnalysisOcrRequest analysisOcrRequest = buildOcrRequest(file);
|
||||
AnalysisResponse ocrResponse = analysisOcrService.callOcrService(analysisOcrRequest);
|
||||
// 修复:检查 招标解析算法服务 响应是否为 null
|
||||
if (Objects.isNull(ocrResponse)) {
|
||||
throw new RuntimeException("招标解析算法服务返回结果为空");
|
||||
|
|
@ -146,17 +167,49 @@ public class RabbitMQConsumerService {
|
|||
}
|
||||
}
|
||||
|
||||
public void performAnalysisRecognition2(RabbitMqMessage message,String folderPath){
|
||||
try {
|
||||
List<AnalysisLabelItemOcrVo> labelItemVoList = analysisService.getAnalysisLabels(message.getAnalysisLabelId(),message.getTemplateId());
|
||||
AnalysisOcrRequest analysisOcrRequest = buildOcrRequest2(folderPath, labelItemVoList);
|
||||
AnalysisResponse ocrResponse2 = analysisOcrService.callOcrService(analysisOcrRequest);
|
||||
// 修复:检查 招标解析算法服务 响应是否为 null
|
||||
if (Objects.isNull(ocrResponse2)) {
|
||||
throw new RuntimeException("招标解析算法服务返回结果为空");
|
||||
}
|
||||
log.info("OCR识别成功 - 数据: {}", ocrResponse2.getData());
|
||||
} catch (IOException e) {
|
||||
log.error("OCR识别失败", e);
|
||||
throw new RuntimeException("OCR识别失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建招标解析算法服务请求
|
||||
* 构建招标解析算法服务请求 - 一次处理
|
||||
* @param file
|
||||
* @return OcrRequest
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 13:29
|
||||
*/
|
||||
private OcrRequest buildOcrRequest(File file) {
|
||||
OcrRequest ocrRequest = new OcrRequest();
|
||||
private AnalysisOcrRequest buildOcrRequest(File file) {
|
||||
AnalysisOcrRequest ocrRequest = new AnalysisOcrRequest();
|
||||
ocrRequest.setFile(file);
|
||||
ocrRequest.setType(FileUtil.getMimeTypeByFilename(file.getName()));
|
||||
ocrRequest.setAnalysisType("1");
|
||||
return ocrRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建招标解析算法服务请求 - 二次处理
|
||||
* @return OcrRequest
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 13:29
|
||||
*/
|
||||
private AnalysisOcrRequest buildOcrRequest2(String filePath,List<AnalysisLabelItemOcrVo> list) {
|
||||
AnalysisOcrRequest ocrRequest = new AnalysisOcrRequest();
|
||||
ocrRequest.setCover_keys("");
|
||||
ocrRequest.setExtraction_items(list);
|
||||
ocrRequest.setDoc_folder_path(filePath);
|
||||
ocrRequest.setAnalysisType("2");
|
||||
return ocrRequest;
|
||||
}
|
||||
}
|
||||
|
|
@ -21,13 +21,26 @@ public class SendRabbitMqService {
|
|||
@Resource(name = "RabbitMQProducerService")
|
||||
private RabbitMQProducerService rabbitMQProducerService;
|
||||
|
||||
/**
|
||||
* 招标解析mq
|
||||
* @param list
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2025/11/29 14:04
|
||||
*/
|
||||
public void sendRabbitMq(List<Map<String,Object>> list){
|
||||
for (Map<String,Object> map : list) {
|
||||
String taskId = map.get("taskId").toString();
|
||||
String uploadPath = map.get("uploadPath").toString();
|
||||
String analysisLabelId = map.get("analysisLabelId").toString();
|
||||
String businessId = map.get("businessId").toString();
|
||||
String templateId = map.get("templateId").toString();
|
||||
RabbitMqMessage mqMessage = new RabbitMqMessage();
|
||||
mqMessage.setMessageId(taskId);
|
||||
mqMessage.setUploadPath(uploadPath);
|
||||
mqMessage.setBusinessId(Long.parseLong(businessId));
|
||||
mqMessage.setAnalysisLabelId(Long.parseLong(analysisLabelId));
|
||||
mqMessage.setTemplateId(Long.parseLong(templateId));
|
||||
mqMessage.setTaskName("OCR_PROCESS");
|
||||
rabbitMQProducerService.sendMessageSync(mqMessage);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<select id="getAnalysisSelects" resultType="com.bonus.common.domain.system.vo.SelectVo">
|
||||
SELECT tt.template_id AS id,
|
||||
tt.template_name AS name,
|
||||
GROUP_CONCAT(ttc.file_name) AS uploadType
|
||||
GROUP_CONCAT(ttc.file_name) AS uploadType,
|
||||
tt.analysis_label_id AS analysisLabelId
|
||||
FROM tb_template tt
|
||||
LEFT JOIN tb_template_composition ttc ON tt.template_id = ttc.template_id AND ttc.composition_type = '1'
|
||||
WHERE tt.use_state = '0' AND tt.del_flag = '0'
|
||||
|
|
|
|||
Loading…
Reference in New Issue