招标解析算法服务

This commit is contained in:
cwchen 2025-11-29 16:57:05 +08:00
parent ecfbcf43bc
commit 36e99617e3
11 changed files with 180 additions and 33 deletions

View File

@ -92,13 +92,21 @@ public class AnalysisController extends BaseController {
} }
@ApiOperation(value = "招标解析", notes = "删除项目数据") @ApiOperation(value = "招标解析", notes = "删除项目数据")
@PostMapping("delBidData") @PostMapping("delProData")
@SysLog(title = "招标解析", module = "招标解析->删除项目数据", businessType = OperaType.DELETE, details = "删除项目数据", logType = 1) @SysLog(title = "招标解析", module = "招标解析->删除项目数据", businessType = OperaType.DELETE, details = "删除项目数据", logType = 1)
@RequiresPermissions("analysis:analysis:del") @RequiresPermissions("analysis:analysis:del")
public AjaxResult delProData(@RequestBody AnalysisDto.TemplateDto dto) { public AjaxResult delProData(@RequestBody AnalysisDto.TemplateDto dto) {
return analysisService.delProData(dto); return analysisService.delProData(dto);
} }
@ApiOperation(value = "招标解析", notes = "标段提交文件解析")
@PostMapping("saveBidData")
@SysLog(title = "招标解析", module = "招标解析->标段提交文件解析", businessType = OperaType.INSERT, details = "标段提交文件解析", logType = 1)
@RequiresPermissions("analysis:analysis:add")
public AjaxResult saveBidData(@RequestBody AnalysisDto.TemplateBidDto dto) {
return analysisService.saveBidData(dto);
}
@ApiOperation(value = "测试mq异步消息", notes = "测试mq异步消息") @ApiOperation(value = "测试mq异步消息", notes = "测试mq异步消息")
@GetMapping("/testAsyncMq2") @GetMapping("/testAsyncMq2")
public AjaxResult testAsyncMq2() { public AjaxResult testAsyncMq2() {

View File

@ -14,6 +14,7 @@ import com.bonus.common.domain.file.vo.ResourceFileVo;
import com.bonus.common.domain.file.vo.SysFile; import com.bonus.common.domain.file.vo.SysFile;
import com.bonus.common.domain.ocr.dto.OcrRequest; import com.bonus.common.domain.ocr.dto.OcrRequest;
import com.bonus.common.domain.ocr.vo.WordConvertPdfResponse; import com.bonus.common.domain.ocr.vo.WordConvertPdfResponse;
import com.bonus.common.domain.rabbitmq.dto.RabbitMqMessage;
import com.bonus.common.utils.Base64ToPdfConverter; import com.bonus.common.utils.Base64ToPdfConverter;
import com.bonus.common.utils.ValidatorsUtils; import com.bonus.common.utils.ValidatorsUtils;
import com.bonus.file.service.FileUploadService; import com.bonus.file.service.FileUploadService;
@ -120,7 +121,7 @@ public class AnalysisService {
map.put("uploadPath", uploadPath); map.put("uploadPath", uploadPath);
list.add(map); list.add(map);
} }
AsyncManager.me().executeSendRabbitMqMessage(list); // AsyncManager.me().executeSendRabbitMqMessage(list);
return AjaxResult.success(); return AjaxResult.success();
} }
@ -147,7 +148,7 @@ public class AnalysisService {
public AjaxResult saveData(AnalysisDto.TemplateDto dto) { public AjaxResult saveData(AnalysisDto.TemplateDto dto) {
try { try {
// 异步任务集合 // 异步任务集合
List<Map<String,Object>> asyncTaskList = new ArrayList<>(); List<RabbitMqMessage> asyncTaskList = new ArrayList<>();
// 校验数据是否合法 // 校验数据是否合法
String validResult = validatorsUtils.valid(dto, AnalysisDto.TemplateDto.ADD.class); String validResult = validatorsUtils.valid(dto, AnalysisDto.TemplateDto.ADD.class);
if (StringUtils.isNotBlank(validResult)) { if (StringUtils.isNotBlank(validResult)) {
@ -169,14 +170,15 @@ public class AnalysisService {
dto.getFiles().get(i).setBusinessId(id); dto.getFiles().get(i).setBusinessId(id);
dto.getFiles().get(i).setSourceTable(TableConstants.TB_PRO_COMPOSITION); dto.getFiles().get(i).setSourceTable(TableConstants.TB_PRO_COMPOSITION);
// 添加异步任务数据 // 添加异步任务数据
Map<String, Object> map = new HashMap<>(); RabbitMqMessage msg = new RabbitMqMessage();
String taskId = UUID.randomUUID().toString(); String taskId = UUID.randomUUID().toString();
map.put("taskId", taskId); msg.setMessageId(taskId);
map.put("uploadPath", dto.getFiles().get(i).getFilePath()); msg.setUploadPath(dto.getFiles().get(i).getFilePath());
map.put("businessId", dto.getProId()); msg.setProId(dto.getProId());
map.put("templateId",dto.getTemplateId()); msg.setTemplateId(dto.getTemplateId());
map.put("analysisLabelId",dto.getAnalysisLabelId()); msg.setAnalysisLabelId(dto.getAnalysisLabelId());
asyncTaskList.add(map); msg.setTaskName("OCR_PROCESS");
asyncTaskList.add(msg);
} }
sourceFileService.saveResourceFile(dto.getFiles()); sourceFileService.saveResourceFile(dto.getFiles());
// 执行异步任务 // 执行异步任务
@ -336,5 +338,57 @@ public class AnalysisService {
return AjaxResult.error(); return AjaxResult.error();
} }
} }
/**
* 招标解析->标段提交文件解析
* @param dto
* @return AjaxResult
* @author cwchen
* @date 2025/11/29 16:17
*/
@Transactional(rollbackFor = Exception.class)
public AjaxResult saveBidData(AnalysisDto.TemplateBidDto dto) {
try {
// 异步任务集合
List<RabbitMqMessage> asyncTaskList = new ArrayList<>();
// 校验数据是否合法
String validResult = validatorsUtils.valid(dto, AnalysisDto.TemplateBidDto.ADD.class);
if (StringUtils.isNotBlank(validResult)) {
return AjaxResult.error(validResult);
}
List<ProComposition> compositions = new ArrayList<>();
for (String uploadType : dto.getUploadType()) {
ProComposition vo = createVo(dto.getBidId(), uploadType,"2");
compositions.add(vo);
}
// 保存标段的文件组成数据
analysisService.addProCompositionData(compositions);
// 添加文件
for (int i = 0; i < compositions.size(); i++) {
Long id = compositions.get(i).getId();
dto.getFiles().get(i).setBusinessId(id);
dto.getFiles().get(i).setSourceTable(TableConstants.TB_PRO_COMPOSITION);
// 添加异步任务数据
RabbitMqMessage msg = new RabbitMqMessage();
String taskId = UUID.randomUUID().toString();
msg.setMessageId(taskId);
msg.setUploadPath(dto.getFiles().get(i).getFilePath());
msg.setProId(dto.getProId());
msg.setBidId(dto.getBidId());
msg.setTaskName("OCR_PROCESS");
asyncTaskList.add(msg);
}
sourceFileService.saveResourceFile(dto.getFiles());
// 执行异步任务
AsyncManager.me().executeSendRabbitMqMessage(asyncTaskList);
return AjaxResult.success();
} catch (Exception e) {
log.error(e.toString(),e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return AjaxResult.error();
}
}
} }

View File

@ -122,8 +122,8 @@
<!--获取解析标签项--> <!--获取解析标签项-->
<select id="getAnalysisLabels" resultType="com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo"> <select id="getAnalysisLabels" resultType="com.bonus.common.domain.analysis.vo.AnalysisLabelItemOcrVo">
SELECT tali.analysis_label_item_id AS id, SELECT tali.analysis_label_item_id AS id,
tali.analysis_name AS searchKeyword, tali.analysis_name AS search_keyword,
tali.analysis_code AS targetField, tali.analysis_code AS target_field,
tali.parent_id AS parentId, tali.parent_id AS parentId,
tali.analysis_level AS analysisLevel, tali.analysis_level AS analysisLevel,
tali.analysis_sort AS analysisSort, tali.analysis_sort AS analysisSort,

View File

@ -42,8 +42,12 @@ public class AnalysisDto {
/**开标结束日期*/ /**开标结束日期*/
private String endDate; private String endDate;
/**项目解析模板*/
private TemplateDto templateDto; private TemplateDto templateDto;
/**标段解析模板*/
private TemplateBidDto templateBidDto;
@Data @Data
public static class TemplateDto{ public static class TemplateDto{
@ -119,4 +123,38 @@ public class AnalysisDto {
} }
} }
@Data
public static class TemplateBidDto{
/**
* 项目id
* */
@NotNull(message = "项目ID不能为空", groups = {ADD.class})
private Long proId;
@NotNull(message = "标段id不能为空", groups = {ADD.class})
private Long bidId;
/**文件组成名称*/
private String[] uploadType;
/**模板组成类型 1.项目文件 2.标段/标包文件*/
private String compositionType = "2";
/**
* 资源文件
*/
@NotEmpty(message = "文件不能为空", groups = {ADD.class})
private List<ResourceFilePo> files;
/**
* 新增条件限制
*/
public interface ADD {
}
}
} }

