xiatian 1 년 전
부모
커밋
e2baf763ea

+ 22 - 0
src/main/java/cn/com/qmth/am/bean/AiMarkingDto.java

@@ -0,0 +1,22 @@
+package cn.com.qmth.am.bean;
+
+import cn.com.qmth.am.entity.StudentScoreEntity;
+
+public class AiMarkingDto {
+	private StudentScoreEntity scoreInfo;
+	private Integer retry=0;
+	public StudentScoreEntity getScoreInfo() {
+		return scoreInfo;
+	}
+	public void setScoreInfo(StudentScoreEntity scoreInfo) {
+		this.scoreInfo = scoreInfo;
+	}
+	public Integer getRetry() {
+		return retry;
+	}
+	public void setRetry(Integer retry) {
+		this.retry = retry;
+	}
+
+
+}

+ 4 - 0
src/main/java/cn/com/qmth/am/service/StudentScoreService.java

@@ -30,4 +30,8 @@ public interface StudentScoreService  extends IService<StudentScoreEntity> {
 
 	void ocr(StudentScoreImageDto dto);
 
+	StudentScoreEntity findOneToAiMarking();
+
+	void aiMarking(StudentScoreEntity score);
+
 }

+ 144 - 28
src/main/java/cn/com/qmth/am/service/impl/StudentScoreServiceImpl.java

@@ -27,7 +27,9 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.boot.core.ai.client.OcrApiClient;
+import com.qmth.boot.core.ai.model.llm.AutoScoreRequest;
 import com.qmth.boot.core.ai.model.ocr.OcrType;
+import com.qmth.boot.core.ai.service.AiService;
 import com.qmth.boot.core.exception.StatusException;
 import com.qmth.boot.core.retrofit.exception.RetrofitResponseError;
 import com.qmth.boot.core.retrofit.utils.SignatureInfo;
@@ -39,6 +41,7 @@ import com.qmth.boot.tools.excel.enums.ExcelType;
 import com.qmth.boot.tools.excel.model.DataMap;
 import com.qmth.boot.tools.models.ByteArray;
 
+import cn.com.qmth.am.bean.AiMarkingDto;
 import cn.com.qmth.am.bean.AnswerImageDto;
 import cn.com.qmth.am.bean.ImageSlice;
 import cn.com.qmth.am.bean.ImportResult;
@@ -50,8 +53,10 @@ import cn.com.qmth.am.entity.QuestionEntity;
 import cn.com.qmth.am.entity.StudentEntity;
 import cn.com.qmth.am.entity.StudentScoreEntity;
 import cn.com.qmth.am.enums.DataStatus;
+import cn.com.qmth.am.service.QuestionService;
 import cn.com.qmth.am.service.StudentScoreService;
 import cn.com.qmth.am.service.StudentService;
+import cn.com.qmth.am.utils.Calculator;
 import cn.com.qmth.am.utils.ImageUtil;
 
 @Service
@@ -68,6 +73,10 @@ public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, Studen
 	private StudentService studentService;
 	@Autowired
 	private OcrApiClient ocrApiClient;
