Browse Source

算法生题逻辑修改

master
luoweijian 2 months ago
parent
commit
1f5ea3e8fc
  1. 3
      src/main/java/com/project/base/domain/entity/BaseEntity.java
  2. 7
      src/main/java/com/project/classicpaper/domain/service/impl/ClassicPaperQuestionCallbackServiceImpl.java
  3. 24
      src/main/java/com/project/exam/domain/service/strategy/SubjectiveScoringStrategy.java
  4. 24
      src/main/java/com/project/interaction/domain/dto/AiScoringRequestDTO.java
  5. 4
      src/main/java/com/project/interaction/domain/service/impl/PostToAiScoringDomainServiceImpl.java
  6. 36
      src/main/java/com/project/milvus/application/impl/MilvusApplicationServiceImpl.java
  7. 15
      src/main/java/com/project/question/domain/dto/QuestionDTO.java

3
src/main/java/com/project/base/domain/entity/BaseEntity.java

@ -72,8 +72,7 @@ public class BaseEntity implements Serializable {
try {
String currentUserId = SecurityUtils.getUserId();
boolean isCreator = StrUtil.equals(currentUserId, this.creatorId);
boolean isAdmin = SecurityUtils.hasRole("ROLE_ADMIN")
|| SecurityUtils.hasRole("ROLE_SUPER_ADMIN");
boolean isAdmin = SecurityUtils.hasRole("ROLE_SUPER_ADMIN");
baseDTO.setCanEdit(isCreator || isAdmin);
} catch (Exception ignored) {
// 获取当前用户信息失败时默认不可编辑

7
src/main/java/com/project/classicpaper/domain/service/impl/ClassicPaperQuestionCallbackServiceImpl.java

@ -83,8 +83,11 @@ public class ClassicPaperQuestionCallbackServiceImpl implements ClassicPaperQues
return;
}
// 2. 查找 paper_question → paperId
ClassicPaperQuestionEntity paperQuestion = classicPaperQuestionBaseService.getById(paperQuestionId);
// 2. 查找 paper_question → paperId(加悲观锁,防止并发回调同时提拔)
ClassicPaperQuestionEntity paperQuestion = classicPaperQuestionBaseService.lambdaQuery()
.eq(ClassicPaperQuestionEntity::getId, paperQuestionId)
.last("FOR UPDATE")
.one();
if (paperQuestion == null) {
log.warn(">>> [经典套题-回调] paper_question 不存在, id={}", paperQuestionId);
return;

24
src/main/java/com/project/exam/domain/service/strategy/SubjectiveScoringStrategy.java

@ -7,6 +7,7 @@ import com.project.interaction.domain.dto.AiScoringRequestDTO;
import com.project.interaction.domain.dto.AiScoringResponseDTO;
import com.project.interaction.domain.service.PostToAiScoringDomainService;
import com.project.question.domain.entity.QuestionEntity;
import com.project.question.domain.service.QuestionBaseService;
import com.project.task.domain.enums.QuestionTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -29,6 +30,9 @@ public class SubjectiveScoringStrategy implements ScoringStrategy {
@Autowired
private AiGradingLogBaseService aiGradingLogBaseService;
@Autowired
private QuestionBaseService questionBaseService;
@Override
public boolean supports(Integer questionType) {
return QuestionTypeEnum.SHORT_ANSWER.getValue().equals(questionType);
@ -38,16 +42,22 @@ public class SubjectiveScoringStrategy implements ScoringStrategy {
public void score(ExamRecordDTO.QuestionSnapshotDTO snapshot, ScoringContext context, Long taskId) {
Long questionId = snapshot.getQuestionId();
// 构建AI阅卷请求
// 构建AI阅卷请求(新接口:/v1/score/short_answer)
AiScoringRequestDTO request = new AiScoringRequestDTO();
request.setQuestionId(questionId);
request.setQuestionContent(snapshot.getQuestionContent());
request.setProducts(context.getTask() != null ? context.getTask().getName() : "");
request.setQuestion(snapshot.getQuestionContent());
request.setUserAnswer(snapshot.getUserAnswer());
// 构建得分点列表(从快照的 options 中获取,简答题的 options 存储得分点)
// 注意:得分点存储在 QuestionDetail.scoringPoints 中,需要从快照中获取
// 这里先用空列表,后续从快照中获取
request.setScoringPoints(new ArrayList<>());
// 从数据库查询得分点,转为字符串列表
QuestionEntity question = questionBaseService.getById(questionId);
List<String> options = new ArrayList<>();
if (question != null && question.getQuestionDetail() != null
&& question.getQuestionDetail().getScoringPoints() != null) {
for (QuestionEntity.QuestionDetail.ScoringPoint sp : question.getQuestionDetail().getScoringPoints()) {
options.add(sp.getContent());
}
}
request.setOptions(options);
// 创建判分日志
AiGradingLogEntity logEntity = new AiGradingLogEntity();

24
src/main/java/com/project/interaction/domain/dto/AiScoringRequestDTO.java

@ -1,5 +1,6 @@
package com.project.interaction.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@ -7,30 +8,21 @@ import java.util.List;
/**
* AI阅卷请求 DTO
* 发送给算法服务请求对简答题进行评分
* 接口/v1/score/short_answer
*/
@Data
public class AiScoringRequestDTO {
/** 考试记录ID */
private Long examRecordId;
/** 题目ID */
private Long questionId;
/** 产品线/来源标识 */
private String products;
/** 题目内容 */
private String questionContent;
private String question;
/** 考生作答 */
@JsonProperty("user_answer")
private String userAnswer;
/** 得分点列表 */
private List<ScoringPoint> scoringPoints;
@Data
public static class ScoringPoint {
/** 得分点序号 */
private Integer index;
/** 得分点内容 */
private String content;
}
/** 得分点内容列表(按顺序,算法按顺序匹配命中) */
private List<String> options;
}

4
src/main/java/com/project/interaction/domain/service/impl/PostToAiScoringDomainServiceImpl.java

@ -24,8 +24,8 @@ public class PostToAiScoringDomainServiceImpl implements PostToAiScoringDomainSe
@Resource(name = "algorithmWebClient")
private WebClient algorithmWebClient;
/** 算法服务阅卷路径(待确认) */
@Value("${algo.scoringUrl:/ai-scoring}")
/** 算法服务阅卷路径 */
@Value("${algo.scoringUrl:/v1/score/short_answer}")
private String scoringUrl;
private final ObjectMapper objectMapper = new ObjectMapper();

36
src/main/java/com/project/milvus/application/impl/MilvusApplicationServiceImpl.java

@ -1,5 +1,6 @@
package com.project.milvus.application.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.project.base.domain.exception.MissingParameterException;
import com.project.classicpaper.domain.service.ClassicPaperQuestionCallbackService;
@ -43,10 +44,10 @@ public class MilvusApplicationServiceImpl implements MilvusApplicationService {
public void insertTitle(TitleVector title) {
// 经典套卷分支:走备用池 + 提拔,跳过 Milvus
log.info(">>> [回调处理] 经典套卷生题回调, json={}", JSONUtil.toJsonStr(title));
if (title.getBizKey() != null && title.getBizKey().startsWith("PQ:")) {
log.info(">>> [回调处理] 经典套卷生题回调, bizKey={}", title.getBizKey());
log.info(">>> [回调处理] 经典套卷生题回调, json={}", JSONUtil.toJsonStr(title));
handleClassicPaper(title);
return;
@ -135,6 +136,8 @@ public class MilvusApplicationServiceImpl implements MilvusApplicationService {
private void handleClassicPaper(TitleVector title) {
// 构造单题列表
QuestionDTO questionDTO = buildQuestionDTO(title);
// 简答题:算法把得分点放在 options 中(key="1","2","3"...),转为 scoringPoints
convertShortAnswerScoringPoints(questionDTO);
List<QuestionDTO> questions = Collections.singletonList(questionDTO);
QuestionCallBackDTO callback = new QuestionCallBackDTO();
@ -151,4 +154,35 @@ public class MilvusApplicationServiceImpl implements MilvusApplicationService {
String collect = poinIds.stream().map(String::valueOf).collect(Collectors.joining(","));
return LOCK_KEY + DigestUtils.md5Hex(collect);
}
/**
* 简答题转换算法把得分点放在 optionskey="1","2","3"...
* 转为 scoringPoints 格式清空 options/rightAnswer
*/
private void convertShortAnswerScoringPoints(QuestionDTO dto) {
QuestionDTO.QuestionDetailDTO detail = dto.getQuestionDetailDTO();
if (detail == null || detail.getType() != 4) {
return;
}
if (detail.getOptions() == null || detail.getOptions().isEmpty()) {
return;
}
if (detail.getScoringPoints() != null && !detail.getScoringPoints().isEmpty()) {
return;
}
List<QuestionDTO.ScoringPointDTO> spList = new ArrayList<>();
for (Map.Entry<String, String> entry : detail.getOptions().entrySet()) {
String content = entry.getValue();
if (StrUtil.isNotBlank(content)) {
QuestionDTO.ScoringPointDTO sp = new QuestionDTO.ScoringPointDTO();
sp.setIndex(Integer.parseInt(entry.getKey()));
sp.setContent(content);
spList.add(sp);
}
}
detail.setScoringPoints(spList);
detail.setOptions(null);
detail.setRightAnswer(null);
}
}

15
src/main/java/com/project/question/domain/dto/QuestionDTO.java

@ -56,6 +56,21 @@ public class QuestionDTO extends BaseDTO {
if (this.questionDetailDTO != null) {
QuestionEntity.QuestionDetail detail = new QuestionEntity.QuestionDetail();
BeanUtils.copyProperties(this.questionDetailDTO, detail);
// BeanUtils 无法处理 List<ScoringPointDTO> → List<ScoringPoint>
// 手动复制得分点
if (this.questionDetailDTO.getScoringPoints() != null) {
List<QuestionEntity.ScoringPoint> spList =
this.questionDetailDTO.getScoringPoints().stream()
.map(sp -> {
QuestionEntity.ScoringPoint target =
new QuestionEntity.ScoringPoint();
target.setIndex(sp.getIndex());
target.setContent(sp.getContent());
return target;
})
.collect(java.util.stream.Collectors.toList());
detail.setScoringPoints(spList);
}
entity.setQuestionDetail(detail);
}

Loading…
Cancel
Save