Эх сурвалжийг харах

core-ai autoScore fixScore

deason 2 сар өмнө
parent
commit
de2e3001a3

+ 57 - 15
core-ai/src/main/java/com/qmth/boot/core/ai/service/AiService.java

@@ -11,10 +11,13 @@ import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.List;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -77,6 +80,22 @@ public class AiService {
      * @return 判分结果;null表示无法获取判分结果
      */
     public AutoScoreResult autoScore(@NotNull @Validated AutoScoreRequest request, @NotNull SignatureInfo signature) {
+        if (StringUtils.isBlank(request.getSubjectName())) {
+            throw new IllegalArgumentException("科目名称不能为空");
+        }
+        if (StringUtils.isBlank(request.getQuestionBody())) {
+            throw new IllegalArgumentException("试题内容不能为空");
+        }
+        if (request.getScoreModel() == null) {
+            throw new IllegalArgumentException("评分模式不能为空");
+        }
+        if (CollectionUtils.isEmpty(request.getStandardAnswer())) {
+            throw new IllegalArgumentException("标答不能为空");
+        }
+        if (StringUtils.isBlank(request.getStudentAnswer())) {
+            throw new IllegalArgumentException("考生回答不能为空");
+        }
+
         ChatResult result = llmApiClient.chatTemplate(signature, LlmAppType.AUTO_SCORE, request);
         String text = result.getChoices().stream().filter(choice -> choice.getMessage().getRole() == ChatRole.assistant)
                 .map(choice -> choice.getMessage().getContent()).findFirst().orElse("");
@@ -85,7 +104,7 @@ public class AiService {
             String[] values = StringUtils.split(text.replaceAll(",", ","), ",");
             int stepCount = request.getStandardAnswer().size();
             if (stepCount != values.length) {
-                log.warn("评分结果无效:{},要求给出{}个关键分值,实际{}个", text, stepCount, values.length);
+                log.warn("评分结果无效,要求给出{}个关键分值,实际响应:{}", stepCount, text);
                 return null;
             }
 
@@ -93,43 +112,66 @@ public class AiService {
             double[] scores = new double[stepCount];
             for (int i = 0; i < stepCount; i++) {
                 double stepScore = Double.parseDouble(values[i].trim());
-                StandardAnswer step = request.getStandardAnswer().get(i);
 
+                StandardAnswer step = request.getStandardAnswer().get(i);
                 if (AutoScoreModel.LEVEL == request.getScoreModel()) {
                     // 按档次给分模式:关键步骤得分应介于当前档次分值区间
                     if (stepScore < step.getLowScore()) {
-                        log.warn("关键步骤得分无效:{},当前档次分值区间{}-{}分", stepScore, step.getLowScore(), step.getHighScore());
-                        scores[i] = 0;
+                        log.warn("评分结果-第{}步得分:{},低于档次分值区间{}-{}分的最低分", i + 1, stepScore, step.getLowScore(), step.getHighScore());
+                        stepScore = 0;
                     } else if (stepScore > step.getHighScore()) {
-                        scores[i] = Math.min(stepScore, step.getHighScore());
+                        log.warn("评分结果-第{}步得分:{},高于档次分值区间{}-{}分的最高分", i + 1, stepScore, step.getLowScore(), step.getHighScore());
                     } else {
-                        scores[i] = stepScore;
+                        // 修正分值-符合最小间隔分规则
+                        stepScore = this.fixScore(stepScore, request.getIntervalScore());
                     }
 
-                    // 处理分值符合最小间隔分 todo
+                    // 步骤分不能超过当前档次区间最高分和试题总分
+                    scores[i] = Math.min(Math.min(stepScore, step.getHighScore()), request.getTotalScore());
                     totalScore = Math.max(totalScore, scores[i]);
                 } else {
                     // 按得分点给分模式:关键步骤得分应小于等于当前得分点的分值
                     if (stepScore > step.getScore()) {
-                        log.warn("关键步骤得分无效:{},当前得分点分值{}分", stepScore, step.getScore());
-                        scores[i] = 0;
-                        continue;
+                        log.warn("评分结果-第{}步得分:{},大于得分点分值{}分的最大分", i + 1, stepScore, step.getScore());
+                    } else {
+                        // 修正分值-符合最小间隔分规则
+                        stepScore = this.fixScore(stepScore, request.getIntervalScore());
                     }
 
-                    // 处理分值符合最小间隔分 todo
-                    scores[i] = stepScore;
-                    totalScore += stepScore;
+                    // 步骤分不能超过当前得分点最高分和试题总分
+                    scores[i] = Math.min(Math.min(stepScore, step.getScore()), request.getTotalScore());
+                    totalScore += scores[i];
                 }
             }
 
             AutoScoreResult scoreResult = new AutoScoreResult();
             scoreResult.setStepScore(scores);
-            scoreResult.setTotalScore(totalScore);
+            scoreResult.setTotalScore(Math.min(totalScore, request.getTotalScore()));
             return scoreResult;
         } catch (Exception e) {
-            log.warn("评分结果无效:{},错误:{}", text, e.getMessage());
+            log.warn("评分结果无效,实际响应:{},错误:{}", text, e.getMessage());
             return null;
         }
     }
 
+    /**
+     * 将分数近似修正为指定“最小间隔分”的整数倍数
+     *
+     * @param score         分数
+     * @param intervalScore 最小间隔分
+     * @return 修正后的分数
+     */
+    private double fixScore(double score, double intervalScore) {
+        if (intervalScore <= 0) {
+            throw new IllegalArgumentException("最小间隔分必须大于0");
+        }
+
+        BigDecimal interval = BigDecimal.valueOf(intervalScore);
+
+        // 计算结果 = 近似取整(score / intervalScore) * intervalScore
+        return BigDecimal.valueOf(score)
+                .divide(interval, 0, RoundingMode.HALF_UP)
+                .multiply(interval).doubleValue();
+    }
+
 }