|
|
@@ -15,11 +15,10 @@ import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Propagation;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Comparator;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.List;
|
|
|
+import java.util.*;
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.TimeoutException;
|
|
|
|
|
|
/**
|
|
|
* @author BaiBai
|
|
|
@@ -117,6 +116,12 @@ public class AIEvaluationService {
|
|
|
@Qualifier("aiTaskExecutor")
|
|
|
private ThreadPoolTaskExecutor aiTaskExecutor;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ @Qualifier("aiPerSentenceExecutor")
|
|
|
+ private ThreadPoolTaskExecutor aiPerSentenceExecutor;
|
|
|
+ @Autowired
|
|
|
+ private SentenceEvaluationMapperServiceImpl sentenceEvaluationMapperServiceImpl;
|
|
|
+
|
|
|
@Autowired
|
|
|
public AIEvaluationService(AIRequestService aiRequestService, StudentAssignmentMapper studentAssignmentMapper, AssignmentMapper assignmentMapper, OverallEvaluationMapper overallEvaluationMapper, SentenceEvaluationMapper sentenceEvaluationMapper, EvaluationMapper evaluationMapper, EvaluationMapperServiceImpl evaluationMapperServiceImpl) {
|
|
|
this.aiRequestService = aiRequestService;
|
|
|
@@ -145,9 +150,9 @@ public class AIEvaluationService {
|
|
|
Assignment assignment = assignmentMapper.selectById(assignmentId);
|
|
|
if (assignment == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
|
|
|
Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
|
|
|
- if(evaluationJudge != null && evaluationJudge.getOverall() != null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过AI分析");
|
|
|
+ if(evaluationJudge != null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过AI分析");
|
|
|
|
|
|
- if(evaluationJudge == null) initEvaluationRecord(assignmentId, studentId, engagement);
|
|
|
+ initEvaluationRecord(assignmentId, studentId, engagement);
|
|
|
|
|
|
String prompt = String.format(REWRITE_PROMPT_TEMPLATE, assignment.getDescription(), engagement.getTextContent());
|
|
|
AIRequestService.AIResponse response = requestAI(prompt, 0);
|
|
|
@@ -210,101 +215,107 @@ public class AIEvaluationService {
|
|
|
* @param studentId
|
|
|
* @return
|
|
|
*/
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
public List<SentenceEvaluation> rewritePerSentence(Long assignmentId, Long studentId){
|
|
|
- // 1 通过assignmentId和studentId找到engagement,获取当前文件链接
|
|
|
- Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
|
|
|
- if(engagement == null)
|
|
|
- throw MyException.create(HttpStatus.BAD_REQUEST, "作业参与不存在");
|
|
|
+ StopWatch sw = StopWatch.createStarted();
|
|
|
|
|
|
- // 通过assignmentId找到作业,获取作业描述
|
|
|
+ Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
|
|
|
+ if(engagement == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业参与不存在");
|
|
|
Assignment assignment = assignmentMapper.selectById(assignmentId);
|
|
|
- if (assignment == null)
|
|
|
- throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
|
|
|
+ if (assignment == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
|
|
|
|
|
|
- // 确定当前批改没有进行过
|
|
|
- Evaluation evaluationJudge = evaluationMapper.selectOne(new QueryWrapper<Evaluation>()
|
|
|
- .eq("assignment_id", assignmentId)
|
|
|
- .eq("student_id", studentId)
|
|
|
- .eq("version", engagement.getVersion()));
|
|
|
- if(evaluationJudge != null && evaluationJudge.getSentence() == 1){
|
|
|
- throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过AI分析");
|
|
|
+ // 没有智能评价记录时,进行重试,等待整体智能批改将记录写入数据库
|
|
|
+ int retryTime = 0;
|
|
|
+ while (retryTime < 3) {
|
|
|
+ Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
|
|
|
+ if (evaluationJudge == null){
|
|
|
+ try {
|
|
|
+ log.info("rewritePerSentence find evaluation record failed, assignmentId: {}, studentId: {}, retryTime: {}", assignmentId, studentId, retryTime + 1);
|
|
|
+ Thread.sleep(300);
|
|
|
+ retryTime++;
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if(evaluationJudge.getSentence() != 0){
|
|
|
+ throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过逐句智能评价");
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(retryTime >= 3) {
|
|
|
+ log.info("rewritePerSentence failed, assignmentId: {}, studentId: {}, reason: over max retry times(3)", assignmentId, studentId);
|
|
|
+ throw MyException.create(HttpStatus.BAD_REQUEST, "逐句批改失败,超过重试次数,请重新发起请求");
|
|
|
}
|
|
|
|
|
|
- String assignmentDescription = assignment.getDescription();
|
|
|
-
|
|
|
- // 2 找到学生作业内容
|
|
|
String content = engagement.getTextContent();
|
|
|
- log.info("作文内容为:" + content);
|
|
|
-
|
|
|
- // 3 分割作文的句子
|
|
|
// TODO: 句子分割需要详细考虑和判断
|
|
|
- String[] res = content.split("\\.");
|
|
|
-
|
|
|
- // 4 初始化AI请求变量
|
|
|
-// List<AIEntry> entry = new ArrayList<>();
|
|
|
- AIRequestService.WorkflowRunResponse response;
|
|
|
-
|
|
|
- // 5 初始化获取返回数据
|
|
|
- String retContent = "";
|
|
|
- List<SentenceEvaluation> responses = new ArrayList<>();
|
|
|
-
|
|
|
- // 6 逐句进行处理
|
|
|
- for(int i = 0; i < res.length; i++) {
|
|
|
- SentenceEvaluation sentenceEvaluation = new SentenceEvaluation();
|
|
|
-
|
|
|
-
|
|
|
- // 1 构造提示词
|
|
|
-// String prompt2 = String.format(SENTENCE_PROMPT_TEMPLATE, assignmentDescription, content, res[i]);
|
|
|
-// log.info("内置提示词为:"+ prompt2);
|
|
|
-//
|
|
|
-// // 2 请求AI
|
|
|
-// entry.clear();
|
|
|
-// entry.add(new AIEntry("user", prompt2));
|
|
|
- response = aiRequestService.requestPreSentenceWorkflow(content, assignmentDescription, res[i]);
|
|
|
-
|
|
|
- // 3 获取返回数据
|
|
|
- try {
|
|
|
- sentenceEvaluation.setEvaluation(response.getData().getOutputs().getResult_content());
|
|
|
- sentenceEvaluation.setType(response.getData().getOutputs().getResult_type());
|
|
|
- sentenceEvaluation.setCategory(response.getData().getOutputs().getResult_category());
|
|
|
- log.info("AI返回的数据为:"+ response);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("AI请求返回的数据内容有误,数据为{}", response);
|
|
|
- throw new MyException(HttpStatus.INTERNAL_SERVER_ERROR.value(), HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()+":"+"请求失败");
|
|
|
- }
|
|
|
+ String[] sentences = content.split("\\.");
|
|
|
+ List<SentenceEvaluation> sentenceEvaluationsList = new ArrayList<>();
|
|
|
+ CompletableFuture<?>[] futures = new CompletableFuture[sentences.length];
|
|
|
+
|
|
|
+ for (int i = 0; i < sentences.length; i++) {
|
|
|
+ final int sentenceNo = i;
|
|
|
+ final String sentence = sentences[i] + ".";
|
|
|
+ futures[i] = CompletableFuture.supplyAsync(() ->
|
|
|
+ processSingleSentence(assignmentId, studentId, content, assignment.getDescription(), sentence, sentenceNo, engagement.getVersion()),
|
|
|
+ aiPerSentenceExecutor)
|
|
|
+ .thenAccept(sentenceEvaluationsList::add);
|
|
|
+ }
|
|
|
|
|
|
- // 4 存储数据
|
|
|
- sentenceEvaluation.setAssignmentId(assignmentId);
|
|
|
- sentenceEvaluation.setStudentId(studentId);
|
|
|
- sentenceEvaluation.setContent(content);
|
|
|
- sentenceEvaluation.setNo(i+1);
|
|
|
- sentenceEvaluation.setSentence(res[i] + ".");
|
|
|
- sentenceEvaluation.setVersion(engagement.getVersion());
|
|
|
- sentenceEvaluationMapper.insert(sentenceEvaluation);
|
|
|
-
|
|
|
- // 5 填入返回信息
|
|
|
- responses.add(sentenceEvaluation);
|
|
|
+ // 等待所有任务完成
|
|
|
+ try {
|
|
|
+ CompletableFuture.allOf(futures).get(180, TimeUnit.SECONDS);
|
|
|
+ log.info("rewritePerSentence allOf success, assignmentId: {}, studentId: {}, version: {}", assignmentId, studentId, engagement.getVersion());
|
|
|
+ } catch (TimeoutException e) {
|
|
|
+ log.warn("rewritePerSentence failed, assignmentId: {}, studentId: {}, reason: timeout", assignmentId, studentId);
|
|
|
+ Arrays.stream(futures).forEach(f -> f.cancel(true));
|
|
|
+ throw MyException.create(HttpStatus.BAD_REQUEST, "处理超时,请重试");
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ throw MyException.create(HttpStatus.BAD_REQUEST, "处理被中断: " + e.getMessage());
|
|
|
+ } catch (Exception e){
|
|
|
+ throw MyException.create(HttpStatus.BAD_REQUEST, "处理失败: " + e.getMessage());
|
|
|
}
|
|
|
|
|
|
- Evaluation evaluationJudge2 = evaluationMapper.selectOne(new QueryWrapper<Evaluation>()
|
|
|
- .eq("assignment_id", assignmentId)
|
|
|
+ // 所有任务完成后批量插入数据库
|
|
|
+ if(!sentenceEvaluationsList.isEmpty()) {
|
|
|
+ sentenceEvaluationMapperServiceImpl.saveBatch(sentenceEvaluationsList);
|
|
|
+ }
|
|
|
+
|
|
|
+ evaluationMapperServiceImpl.update(new UpdateWrapper<Evaluation>()
|
|
|
+ .set("sentence", 1)
|
|
|
.eq("student_id", studentId)
|
|
|
+ .eq("assignment_id", assignmentId)
|
|
|
.eq("version", engagement.getVersion()));
|
|
|
- if(evaluationJudge2 == null){
|
|
|
- Evaluation evaluation = new Evaluation();
|
|
|
- evaluation.setTime(new Date());
|
|
|
- evaluation.setAssignmentId(assignmentId);
|
|
|
- evaluation.setStudentId(studentId);
|
|
|
- evaluation.setVersion(engagement.getVersion());
|
|
|
- evaluation.setSentence(1);
|
|
|
- evaluation.setOverall(0);
|
|
|
- evaluationMapper.insert(evaluation);
|
|
|
- } else {
|
|
|
- evaluationJudge.setSentence(1);
|
|
|
- evaluationMapper.updateById(evaluationJudge);
|
|
|
+
|
|
|
+ log.info("rewritePerSentence cost: {}", sw.formatTime());
|
|
|
+ return sentenceEvaluationsList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private SentenceEvaluation processSingleSentence(
|
|
|
+ Long assignmentId, Long studentId,
|
|
|
+ String content, String assignmentDesc,
|
|
|
+ String sentence, int sentenceNo,
|
|
|
+ Integer version
|
|
|
+ ) {
|
|
|
+ AIRequestService.WorkflowRunResponse response = aiRequestService.requestPreSentenceWorkflow(content, assignmentDesc, sentence);
|
|
|
+ if(response == null || response.getData() == null){
|
|
|
+ log.error("processSingleSentence failed, assignmentId: {}, studentId: {}, sentence: {}, response: {}", assignmentId, studentId, sentence, response);
|
|
|
+ return new SentenceEvaluation().setVersion(version).setNo(sentenceNo + 1).setType("error").setCategory("error").setEvaluation("error");
|
|
|
}
|
|
|
|
|
|
- return responses;
|
|
|
+ return new SentenceEvaluation()
|
|
|
+ .setEvaluation(response.getData().getOutputs().getResult_content())
|
|
|
+ .setType(response.getData().getOutputs().getResult_type())
|
|
|
+ .setCategory(response.getData().getOutputs().getResult_category())
|
|
|
+ .setAssignmentId(assignmentId)
|
|
|
+ .setStudentId(studentId)
|
|
|
+ .setContent(content)
|
|
|
+ .setNo(sentenceNo + 1)
|
|
|
+ .setSentence(sentence)
|
|
|
+ .setVersion(version);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -334,16 +345,15 @@ public class AIEvaluationService {
|
|
|
* @return
|
|
|
*/
|
|
|
public List<SentenceEvaluation> getRewritePerSentence(Long assignmentId, Long studentId, int version){
|
|
|
- QueryWrapper<SentenceEvaluation> queryWrapper = new QueryWrapper<>();
|
|
|
- queryWrapper.eq("assignment_id", assignmentId);
|
|
|
- queryWrapper.eq("student_id", studentId);
|
|
|
- queryWrapper.eq("version", version);
|
|
|
- List<SentenceEvaluation> sentenceEvaluations = sentenceEvaluationMapper.selectList(queryWrapper);
|
|
|
+ List<SentenceEvaluation> sentenceEvaluations = sentenceEvaluationMapperServiceImpl.list(new QueryWrapper<SentenceEvaluation>()
|
|
|
+ .eq("assignment_id", assignmentId)
|
|
|
+ .eq("student_id", studentId)
|
|
|
+ .eq("version", version));
|
|
|
|
|
|
if(sentenceEvaluations.isEmpty()){
|
|
|
throw MyException.create(HttpStatus.BAD_REQUEST, "AI批改不存在");
|
|
|
}
|
|
|
- // 按no属性进行排序
|
|
|
+
|
|
|
return sentenceEvaluations.stream().sorted(Comparator.comparing(SentenceEvaluation::getNo)).toList();
|
|
|
}
|
|
|
|