|
|
@@ -15,6 +15,9 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Propagation;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.transaction.PlatformTransactionManager;
|
|
|
+import org.springframework.transaction.support.TransactionTemplate;
|
|
|
+import org.springframework.transaction.TransactionDefinition;
|
|
|
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
@@ -45,6 +48,8 @@ public class AIEvaluationService {
|
|
|
|
|
|
private final EvaluationMapperServiceImpl evaluationMapperServiceImpl;
|
|
|
|
|
|
+ private final TransactionTemplate requiresNewTransactionTemplate;
|
|
|
+
|
|
|
@Autowired
|
|
|
@Qualifier("aiTaskExecutor")
|
|
|
private ThreadPoolTaskExecutor aiTaskExecutor;
|
|
|
@@ -56,7 +61,11 @@ public class AIEvaluationService {
|
|
|
private SentenceEvaluationMapperServiceImpl sentenceEvaluationMapperServiceImpl;
|
|
|
|
|
|
@Autowired
|
|
|
- public AIEvaluationService(AIRequestService aiRequestService, StudentAssignmentMapper studentAssignmentMapper, AssignmentMapper assignmentMapper, OverallEvaluationMapper overallEvaluationMapper, SentenceEvaluationMapper sentenceEvaluationMapper, EvaluationMapper evaluationMapper, EvaluationMapperServiceImpl evaluationMapperServiceImpl) {
|
|
|
+ public AIEvaluationService(AIRequestService aiRequestService, StudentAssignmentMapper studentAssignmentMapper,
|
|
|
+ AssignmentMapper assignmentMapper, OverallEvaluationMapper overallEvaluationMapper,
|
|
|
+ SentenceEvaluationMapper sentenceEvaluationMapper, EvaluationMapper evaluationMapper,
|
|
|
+ EvaluationMapperServiceImpl evaluationMapperServiceImpl,
|
|
|
+ PlatformTransactionManager transactionManager) {
|
|
|
this.aiRequestService = aiRequestService;
|
|
|
this.studentAssignmentMapper = studentAssignmentMapper;
|
|
|
this.assignmentMapper = assignmentMapper;
|
|
|
@@ -64,6 +73,10 @@ public class AIEvaluationService {
|
|
|
this.sentenceEvaluationMapper = sentenceEvaluationMapper;
|
|
|
this.evaluationMapper = evaluationMapper;
|
|
|
this.evaluationMapperServiceImpl = evaluationMapperServiceImpl;
|
|
|
+
|
|
|
+ // 创建一个使用REQUIRES_NEW传播行为的TransactionTemplate,确保每次都在新事务中执行
|
|
|
+ this.requiresNewTransactionTemplate = new TransactionTemplate(transactionManager);
|
|
|
+ this.requiresNewTransactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
|
|
}
|
|
|
|
|
|
public CompletableFuture<AIEntry> evaluationAsync(Long assignmentId, Long studentId) {
|
|
|
@@ -71,7 +84,7 @@ public class AIEvaluationService {
|
|
|
.exceptionally(ex -> { throw new MyException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "AI请求失败:" + ex.getMessage());})
|
|
|
.orTimeout(40, TimeUnit.SECONDS);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* AI作文整体智能批改
|
|
|
* @param assignmentId
|
|
|
@@ -81,34 +94,23 @@ public class AIEvaluationService {
|
|
|
*/
|
|
|
public AIEntry evaluation(Long assignmentId, Long studentId) {
|
|
|
StopWatch sw = StopWatch.createStarted();
|
|
|
+ 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, "作业不存在");
|
|
|
+ Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
|
|
|
+ if(evaluationJudge != null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过AI分析");
|
|
|
+ // 先在独立事务中初始化记录,确保其他线程能立即查询到
|
|
|
+ initEvaluationRecord(assignmentId, studentId, engagement);
|
|
|
try{
|
|
|
- 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, "作业不存在");
|
|
|
- Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
|
|
|
- if(evaluationJudge != null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业已进行过AI分析");
|
|
|
- initEvaluationRecord(assignmentId, studentId, engagement);
|
|
|
-
|
|
|
// 发起LLM请求
|
|
|
String prompt = String.format(PromptConstant.REWRITE_PROMPT_TEMPLATE, assignment.getDescription(), engagement.getTextContent());
|
|
|
AIRequestService.AIResponse response = requestAIWithRetry(prompt, 0);
|
|
|
String retContent = response.getChoices().get(0).getMessage().getContent();
|
|
|
String role = response.getChoices().get(0).getMessage().getRole();
|
|
|
|
|
|
- OverallEvaluation overallEvaluation = new OverallEvaluation()
|
|
|
- .setStudentId(studentId)
|
|
|
- .setAssignmentId(assignmentId)
|
|
|
- .setContent(engagement.getTextContent())
|
|
|
- .setEvaluation(retContent)
|
|
|
- .setVersion(engagement.getVersion());
|
|
|
- overallEvaluationMapper.insert(overallEvaluation);
|
|
|
-
|
|
|
- evaluationMapperServiceImpl.update(new UpdateWrapper<Evaluation>()
|
|
|
- .set("overall", 1)
|
|
|
- .eq("student_id", studentId)
|
|
|
- .eq("assignment_id", assignmentId)
|
|
|
- .eq("version", engagement.getVersion()));
|
|
|
+ // 保存评估结果
|
|
|
+ saveOverallEvaluationResult(assignmentId, studentId, engagement, retContent);
|
|
|
|
|
|
log.info("evaluation cost: {}", sw.formatTime());
|
|
|
return new AIEntry(role, retContent);
|
|
|
@@ -120,16 +122,36 @@ public class AIEvaluationService {
|
|
|
}
|
|
|
|
|
|
private void initEvaluationRecord(Long assignmentId, Long studentId, Engagement engagement) {
|
|
|
- Evaluation evaluation = new Evaluation()
|
|
|
- .setTime(new Date())
|
|
|
- .setAssignmentId(assignmentId)
|
|
|
+ // 使用编程式事务,确保记录立即提交,其他线程能够查询到
|
|
|
+ requiresNewTransactionTemplate.executeWithoutResult(status -> {
|
|
|
+ Evaluation evaluation = new Evaluation()
|
|
|
+ .setTime(new Date())
|
|
|
+ .setAssignmentId(assignmentId)
|
|
|
+ .setStudentId(studentId)
|
|
|
+ .setVersion(engagement.getVersion())
|
|
|
+ .setSentence(0)
|
|
|
+ .setOverall(0);
|
|
|
+ evaluationMapperServiceImpl.save(evaluation);
|
|
|
+ log.info("evaluation record init");
|
|
|
+ log.info("evaluation record: {}", evaluation);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public void saveOverallEvaluationResult(Long assignmentId, Long studentId, Engagement engagement, String retContent) {
|
|
|
+ OverallEvaluation overallEvaluation = new OverallEvaluation()
|
|
|
.setStudentId(studentId)
|
|
|
- .setVersion(engagement.getVersion())
|
|
|
- .setSentence(0)
|
|
|
- .setOverall(0);
|
|
|
- evaluationMapperServiceImpl.save(evaluation);
|
|
|
- log.info("evaluation record init");
|
|
|
- log.info("evaluation record: {}", evaluation);
|
|
|
+ .setAssignmentId(assignmentId)
|
|
|
+ .setContent(engagement.getTextContent())
|
|
|
+ .setEvaluation(retContent)
|
|
|
+ .setVersion(engagement.getVersion());
|
|
|
+ overallEvaluationMapper.insert(overallEvaluation);
|
|
|
+
|
|
|
+ evaluationMapperServiceImpl.update(new UpdateWrapper<Evaluation>()
|
|
|
+ .set("overall", 1)
|
|
|
+ .eq("student_id", studentId)
|
|
|
+ .eq("assignment_id", assignmentId)
|
|
|
+ .eq("version", engagement.getVersion()));
|
|
|
}
|
|
|
|
|
|
private AIRequestService.AIResponse requestAIWithRetry(String prompt, int retryTime) {
|
|
|
@@ -159,9 +181,13 @@ public class AIEvaluationService {
|
|
|
if (assignment == null) throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
|
|
|
|
|
|
// 没有智能评价记录时,进行重试,等待整体智能批改将记录写入数据库
|
|
|
+ // 使用编程式事务在新事务中查询,避免REPEATABLE READ隔离级别导致看不到其他事务提交的数据
|
|
|
int retryTime = 0;
|
|
|
while (retryTime < 3) {
|
|
|
- Evaluation evaluationJudge = evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, engagement.getVersion());
|
|
|
+ final int currentVersion = engagement.getVersion();
|
|
|
+ Evaluation evaluationJudge = requiresNewTransactionTemplate.execute(status ->
|
|
|
+ evaluationMapperServiceImpl.getByVersion(assignmentId, studentId, currentVersion)
|
|
|
+ );
|
|
|
log.info("rewritePerSentence find evaluation record, assignmentId: {}, studentId: {}, version: {}", assignmentId, studentId, engagement.getVersion());
|
|
|
if (evaluationJudge == null){
|
|
|
try {
|