+	@Autowired
+	private AiService aiService;
+	@Autowired
+	private QuestionService questionService;
 	static {
 		int threadCount = Runtime.getRuntime().availableProcessors();
 		queue = new ArrayBlockingQueue<>(threadCount * 2);
@@ -343,7 +352,7 @@ public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, Studen
 
 	@Override
 	public void createSlice(StudentScoreEntity score, QuestionEntity q, Map<Integer, AnswerImageDto> answerImages) {
-		StudentScoreImageDto dto=new StudentScoreImageDto();
+		StudentScoreImageDto dto = new StudentScoreImageDto();
 		dto.setStudentId(score.getStudentId());
 		dto.setStudentScoreId(score.getId());
 		dto.setImage(getSlice(score, q, answerImages));
@@ -355,13 +364,13 @@ public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, Studen
 		String suff = null;
 		for (ImageSlice s : q.getImageSlice()) {
 			AnswerImageDto sheet = getSheet(score, q, s.getI(), answerImages);
-			suff=sheet.getSuff();
+			suff = sheet.getSuff();
 			ret.add(ImageUtil.cutImage(sheet.getImage(), sheet.getSuff(), s.getX().intValue(), s.getY().intValue(),
 					s.getW().intValue(), s.getH().intValue()));
 		}
-		if(ret.size()>1) {
+		if (ret.size() > 1) {
 			return ImageUtil.joinImages(ret, suff);
-		}else {
+		} else {
 			return ret.get(0);
 		}
 	}
@@ -390,7 +399,7 @@ public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, Studen
 	private String getImageUrl(StudentScoreEntity score, QuestionEntity q, Integer pageIndex) {
 		return null;
 	}
-	
+
 	@Override
 	public StudentScoreImageDto pollStudentScoreImage() {
 		return queue.poll();
@@ -399,13 +408,18 @@ public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, Studen
 	@Transactional
 	@Override
 	public void ocr(StudentScoreImageDto dto) {
-		OrgInfo org=solarService.getOrgList().get(0);
-		String ret=ocrDispose(dto, org);
-		if(ret!=null) {
-			updateAnswer(dto.getStudentScoreId(), ret);
+		try {
+			OrgInfo org = solarService.getOrgList().get(0);
+			String ret = ocrDispose(dto, org);
+			if (ret != null) {
+				updateAnswer(dto.getStudentScoreId(), ret);
+			}
+		} catch (Exception e) {
+			ocrErr(dto, e.getMessage());
 		}
 	}
-	public void updateAnswer(Long id, String answer) {
+
+	private void updateAnswer(Long id, String answer) {
 		UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
 		LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
 		lw.set(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
@@ -413,39 +427,141 @@ public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, Studen
 		lw.eq(StudentScoreEntity::getId, id);
 		this.update(wrapper);
 	}
-	private String ocrDispose(StudentScoreImageDto dto,OrgInfo org) {
+
+	private String ocrDispose(StudentScoreImageDto dto, OrgInfo org) {
 		SignatureInfo signature = SignatureInfo.secret(org.getAccessKey(), org.getAccessSecret());
 		try {
 			return ocrApiClient.forImage(signature, OcrType.HANDWRITING, UploadFile.build("image", "", dto.getImage()));
 		} catch (Exception e) {
-			log.error("ocr异常",e);
-			if(e instanceof RetrofitResponseError) {
-				RetrofitResponseError tem=(RetrofitResponseError)e;
-				if(tem.getCode()==503) {
-					if(dto.getRetry()<=3) {
+			log.error("ocr异常", e);
+			if (e instanceof RetrofitResponseError) {
+				RetrofitResponseError tem = (RetrofitResponseError) e;
+				if (tem.getCode() == 503) {
+					if (dto.getRetry() <= 3) {
 						try {
 							Thread.sleep(3000);
 						} catch (InterruptedException e1) {
 						}
-						dto.setRetry(dto.getRetry()+1);
+						dto.setRetry(dto.getRetry() + 1);
 						return ocrDispose(dto, org);
-					}else {
-						ocrErr(dto);
-						return null;
+					} else {
+						throw new StatusException("重试次数过多");
 					}
-				}else {
-					ocrErr(dto);
-					return null;
+				} else {
+					throw e;
+				}
+			} else {
+				throw e;
+			}
+		}
+	}
+
+	private void ocrErr(StudentScoreImageDto dto,String err) {
+		updateAnswerErr(dto.getStudentScoreId(),err);
+		studentService.updateStatus(dto.getStudentId(), DataStatus.PROCESSING, DataStatus.FAILED);
+	}
+
+	@Override
+	public StudentScoreEntity findOneToAiMarking() {
+		QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
+		LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
+		lw.eq(StudentScoreEntity::getAnswerStatus, DataStatus.SUCCESS);
+		lw.eq(StudentScoreEntity::getScoreStatus, DataStatus.WAITING);
+		wrapper.last("LIMIT 1");
+		return this.getOne(wrapper);
+	}
+
+	@Transactional
+	@Override
+	public void aiMarking(StudentScoreEntity score) {
+		AiMarkingDto dto = new AiMarkingDto();
+		dto.setScoreInfo(score);
+		try {
+			OrgInfo org = solarService.getOrgList().get(0);
+			QuestionEntity q = questionService.getById(score.getQuestionId());
+			if (q == null) {
+				throw new StatusException("未找到试题信息");
+			}
+			AutoScoreRequest req = new AutoScoreRequest();
+			req.setQuestionBody(q.getContent());
+			req.setStandardAnswer(q.getAnswer());
+			req.setStudentAnswer(score.getAnswer());
+			req.setSubjectName(q.getSubjectName());
+			Double ret = aiMarkingDispose(dto, org, req);
+			if (ret != null) {
+				updateScore(score.getId(), Calculator.multiply(q.getFullScore(), ret));
+				if (allSuccess(score.getStudentId())) {
+					studentService.updateStatus(score.getStudentId(), DataStatus.PROCESSING, DataStatus.SUCCESS);
 				}
 			}else {
-				ocrErr(dto);
-				return null;
+				aiScoreErr(dto, "aiScore异常");
 			}
+		} catch (Exception e) {
+			aiScoreErr(dto, e.getMessage());
 		}
 	}
+
+	private boolean allSuccess(Long studentId) {
+		QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
+		LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
+		lw.eq(StudentScoreEntity::getStudentId, studentId);
+		List<StudentScoreEntity> list = this.list(wrapper);
+		for (StudentScoreEntity s : list) {
+			if (!DataStatus.SUCCESS.equals(s.getScoreStatus())) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	private Double aiMarkingDispose(AiMarkingDto dto, OrgInfo org, AutoScoreRequest req) {
+		SignatureInfo signature = SignatureInfo.secret(org.getAccessKey(), org.getAccessSecret());
+		try {
+			return aiService.autoScore(req, signature);
+		} catch (Exception e) {
+			log.error("aiScore异常", e);
+			if (e instanceof RetrofitResponseError) {
+				RetrofitResponseError tem = (RetrofitResponseError) e;
+				if (tem.getCode() == 503) {
+					if (dto.getRetry() <= 3) {
+						try {
+							Thread.sleep(3000);
+						} catch (InterruptedException e1) {
+						}
+						dto.setRetry(dto.getRetry() + 1);
+						return aiMarkingDispose(dto, org, req);
+					} else {
+						throw new StatusException("重试次数过多");
+					}
+				} else {
+					throw e;
+				}
+			} else {
+				throw e;
+			}
+		}
+	}
+
+	private void updateScore(Long id, Double aiScore) {
+		UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
+		LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
+		lw.set(StudentScoreEntity::getScoreStatus, DataStatus.SUCCESS);
+		lw.set(StudentScoreEntity::getAiScore, aiScore);
+		lw.eq(StudentScoreEntity::getId, id);
+		this.update(wrapper);
+	}
+
+	private void aiScoreErr(AiMarkingDto dto, String err) {
+		updateScoreErr(dto.getScoreInfo().getId(), err);
+		studentService.updateStatus(dto.getScoreInfo().getStudentId(), DataStatus.PROCESSING, DataStatus.FAILED);
+	}
 	
-	private void ocrErr(StudentScoreImageDto dto) {
-		updateAnswerErr(dto.getStudentScoreId(), "ocr异常");
-		studentService.updateStatus(dto.getStudentId(), DataStatus.PROCESSING, DataStatus.FAILED);
+	private void updateScoreErr(Long id, String err) {
+		UpdateWrapper<StudentScoreEntity> wrapper = new UpdateWrapper<>();
+		LambdaUpdateWrapper<StudentScoreEntity> lw = wrapper.lambda();
+		lw.set(StudentScoreEntity::getScoreStatus, DataStatus.FAILED);
+		lw.set(StudentScoreEntity::getErrMsg, err);
+		lw.eq(StudentScoreEntity::getId, id);
+		this.update(wrapper);
 	}
 }

+ 31 - 22
src/main/java/cn/com/qmth/am/task/AiMarkingJob.java

@@ -6,31 +6,40 @@ import org.springframework.stereotype.Service;
 
 import com.qmth.boot.core.concurrent.service.ConcurrentService;
 
+import cn.com.qmth.am.entity.StudentScoreEntity;
 import cn.com.qmth.am.enums.LockType;
+import cn.com.qmth.am.service.StudentScoreService;
 
 @Service
 public class AiMarkingJob {
-
-
-    @Autowired
-    private ConcurrentService concurrentService;
-
-    @Scheduled(fixedDelay = 5 * 1000, initialDelay = 20 * 1000)
-    public void doJob() {
-        boolean lock = concurrentService.getReadWriteLock(LockType.AI_MARKING.name()).writeLock().tryLock();
-        try {
-            if (!lock) {
-                return;
-            }
-            this.dispose();
-        } finally {
-            if (lock) {
-                concurrentService.getReadWriteLock(LockType.AI_MARKING.name()).writeLock().unlock();
-            }
-        }
-    }
-
-    private void dispose() {
-    }
+	@Autowired
+	private StudentScoreService studentScoreService;
+	@Autowired
+	private ConcurrentService concurrentService;
+
+	@Scheduled(fixedDelay = 30 * 1000, initialDelay = 20 * 1000)
+	public void doJob() {
+		boolean lock = concurrentService.getReadWriteLock(LockType.AI_MARKING.name()).writeLock().tryLock();
+		try {
+			if (!lock) {
+				return;
+			}
+			this.dispose();
+		} finally {
+			if (lock) {
+				concurrentService.getReadWriteLock(LockType.AI_MARKING.name()).writeLock().unlock();
+			}
+		}
+	}
+
+	private void dispose() {
+		for(;;) {
+			StudentScoreEntity score = studentScoreService.findOneToAiMarking();
+			if (score==null) {
+				return;
+			}
+			studentScoreService.aiMarking(score);
+		}
+	}
 
 }

+ 1 - 1
src/main/java/cn/com/qmth/am/task/BiuldImageJob.java

@@ -52,7 +52,7 @@ public class BiuldImageJob {
 
 	}
 
-	@Scheduled(fixedDelay = 5 * 1000, initialDelay = 20 * 1000)
+	@Scheduled(fixedDelay = 30 * 1000, initialDelay = 20 * 1000)
 	public void doJob() {
 		boolean lock = concurrentService.getReadWriteLock(LockType.OCR.name()).writeLock().tryLock();
 		try {