View File

@ -23,12 +23,12 @@ public class AnalysisLabelItemOcrVo {
/** /**
* 解析名称 * 解析名称
*/ */
private String searchKeyword; private String search_keyword;
/** /**
* 解析编码 * 解析编码
*/ */
private String targetField; private String target_field;
/** /**
* 父节点 * 父节点

View File

@ -18,7 +18,12 @@ public class RabbitMqMessage implements Serializable {
/** /**
* 业务id * 业务id
* */ * */
private Long businessId; private Long proId;
/**
* 标段id
* */
private Long bidId;
/** /**
* 标签组id * 标签组id

View File

@ -528,6 +528,32 @@ public class MinioUtil {
} }
} }
public File getFileFromMinio2(String bucketName, String objectName) throws Exception {
Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), "minio_downloads");
Files.createDirectories(tempDir);
// 处理各种路径分隔符
String normalizedPath = objectName.replace('\\', '/');
// 获取文件名包含后缀
String safeFileName = normalizedPath.substring(normalizedPath.lastIndexOf('/') + 1);
// String fileName = "minio_" + System.currentTimeMillis() + "_" + safeFileName;
String fileName = "minio_" + "_" + safeFileName;
Path tempFilePath = tempDir.resolve(fileName);
try (InputStream stream = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build())) {
Files.copy(stream, tempFilePath, StandardCopyOption.REPLACE_EXISTING);
return tempFilePath.toFile();
} catch (Exception e) {
Files.deleteIfExists(tempFilePath);
throw e;
}
}
/** /**
* 获取安全的文件名移除路径和非法字符 * 获取安全的文件名移除路径和非法字符
*/ */
@ -558,4 +584,5 @@ public class MinioUtil {
return fileName.isEmpty() ? "minio_file" : fileName; return fileName.isEmpty() ? "minio_file" : fileName;
} }
} }

