From aaa989fd1e29cdc3ef91ea422cc05bde34f0b356 Mon Sep 17 00:00:00 2001 From: luoweijian <1329394916@qq.com> Date: Tue, 30 Jun 2026 10:29:53 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=97=E6=B3=95=E6=9C=8D=E5=8A=A1=E5=AF=B9?= =?UTF-8?q?=E6=8E=A5=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TriggerAiExtractApplicationService.java | 17 +++ ...riggerAiExtractApplicationServiceImpl.java | 110 ++++++++++++++++++ .../controller/InteractionController.java | 13 +++ .../domain/dto/AiExtractRequestDTO.java | 9 +- .../domain/dto/AiExtractTriggerResultDTO.java | 49 ++++++++ .../dto/GenerateQuestionRequestDTO.java | 6 + .../SaveDataExtractResultDomainService.java | 9 ++ ...stToGenerateQuestionDomainServiceImpl.java | 5 + ...aveDataExtractResultDomainServiceImpl.java | 58 +++++---- 9 files changed, 254 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/project/interaction/application/TriggerAiExtractApplicationService.java create mode 100644 src/main/java/com/project/interaction/application/impl/TriggerAiExtractApplicationServiceImpl.java create mode 100644 src/main/java/com/project/interaction/domain/dto/AiExtractTriggerResultDTO.java diff --git a/src/main/java/com/project/interaction/application/TriggerAiExtractApplicationService.java b/src/main/java/com/project/interaction/application/TriggerAiExtractApplicationService.java new file mode 100644 index 0000000..ce29d62 --- /dev/null +++ b/src/main/java/com/project/interaction/application/TriggerAiExtractApplicationService.java @@ -0,0 +1,17 @@ +package com.project.interaction.application; + +import com.project.interaction.domain.dto.AiExtractTriggerResultDTO; + +/** + * 手动触发知识点提取应用服务 + */ +public interface TriggerAiExtractApplicationService { + + /** + * 手动触发知识点提取 + * 校验子文件是否全部解析完成,完成则调用算法服务 + * @param informationId 虚拟资料ID + * @return 触发结果(含各文件解析状态) + */ + AiExtractTriggerResultDTO trigger(Long informationId); +} diff --git a/src/main/java/com/project/interaction/application/impl/TriggerAiExtractApplicationServiceImpl.java b/src/main/java/com/project/interaction/application/impl/TriggerAiExtractApplicationServiceImpl.java new file mode 100644 index 0000000..fcbb0e4 --- /dev/null +++ b/src/main/java/com/project/interaction/application/impl/TriggerAiExtractApplicationServiceImpl.java @@ -0,0 +1,110 @@ +package com.project.interaction.application.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.project.information.domain.entity.InformationFileEntity; +import com.project.information.domain.enums.FileParseStatusEnum; +import com.project.information.domain.service.InformationFileBaseService; +import com.project.interaction.application.TriggerAiExtractApplicationService; +import com.project.interaction.domain.dto.AiExtractRequestDTO; +import com.project.interaction.domain.dto.AiExtractTriggerResultDTO; +import com.project.interaction.domain.service.PostToAiExtractDomainService; +import com.project.interaction.domain.service.SaveDataExtractResultDomainService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * 手动触发知识点提取应用服务实现 + */ +@Service +@Slf4j +public class TriggerAiExtractApplicationServiceImpl implements TriggerAiExtractApplicationService { + + @Autowired + private InformationFileBaseService informationFileBaseService; + + @Autowired + private PostToAiExtractDomainService postToAiExtractDomainService; + + @Autowired + private SaveDataExtractResultDomainService saveDataExtractResultDomainService; + + @Override + public AiExtractTriggerResultDTO trigger(Long informationId) { + + // 1. 查询该虚拟资料下所有子文件 + List allFiles = informationFileBaseService.list( + new LambdaQueryWrapper() + .eq(InformationFileEntity::getInformationId, informationId) + .orderByAsc(InformationFileEntity::getCreateTime)); + + if (allFiles.isEmpty()) { + return new AiExtractTriggerResultDTO(true, null, "该虚拟资料下没有子文件", new ArrayList<>()); + } + + // 2. 构建各文件状态 + List fileStatuses = new ArrayList<>(); + boolean allDone = true; + boolean allSuccess = true; + + for (InformationFileEntity f : allFiles) { + Integer parseStatus = f.getParseStatus(); + String statusText = getStatusText(parseStatus); + + AiExtractTriggerResultDTO.FileStatus fs = + new AiExtractTriggerResultDTO.FileStatus(f.getId(), f.getFileName(), parseStatus, statusText); + fileStatuses.add(fs); + + if (!FileParseStatusEnum.Success.getValue().equals(parseStatus) + && !FileParseStatusEnum.Failed.getValue().equals(parseStatus)) { + allDone = false; + } + if (!FileParseStatusEnum.Success.getValue().equals(parseStatus)) { + allSuccess = false; + } + } + + // 3. 未全部完成 + if (!allDone) { + String message = "子文件尚未全部解析完成,共 " + allFiles.size() + " 个文件," + + allFiles.stream().filter(f -> FileParseStatusEnum.Success.getValue().equals(f.getParseStatus())).count() + + " 个已完成"; + return new AiExtractTriggerResultDTO(false, null, message, fileStatuses); + } + + // 4. 全部完成但有失败 + if (!allSuccess) { + String message = "存在解析失败的子文件,无法调用算法服务"; + return new AiExtractTriggerResultDTO(true, false, message, fileStatuses); + } + + // 5. 全部成功 → 调用算法服务 + log.info(">>> [手动触发] 虚拟资料 {} 下所有子文件解析完成,开始调用算法服务", informationId); + + AiExtractRequestDTO extractRequest = saveDataExtractResultDomainService.buildExtractRequest(informationId); + if (extractRequest == null) { + return new AiExtractTriggerResultDTO(true, true, "所有子文件解析成功,但无有效文本内容", fileStatuses); + } + + postToAiExtractDomainService.postToAiExtract(extractRequest); + + String message = "已成功触发算法服务,共 " + extractRequest.getSegments().size() + " 个文本片段"; + return new AiExtractTriggerResultDTO(true, true, message, fileStatuses); + } + + private String getStatusText(Integer status) { + if (status == null) { + return "未知"; + } + return switch (status) { + case 0 -> "未开始"; + case 1 -> "进行中"; + case 2 -> "成功"; + case -1 -> "失败"; + default -> "未知"; + }; + } +} diff --git a/src/main/java/com/project/interaction/controller/InteractionController.java b/src/main/java/com/project/interaction/controller/InteractionController.java index 2b4ba5a..487d1f8 100644 --- a/src/main/java/com/project/interaction/controller/InteractionController.java +++ b/src/main/java/com/project/interaction/controller/InteractionController.java @@ -7,7 +7,9 @@ import com.project.base.domain.result.Result; import com.project.interaction.application.AiExtractCallbackApplicationService; import com.project.interaction.application.AlgorithmApplicationService; import com.project.interaction.application.DataExtractCallbackApplicationService; +import com.project.interaction.application.TriggerAiExtractApplicationService; import com.project.interaction.domain.dto.AiExtractCallbackDTO; +import com.project.interaction.domain.dto.AiExtractTriggerResultDTO; import com.project.interaction.domain.dto.ClusterCallbackDTO; import com.project.interaction.domain.dto.DataExtractCallbackDTO; import com.project.interaction.domain.dto.QuestionCallBackDTO; @@ -39,6 +41,8 @@ public class InteractionController { private DataExtractCallbackApplicationService dataExtractCallbackApplicationService; @Autowired private AiExtractCallbackApplicationService aiExtractCallbackApplicationService; + @Autowired + private TriggerAiExtractApplicationService triggerAiExtractApplicationService; // @PostMapping("/saveCluster") // public Result saveCluster(ClusterCallbackDTO dto) throws Exception{ @@ -102,6 +106,15 @@ public class InteractionController { return Result.success("回调处理成功"); } + /** + * 手动触发知识点提取 + * 校验子文件是否全部解析完成,完成则调用算法服务 + */ + @PostMapping("/triggerAiExtract") + public Result triggerAiExtract(@RequestParam("informationId") Long informationId) { + return Result.success(triggerAiExtractApplicationService.trigger(informationId)); + } + /** * 算法服务知识点提取回调 * 算法服务返回草稿知识点,写入草稿表 diff --git a/src/main/java/com/project/interaction/domain/dto/AiExtractRequestDTO.java b/src/main/java/com/project/interaction/domain/dto/AiExtractRequestDTO.java index b1fda9e..42fed66 100644 --- a/src/main/java/com/project/interaction/domain/dto/AiExtractRequestDTO.java +++ b/src/main/java/com/project/interaction/domain/dto/AiExtractRequestDTO.java @@ -7,6 +7,7 @@ import java.util.List; /** * 算法服务 - 知识点提取请求 DTO + * 入参结构按算法接口确认 */ @Data public class AiExtractRequestDTO { @@ -15,10 +16,14 @@ public class AiExtractRequestDTO { @JsonProperty("information_id") private Long informationId; - /** 子文件解析后的分段列表(直接取 parsed_text 的 segments) */ + /** 文件内容分类(产品类/知识类/规范类/流程类) */ + @JsonProperty("chunk_size") + private Integer chunkSize = 80; + + /** 子文件解析文本列表 */ private List segments; - /** 回调URL(配置注入) */ + /** 回调URL */ @JsonProperty("callback_url") private String callbackUrl; diff --git a/src/main/java/com/project/interaction/domain/dto/AiExtractTriggerResultDTO.java b/src/main/java/com/project/interaction/domain/dto/AiExtractTriggerResultDTO.java new file mode 100644 index 0000000..8ac1448 --- /dev/null +++ b/src/main/java/com/project/interaction/domain/dto/AiExtractTriggerResultDTO.java @@ -0,0 +1,49 @@ +package com.project.interaction.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * 手动触发知识点提取结果 DTO + */ +@Data +@AllArgsConstructor +public class AiExtractTriggerResultDTO { + + /** 是否全部解析完成 */ + private Boolean allDone; + + /** 是否全部成功(allDone 为 true 时有效) */ + private Boolean allSuccess; + + /** 提示信息 */ + private String message; + + /** 各子文件解析状态 */ + private List fileStatuses; + + @Data + public static class FileStatus { + /** 子文件ID */ + private Long fileId; + + /** 文件名 */ + private String fileName; + + /** 解析状态:0-未开始,1-进行中,2-成功,-1-失败 */ + private Integer parseStatus; + + /** 状态文本 */ + private String statusText; + + public FileStatus(Long fileId, String fileName, Integer parseStatus, String statusText) { + this.fileId = fileId; + this.fileName = fileName; + this.parseStatus = parseStatus; + this.statusText = statusText; + } + } +} diff --git a/src/main/java/com/project/interaction/domain/dto/GenerateQuestionRequestDTO.java b/src/main/java/com/project/interaction/domain/dto/GenerateQuestionRequestDTO.java index 99b7653..fffebe9 100644 --- a/src/main/java/com/project/interaction/domain/dto/GenerateQuestionRequestDTO.java +++ b/src/main/java/com/project/interaction/domain/dto/GenerateQuestionRequestDTO.java @@ -41,6 +41,12 @@ public class GenerateQuestionRequestDTO { @JsonProperty("question_types") private List questionTypes; + /** + * 回调URL + */ + @JsonProperty("callback_url") + private String callbackUrl; + /** * 聚类信息内部类 */ diff --git a/src/main/java/com/project/interaction/domain/service/SaveDataExtractResultDomainService.java b/src/main/java/com/project/interaction/domain/service/SaveDataExtractResultDomainService.java index 8d25bd3..dd86ebb 100644 --- a/src/main/java/com/project/interaction/domain/service/SaveDataExtractResultDomainService.java +++ b/src/main/java/com/project/interaction/domain/service/SaveDataExtractResultDomainService.java @@ -1,11 +1,20 @@ package com.project.interaction.domain.service; +import com.project.interaction.domain.dto.AiExtractRequestDTO; import com.project.interaction.domain.dto.DataExtractCallbackDTO; + /** * 保存数据服务解析结果域服务 * 更新子文件解析状态和文本,检查批次完成,触发算法服务 */ public interface SaveDataExtractResultDomainService { void handleCallback(DataExtractCallbackDTO callback); + + /** + * 构建知识点提取请求(从已解析完成的子文件列表) + * @param informationId 虚拟资料ID + * @return 请求 DTO,null 表示无有效数据 + */ + AiExtractRequestDTO buildExtractRequest(Long informationId); } diff --git a/src/main/java/com/project/interaction/domain/service/impl/PostToGenerateQuestionDomainServiceImpl.java b/src/main/java/com/project/interaction/domain/service/impl/PostToGenerateQuestionDomainServiceImpl.java index c5291d1..40df87e 100644 --- a/src/main/java/com/project/interaction/domain/service/impl/PostToGenerateQuestionDomainServiceImpl.java +++ b/src/main/java/com/project/interaction/domain/service/impl/PostToGenerateQuestionDomainServiceImpl.java @@ -44,6 +44,10 @@ public class PostToGenerateQuestionDomainServiceImpl implements PostToGenerateQu @Value("${algo.apiUrl:http://172.16.25.174:8000}") private String apiUrl; + /** 题目生成回调地址 */ + @Value("${algo.generateQuestionCallbackUrl:http://172.16.204.50/evaluator-api}") + private String callbackUrl; + @Autowired private SaveQuestionDomainService saveQuestionDomainService; @@ -159,6 +163,7 @@ public class PostToGenerateQuestionDomainServiceImpl implements PostToGenerateQu // 构建请求 GenerateQuestionRequestDTO requestDTO = GenerateQuestionRequestDTO.builder() + .callbackUrl(callbackUrl) .cluster(GenerateQuestionRequestDTO.ClusterInfo.builder() .clusterId(clusterId) .taskId(taskId) diff --git a/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java b/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java index 74bdced..4886079 100644 --- a/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java +++ b/src/main/java/com/project/interaction/domain/service/impl/SaveDataExtractResultDomainServiceImpl.java @@ -36,7 +36,7 @@ public class SaveDataExtractResultDomainServiceImpl implements SaveDataExtractRe private ObjectMapper objectMapper; /** 算法服务回调地址 */ - @Value("${algo.callbackUrl:http://172.16.204.50/evaluator-api/api/interaction/aiExtractCallback}") + @Value("${algo.callbackUrl:http://172.16.204.50/evaluator-api}") private String callbackUrl; @Override @@ -82,47 +82,65 @@ public class SaveDataExtractResultDomainServiceImpl implements SaveDataExtractRe return; } - // 4. 全部成功 → 解析 parsedText JSON,构建 segments 列表,调用算法服务 + // 4. 全部成功 → 构建请求并调用算法服务 log.info(">>> [数据服务回调] 虚拟资料 {} 下所有子文件解析成功,开始调用算法服务", informationId); + AiExtractRequestDTO request = buildExtractRequest(informationId); + if (request != null) { + postToAiExtractDomainService.postToAiExtract(request); + } + } + + @Override + public AiExtractRequestDTO buildExtractRequest(Long informationId) { + List allFiles = informationFileBaseService.list( + new LambdaQueryWrapper() + .eq(InformationFileEntity::getInformationId, informationId)); + + if (allFiles.isEmpty()) { + return null; + } + List allSegments = new ArrayList<>(); for (InformationFileEntity f : allFiles) { if (f.getParsedText() == null || f.getParsedText().isBlank()) { continue; } - // 解析 parsed_text JSON: {"segments": [{"content": "...", "supplement": "", "chapter": "...", "content_type": "..."}]} + // 解析 parsed_text JSON: {"segments": [[{"content": "...", "supplement": "", "chapter": "...", "content_type": "..."}]]} + // segments 是双层数组:外层=每个子文件,内层=该文件的段落列表 try { - Map>> parsed = objectMapper.readValue( - f.getParsedText(), new TypeReference>>>() {}); - List> segments = parsed.get("segments"); - if (segments == null || segments.isEmpty()) { + Map>>> parsed = objectMapper.readValue( + f.getParsedText(), new TypeReference<>() { + }); + List>> fileGroups = parsed.get("segments"); + if (fileGroups == null || fileGroups.isEmpty()) { continue; } String fileName = f.getFileName(); - for (Map seg : segments) { - AiExtractRequestDTO.Segment segment = new AiExtractRequestDTO.Segment(); - segment.setContent(seg.get("content")); - segment.setSupplement(seg.get("supplement")); - segment.setChapter(seg.get("chapter")); - segment.setParseName(fileName); // parseName = 文件名 - segment.setContentType(seg.get("content_type")); - allSegments.add(segment); + for (List> group : fileGroups) { + for (Map seg : group) { + AiExtractRequestDTO.Segment segment = new AiExtractRequestDTO.Segment(); + segment.setContent(seg.get("content")); + segment.setSupplement(seg.get("supplement")); + segment.setChapter(seg.get("chapter")); + segment.setParseName(fileName); + segment.setContentType(seg.get("content_type")); + allSegments.add(segment); + } } } catch (Exception e) { - log.error(">>> [数据服务回调] 解析 parsedText 失败, fileId={}, error={}", f.getId(), e.getMessage()); + log.error(">>> [数据服务] 解析 parsedText 失败, fileId={}, error={}", f.getId(), e.getMessage()); } } if (allSegments.isEmpty()) { - log.warn(">>> [数据服务回调] 虚拟资料 {} 下所有子文件已解析但无有效 segments", informationId); - return; + return null; } AiExtractRequestDTO request = new AiExtractRequestDTO(); request.setInformationId(informationId); request.setSegments(allSegments); request.setCallbackUrl(callbackUrl); - - postToAiExtractDomainService.postToAiExtract(request); + return request; } }