fix(examWords): 修复考试单词顺序混乱和标记阈值调整

- 限制单词释义显示长度,避免过长显示问题
- 修复获取单词后单词 ID 顺序混乱问题,增加更新考试记录单词 ID 顺序功能
- 增加 ExamWordsDOMapper 中更新单词 ID 顺序的方法及对应 XML 配置
- 在 ExamWordsService 中新增更新单词 ID 顺序方法及其实现
- 调整 PngUtil 中未背熟单词标记阈值由 800 降至 500,增强识别准确性
- 优化测试用例,增加对未掌握单词的输出日志
- 更新测试数据文件路径及格式对应关系,改进词汇插入逻辑,完善变量赋值
- 统一单词实体中音标和词性赋值,保证完整词汇信息展现
This commit is contained in:
lbw
2025-12-25 17:01:21 +08:00
parent aff862d161
commit bc9334f5ab
10 changed files with 64 additions and 10 deletions

View File

@@ -54,12 +54,16 @@ public class ExamWordsController {
if (examWordsDO == null || examWordsDO.getWordIds().isEmpty()) {
throw new RuntimeException("没有单词");
}
List<VocabularyBankDO> vocabularyBankDOS = vocabularyService.findVocabularyBankDOListById(examWordsDO.getWordIds());
List<Word> assessmentWords = vocabularyBankDOS.stream().map(vocabularyBankDO -> Word.builder()
.id(vocabularyBankDO.getId())
.title(vocabularyBankDO.getWord())
.definition(vocabularyBankDO.getDefinition())
.definition(vocabularyBankDO.getDefinition().length() > 6 ? vocabularyBankDO.getDefinition().substring(0, 6) : vocabularyBankDO.getDefinition())
.build()).toList();
// bug: 获取单词后单词的id会乱序、 需要重新更新考试记录中的 id
examWordsDO.setWordIds(assessmentWords.stream().map(Word::getId).toList());
examWordsService.updateExamWordsWordIdsOrder(examWordsDO);
List<StudentDetail> studentDetailList = studentService.getStudentDetailList(Collections.singletonList(studentId));
List<Map<String, Object>> maps = studentDetailList.stream().map(studentDetail -> {

View File

@@ -7,4 +7,6 @@ public interface ExamWordsDOMapper {
int insert(ExamWordsDO record);
ExamWordsDO selectById(Integer id);
void updateWordIdsOrder(ExamWordsDO examWordsDO);
}

View File

@@ -11,4 +11,6 @@ public interface ExamWordsService {
ExamWordsDO generateExamWords(Integer gradeId, Integer level, Integer studentId, Integer type);
int saveExamWordsPngToDbAndLocal(MultipartFile file);
void updateExamWordsWordIdsOrder(ExamWordsDO examWordsDO);
}

View File

@@ -141,5 +141,10 @@ public class ExamWordsServiceImpl implements ExamWordsService {
}
@Override
public void updateExamWordsWordIdsOrder(ExamWordsDO examWordsDO) {
examWordsDOMapper.updateWordIdsOrder(examWordsDO);
}
}

View File

@@ -134,7 +134,7 @@ public class PngUtil {
// 建议:如果光照不均匀,考虑使用 THRESH_OTSU 自动阈值,或者自适应阈值
Imgproc.threshold(gray, binary, 150, 255, Imgproc.THRESH_BINARY_INV);
// 调试时打印
// Imgcodecs.imwrite("output_binary.png", binary);
// Imgcodecs.imwrite("output_binary.png", binary);
List<Integer> answer = new ArrayList<>();
int words_index = 0;
@@ -169,10 +169,10 @@ public class PngUtil {
Mat region = binary.submat(rect);
int countNonZero = Core.countNonZero(region);
if (countNonZero > 800) {
if (countNonZero > 500) {
Integer id = wordIds.get(words_index);
answer.add(id);
log.info("检测到标记未背熟ID={}", id);
log.info("检测到标记未背熟ID={}, 当前坐标 x = {} y = {} ", id, currentX + 1, currentY + 1);
}
region.release();

View File

@@ -18,6 +18,12 @@
VALUES (#{gradeId}, #{level}, #{title}, #{wordIds, typeHandler=com.yinlihupo.enlish.service.config.ListWordIdTypeHandler}, #{createdAt})
</insert>
<update id="updateWordIdsOrder">
update exam_words
set word_ids = #{wordIds, typeHandler=com.yinlihupo.enlish.service.config.ListWordIdTypeHandler}
where id = #{id}
</update>
<select id="selectById" resultMap="ResultMapWithBLOBs">
select * from exam_words where id = #{id}
</select>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 KiB

View File

@@ -35,9 +35,9 @@ public class TestVocabularyBankInsert {
private GradeUnitDOMapper gradeUnitDOMapper;
@Test
void test() {
String file = "C:\\project\\java\\enlish_edu\\enlish\\enlish-service\\src\\test\\java\\com\\yinlihupo\\enlish\\service\\mapper\\3上.xlsx";
String file = "C:\\project\\java\\enlish_edu\\enlish\\enlish-service\\src\\test\\java\\com\\yinlihupo\\enlish\\service\\mapper\\八下.xlsx";
HashMap<String, Integer> map = new HashMap<>();
int gradeId = 3;
int gradeId = 8;
try (FileInputStream fis = new FileInputStream(file); Workbook workbook = new XSSFWorkbook(fis)) {
Sheet sheet = workbook.getSheetAt(0);
@@ -49,15 +49,22 @@ public class TestVocabularyBankInsert {
}
// String word = row.getCell(0).getStringCellValue();
// String pronunciation = row.getCell(1) != null ? row.getCell(1).getStringCellValue() : "";
// String pos = row.getCell(2) != null ? row.getCell(2).getStringCellValue() : "";
// String meaning = row.getCell(3) != null ? row.getCell(3).getStringCellValue() : "";
// String gradeUnit = row.getCell(4) != null ? row.getCell(4).getStringCellValue() : "";
String word = row.getCell(0).getStringCellValue();
String meaning = row.getCell(1) != null ? row.getCell(1).getStringCellValue() : "";
String gradeUnit = row.getCell(2) != null ? row.getCell(2).getStringCellValue() : "";
String pronunciation = "";
String pos = "";
if (word.contains("Unit")) {
continue;
}
int gradeUnitId = 0;
int gradeUnitId;
if (map.containsKey(gradeUnit)) {
gradeUnitId = map.get(gradeUnit);
} else {
@@ -80,7 +87,8 @@ public class TestVocabularyBankInsert {
VocabularyBankDO vocabularyBankDO = VocabularyBankDO.builder()
.word(word)
.definition(meaning)
.pronunciation("")
.pronunciation(pronunciation)
.pos(pos)
.unitId(gradeUnitId)
.build();
vocabularyBankMapper.insertSelective(vocabularyBankDO);

View File

@@ -1,9 +1,16 @@
package com.yinlihupo.enlish.service.service.exam;
import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsDO;
import com.yinlihupo.enlish.service.domain.dataobject.ExamWordsJudgeResultDO;
import com.yinlihupo.enlish.service.domain.dataobject.VocabularyBankDO;
import com.yinlihupo.enlish.service.domain.mapper.ExamWordsDOMapper;
import com.yinlihupo.enlish.service.domain.mapper.VocabularyBankDOMapper;
import com.yinlihupo.enlish.service.model.bo.CoordinatesXY;
import com.yinlihupo.enlish.service.model.bo.StudentExamId;
import com.yinlihupo.enlish.service.service.ExamWordsJudgeService;
import com.yinlihupo.enlish.service.service.StudentService;
import com.yinlihupo.enlish.service.utils.DifyArticleClient;
import com.yinlihupo.enlish.service.utils.PngUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
@@ -22,9 +29,29 @@ public class ExamWordsJudgeServiceTest {
private StudentService studentService;
@Resource
private DifyArticleClient difyArticleClient;
@Resource
private ExamWordsDOMapper examWordsDOMapper;
@Resource
private VocabularyBankDOMapper vocabularyBankDOMapper;
@Test
public void judgeExamWords() {
examWordsJudgeService.judgeExamWords(1);
String ansSheetPath = "C:\\project\\java\\enlish_edu\\enlish\\enlish-service\\src\\main\\resources\\templates\\3.png";
List<CoordinatesXY> coordinatesXIES = PngUtil.analysisXY(ansSheetPath);
// 从图片中获取学生 id 和考试 id
String tessdataPath = "C:\\project\\tess";
StudentExamId studentExamId = PngUtil.analyzeExamWordsIdAndStudentId(ansSheetPath, tessdataPath, coordinatesXIES);
Integer examWordsId = 41;
ExamWordsDO examWordsDO = examWordsDOMapper.selectById(examWordsId);
List<Integer> wordIds = examWordsDO.getWordIds();
List<Integer> unmemorizedWordIds = PngUtil.analyzePngForUnmemorizedWordIds(ansSheetPath, wordIds, coordinatesXIES);
List<Integer> memorizedWordIds = wordIds.stream().filter(wordId -> !unmemorizedWordIds.contains(wordId)).toList();
List<VocabularyBankDO> vocabularyBankDOS = vocabularyBankDOMapper.selectVocabularyBankDOListByIds(unmemorizedWordIds);
for (VocabularyBankDO vocabularyBankDO : vocabularyBankDOS) {
log.info("未掌握的单词:{}", vocabularyBankDO);
}
}
@Test