diff --git a/src/main/java/com/project/classicpaper/domain/service/impl/AlgorithmClassicPaperQuestionGenerator.java b/src/main/java/com/project/classicpaper/domain/service/impl/AlgorithmClassicPaperQuestionGenerator.java new file mode 100644 index 0000000..ae5107f --- /dev/null +++ b/src/main/java/com/project/classicpaper/domain/service/impl/AlgorithmClassicPaperQuestionGenerator.java @@ -0,0 +1,103 @@ +package com.project.classicpaper.domain.service.impl; + +import com.project.classicpaper.domain.service.ClassicPaperQuestionGenerator; +import com.project.information.domain.entity.KnowledgePointEntity; +import com.project.interaction.domain.dto.GenerateQuestionRequestDTO; +import com.project.interaction.domain.dto.GenerateQuestionResponseDTO; +import com.project.question.domain.entity.QuestionEntity; +import com.project.task.domain.enums.QuestionTypeEnum; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 算法服务实现:经典套卷生题 + * 发送请求到算法服务,算法接受后异步回调 /api/milvus/insert + */ +@Component +@ConditionalOnProperty(value = "classicpaper.algorithm.enabled", havingValue = "true") +@Slf4j +public class AlgorithmClassicPaperQuestionGenerator implements ClassicPaperQuestionGenerator { + + @Resource(name = "algorithmWebClient") + private WebClient algorithmWebClient; + + /** 算法服务生题 URL(待确认) */ + @Value("${algo.classicPaperGenerateUrl:/v1/generate/questions_from_cluster}") + private String generateUrl; + + @Value("${algo.apiUrl:http://172.16.25.174:8000}") + private String apiUrl; + + @Override + public List generate(List knowledgePoints, + QuestionTypeEnum questionType, int count) throws Exception { + // 同步生题暂不支持,走降级 + throw new UnsupportedOperationException("请使用 generateAsync 异步方式"); + } + + @Override + public String generateAsync(Long paperQuestionId, + List knowledgePoints, + QuestionTypeEnum questionType, + int count) throws Exception { + List sourceTexts = knowledgePoints.stream() + .map(kp -> kp.getContent() != null ? kp.getContent() : "") + .collect(Collectors.toList()); + List sourceIds = knowledgePoints.stream() + .map(KnowledgePointEntity::getId) + .collect(Collectors.toList()); + + GenerateQuestionRequestDTO request = GenerateQuestionRequestDTO.builder() + .bizKey("PQ:" + paperQuestionId) + .numQuestions(count) + .questionTypes(Collections.singletonList(questionType.name().toLowerCase())) + .cluster(GenerateQuestionRequestDTO.ClusterInfo.builder() + .sourceText(sourceTexts) + .sourceId(sourceIds) + .products(knowledgePoints.get(0).getParseName()) + .build()) + .build(); + + log.info(">>> [经典套题-算法] 发送生题请求, paperQuestionId={}, 题型={}, 数量={}", + paperQuestionId, questionType, count); + + try { + GenerateQuestionResponseDTO response = algorithmWebClient.post() + .uri(apiUrl + generateUrl) + .bodyValue(request) + .retrieve() + .onStatus( + status -> !status.is2xxSuccessful(), + resp -> resp.bodyToMono(String.class) + .flatMap(body -> Mono.error(WebClientResponseException.create( + resp.statusCode().value(), "", + resp.headers().asHttpHeaders(), + body.getBytes(), StandardCharsets.UTF_8 + ))) + ) + .bodyToMono(GenerateQuestionResponseDTO.class) + .timeout(Duration.ofSeconds(30)) + .block(); + + String taskId = response != null ? response.getTaskId() : UUID.randomUUID().toString(); + log.info(">>> [经典套题-算法] 请求已接受, paperQuestionId={}, taskId={}", + paperQuestionId, taskId); + return taskId; + + } catch (Exception e) { + log.error(">>> [经典套题-算法] 请求失败, paperQuestionId={}", paperQuestionId, e); + throw e; + } + } +} \ No newline at end of file