View File

@ -7,6 +7,7 @@ import java.util.TimerTask;
import java.util.concurrent.*; import java.util.concurrent.*;
import com.bonus.common.domain.file.po.ResourceFileRecordPo; import com.bonus.common.domain.file.po.ResourceFileRecordPo;
import com.bonus.common.domain.rabbitmq.dto.RabbitMqMessage;
import com.bonus.common.utils.Threads; import com.bonus.common.utils.Threads;
import com.bonus.common.utils.spring.SpringUtils; import com.bonus.common.utils.spring.SpringUtils;
import com.bonus.file.service.SourceFileService; import com.bonus.file.service.SourceFileService;
@ -139,7 +140,7 @@ public class AsyncManager
* @author cwchen * @author cwchen
* @date 2025/11/29 10:51 * @date 2025/11/29 10:51
*/ */
public Future<Void> executeSendRabbitMqMessage(List<Map<String,Object>> list) { public Future<Void> executeSendRabbitMqMessage(List<RabbitMqMessage> list) {
Callable<Void> callable = new Callable<Void>() { Callable<Void> callable = new Callable<Void>() {
@Override @Override
public Void call() throws Exception { public Void call() throws Exception {

View File

@ -149,7 +149,7 @@ public class AnalysisOcrService {
/** /**
* 创建HTTP POST请求2 * 创建HTTP POST请求2
*/ */
private HttpPost createHttpPost2(AnalysisOcrRequest analysisOcrRequest) { /*private HttpPost createHttpPost2(AnalysisOcrRequest analysisOcrRequest) {
HttpPost httpPost = new HttpPost(extractInfoUrl); HttpPost httpPost = new HttpPost(extractInfoUrl);
try { try {
@ -165,6 +165,32 @@ public class AnalysisOcrService {
throw new RuntimeException("创建HTTP POST请求失败", e); throw new RuntimeException("创建HTTP POST请求失败", e);
} }
return httpPost; return httpPost;
}*/
private HttpPost createHttpPost2(AnalysisOcrRequest analysisOcrRequest) {
HttpPost httpPost = new HttpPost(extractInfoUrl);
try {
// 将请求对象转换为JSON字符串
String jsonRequest = convertToJson(analysisOcrRequest);
// 打印请求参数
log.info("OCR请求URL: {}", extractInfoUrl);
log.info("OCR请求参数: {}", jsonRequest);
// 设置请求体为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) {
log.error("创建HTTP POST请求失败请求参数: {}", analysisOcrRequest, e);
throw new RuntimeException("创建HTTP POST请求失败", e);
}
return httpPost;
} }
/** /**

View File

@ -133,7 +133,7 @@ public class RabbitMQConsumerService {
*/ */
private File getFileFromMinio(String uploadPath) { private File getFileFromMinio(String uploadPath) {
try { try {
File file = minioUtil.getFileFromMinio(minioConfig.getBucketName(), uploadPath); File file = minioUtil.getFileFromMinio2(minioConfig.getBucketName(), uploadPath);
if (file == null || !file.exists()) { if (file == null || !file.exists()) {
throw new RuntimeException("Minio文件不存在: " + uploadPath); throw new RuntimeException("Minio文件不存在: " + uploadPath);
} }

View File

@ -28,21 +28,9 @@ public class SendRabbitMqService {
* @author cwchen * @author cwchen
* @date 2025/11/29 14:04 * @date 2025/11/29 14:04
*/ */
public void sendRabbitMq(List<Map<String,Object>> list){ public void sendRabbitMq(List<RabbitMqMessage> list){
for (Map<String,Object> map : list) { for (RabbitMqMessage vo : list) {
String taskId = map.get("taskId").toString(); rabbitMQProducerService.sendMessageSync(vo);
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);
} }
} }
} }