|
|
|
@ -4,9 +4,9 @@ import cn.hutool.core.collection.CollUtil; |
|
|
|
import cn.hutool.core.util.RandomUtil; |
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
|
|
import com.project.base.config.SnowflakeIdWorker; |
|
|
|
import com.project.base.domain.exception.BusinessErrorException; |
|
|
|
import com.project.base.domain.result.Result; |
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper; |
|
|
|
import com.project.classicpaper.domain.dto.ClassicPaperDTO; |
|
|
|
import com.project.classicpaper.domain.dto.ClassicPaperSetDTO; |
|
|
|
import com.project.classicpaper.domain.entity.ClassicPaperEntity; |
|
|
|
@ -68,7 +68,10 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
@Autowired |
|
|
|
private TaskKnowledgePointBaseService taskKnowledgePointBaseService; |
|
|
|
|
|
|
|
private final SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(0, 0); |
|
|
|
@Autowired |
|
|
|
private com.project.task.config.ExamScoreRatioConfig examScoreRatioConfig; |
|
|
|
|
|
|
|
private final ObjectMapper objectMapper = new ObjectMapper(); |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
@ -142,6 +145,9 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
throw new BusinessErrorException("多选题数量(" + multipleChoiceNum + ")不能超过知识点簇(大小>1)个数(" + allClusters.size() + ")"); |
|
|
|
} |
|
|
|
|
|
|
|
// 收集关联的资料ID列表(JSON数组)
|
|
|
|
String informationIdsJson = toJsonArray(informationIds); |
|
|
|
|
|
|
|
int setCount = request.getSetCount(); |
|
|
|
|
|
|
|
// 6. 创建套题组(Set)
|
|
|
|
@ -160,26 +166,27 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
paperSet.setStatus(ClassicPaperStatusEnum.GENERATING.getValue()); |
|
|
|
classicPaperSetBaseService.save(paperSet); |
|
|
|
|
|
|
|
// 7. 创建 paperGroupId(N个版本共享,用于知识点模板数据关联)
|
|
|
|
Long paperGroupId = snowflakeIdWorker.nextId(); |
|
|
|
// 初始化分值比例(只包含数量 > 0 的题型)
|
|
|
|
paperSet.setScoreRatio(buildScoreRatio(request)); |
|
|
|
classicPaperSetBaseService.updateById(paperSet); |
|
|
|
|
|
|
|
// 8. 循环生成 N 个版本(每套独立采样)
|
|
|
|
// 7. 循环生成 N 个版本(每套独立采样),用 setId 关联模板数据
|
|
|
|
List<ClassicPaperDTO> paperDTOs = new ArrayList<>(); |
|
|
|
for (int i = 1; i <= setCount; i++) { |
|
|
|
ClassicPaperDTO paperDTO = generateOnePaper(paperSet.getId(), paperGroupId, i, request, allKps, allClusters, informationIds); |
|
|
|
ClassicPaperDTO paperDTO = generateOnePaper(paperSet.getId(), i, request, allKps, allClusters, informationIdsJson); |
|
|
|
paperDTOs.add(paperDTO); |
|
|
|
} |
|
|
|
|
|
|
|
// 9. 所有子套题生成完成,将状态从"生成中"改为"草稿"
|
|
|
|
// 8. 所有子套题生成完成,将状态从"生成中"改为"草稿"
|
|
|
|
classicPaperBaseService.lambdaUpdate() |
|
|
|
.eq(ClassicPaperEntity::getPaperGroupId, paperGroupId) |
|
|
|
.eq(ClassicPaperEntity::getSetId, paperSet.getId()) |
|
|
|
.set(ClassicPaperEntity::getStatus, ClassicPaperStatusEnum.DRAFT.getValue()) |
|
|
|
.update(); |
|
|
|
paperSet.setStatus(ClassicPaperStatusEnum.DRAFT.getValue()); |
|
|
|
classicPaperSetBaseService.updateById(paperSet); |
|
|
|
|
|
|
|
log.info(">>> [经典套题] 批量生成完成, setId={}, paperGroupId={}, 版本数={}, 每套题数={}", |
|
|
|
paperSet.getId(), paperGroupId, setCount, totalPerSet); |
|
|
|
log.info(">>> [经典套题] 批量生成完成, setId={}, 版本数={}, 每套题数={}", |
|
|
|
paperSet.getId(), setCount, totalPerSet); |
|
|
|
|
|
|
|
// 10. 构建返回 DTO
|
|
|
|
ClassicPaperSetDTO setDTO = paperSet.toDTO(ClassicPaperSetDTO::new); |
|
|
|
@ -215,11 +222,11 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
/** |
|
|
|
* 生成一个版本的套卷 |
|
|
|
*/ |
|
|
|
private ClassicPaperDTO generateOnePaper(Long setId, Long paperGroupId, int setIndex, |
|
|
|
private ClassicPaperDTO generateOnePaper(Long setId, int setIndex, |
|
|
|
ClassicPaperSetDTO request, |
|
|
|
List<KnowledgePointEntity> allKps, |
|
|
|
List<KnowledgeClusterEntity> allClusters, |
|
|
|
List<Long> informationIds) throws Exception { |
|
|
|
String informationIdsJson) throws Exception { |
|
|
|
// 创建套卷实体
|
|
|
|
ClassicPaperEntity paper = new ClassicPaperEntity(); |
|
|
|
paper.setName(request.getName() + "-V" + setIndex); |
|
|
|
@ -227,8 +234,8 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
paper.setSourceType(ClassicPaperSourceTypeEnum.AI_GENERATED.getValue()); |
|
|
|
paper.setSubLineId(request.getSubLineId()); |
|
|
|
paper.setClassicCategoryId(request.getClassicCategoryId()); |
|
|
|
paper.setStatus(ClassicPaperStatusEnum.GENERATING.getValue()); // 初始状态:生成中
|
|
|
|
paper.setPaperGroupId(paperGroupId); |
|
|
|
paper.setInformationIds(informationIdsJson); |
|
|
|
paper.setStatus(ClassicPaperStatusEnum.GENERATING.getValue()); |
|
|
|
paper.setSetId(setId); |
|
|
|
paper.setSetIndex(setIndex); |
|
|
|
paper.setQuestionCount(0); |
|
|
|
@ -253,14 +260,13 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
int singleChoiceNum = Optional.ofNullable(request.getSingleChoiceNum()).orElse(0); |
|
|
|
if (singleChoiceNum > 0) { |
|
|
|
List<KnowledgePointEntity> sampledKps = sampleKps(shuffledKps, singleChoiceNum); |
|
|
|
// 创建 TaskKnowledgePointEntity
|
|
|
|
// 注意:taskId 为 null,后续任务绑定套卷时通过 groupId 赋值 taskId
|
|
|
|
// 创建 TaskKnowledgePointEntity(groupId = setId,taskId 为 null,后续任务绑定时赋值)
|
|
|
|
for (KnowledgePointEntity kp : sampledKps) { |
|
|
|
TaskKnowledgePointEntity taskKp = new TaskKnowledgePointEntity(); |
|
|
|
taskKp.setGroupId(paperGroupId); |
|
|
|
taskKp.setGroupId(setId); |
|
|
|
taskKp.setAtomId(kp.getId()); |
|
|
|
taskKp.setContent(kp.getContent()); |
|
|
|
taskKp.setClusterSize(1); // 单知识点维度
|
|
|
|
taskKp.setClusterSize(1); |
|
|
|
taskPointEntities.add(taskKp); |
|
|
|
} |
|
|
|
// 调用生成器生成题目
|
|
|
|
@ -290,7 +296,7 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
List<KnowledgePointEntity> sampledKps = sampleKps(availableKps, trueFalseNum); |
|
|
|
for (KnowledgePointEntity kp : sampledKps) { |
|
|
|
TaskKnowledgePointEntity taskKp = new TaskKnowledgePointEntity(); |
|
|
|
taskKp.setGroupId(paperGroupId); |
|
|
|
taskKp.setGroupId(setId); |
|
|
|
taskKp.setAtomId(kp.getId()); |
|
|
|
taskKp.setContent(kp.getContent()); |
|
|
|
taskKp.setClusterSize(1); |
|
|
|
@ -316,9 +322,9 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
for (KnowledgeClusterEntity cluster : sampledClusters) { |
|
|
|
// 记录已使用的资料级簇ID
|
|
|
|
usedSourceClusterIds.add(cluster.getId()); |
|
|
|
// 创建 TaskKnowledgeClusterEntity(groupId = paperGroupId,taskId 后续任务绑定时赋值)
|
|
|
|
// 创建 TaskKnowledgeClusterEntity(groupId = setId,taskId 后续任务绑定时赋值)
|
|
|
|
TaskKnowledgeClusterEntity taskCluster = new TaskKnowledgeClusterEntity(); |
|
|
|
taskCluster.setGroupId(paperGroupId); |
|
|
|
taskCluster.setGroupId(setId); |
|
|
|
taskCluster.setClusterTopic(cluster.getClusterTopic()); |
|
|
|
taskCluster.setClusterSize(cluster.getClusterSize()); |
|
|
|
taskCluster.setInformationId(cluster.getInformationId()); |
|
|
|
@ -334,7 +340,7 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
// 创建 TaskKnowledgePointEntity
|
|
|
|
for (KnowledgePointEntity kp : clusterKps) { |
|
|
|
TaskKnowledgePointEntity taskKp = new TaskKnowledgePointEntity(); |
|
|
|
taskKp.setGroupId(paperGroupId); |
|
|
|
taskKp.setGroupId(setId); |
|
|
|
taskKp.setClusterId(taskCluster.getId()); |
|
|
|
taskKp.setAtomId(kp.getId()); |
|
|
|
taskKp.setContent(kp.getContent()); |
|
|
|
@ -368,9 +374,9 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
List<KnowledgeClusterEntity> sampledClusters = sampleClusters(availableClusters, multipleChoiceNum); |
|
|
|
|
|
|
|
for (KnowledgeClusterEntity cluster : sampledClusters) { |
|
|
|
// 创建 TaskKnowledgeClusterEntity(taskId 后续任务绑定时赋值)
|
|
|
|
// 创建 TaskKnowledgeClusterEntity(groupId = setId,taskId 后续任务绑定时赋值)
|
|
|
|
TaskKnowledgeClusterEntity taskCluster = new TaskKnowledgeClusterEntity(); |
|
|
|
taskCluster.setGroupId(paperGroupId); |
|
|
|
taskCluster.setGroupId(setId); |
|
|
|
taskCluster.setClusterTopic(cluster.getClusterTopic()); |
|
|
|
taskCluster.setClusterSize(cluster.getClusterSize()); |
|
|
|
taskCluster.setInformationId(cluster.getInformationId()); |
|
|
|
@ -389,7 +395,7 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
// 创建 TaskKnowledgePointEntity
|
|
|
|
for (KnowledgePointEntity kp : subSampledKps) { |
|
|
|
TaskKnowledgePointEntity taskKp = new TaskKnowledgePointEntity(); |
|
|
|
taskKp.setGroupId(paperGroupId); |
|
|
|
taskKp.setGroupId(setId); |
|
|
|
taskKp.setClusterId(taskCluster.getId()); |
|
|
|
taskKp.setAtomId(kp.getId()); |
|
|
|
taskKp.setContent(kp.getContent()); |
|
|
|
@ -430,6 +436,43 @@ public class GenerateClassicPaperDomainServiceImpl implements GenerateClassicPap |
|
|
|
return dto; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 构建分值比例 JSON(只包含数量 > 0 的题型) |
|
|
|
*/ |
|
|
|
private String buildScoreRatio(ClassicPaperSetDTO request) { |
|
|
|
Map<String, Integer> ratioMap = new LinkedHashMap<>(); |
|
|
|
if (Optional.ofNullable(request.getSingleChoiceNum()).orElse(0) > 0) { |
|
|
|
ratioMap.put("single", examScoreRatioConfig.getSingle()); |
|
|
|
} |
|
|
|
if (Optional.ofNullable(request.getMultipleChoiceNum()).orElse(0) > 0) { |
|
|
|
ratioMap.put("multiple", examScoreRatioConfig.getMultiple()); |
|
|
|
} |
|
|
|
if (Optional.ofNullable(request.getTrueFalseNum()).orElse(0) > 0) { |
|
|
|
ratioMap.put("trueFalse", examScoreRatioConfig.getTrueFalse()); |
|
|
|
} |
|
|
|
if (Optional.ofNullable(request.getShortAnswerNum()).orElse(0) > 0) { |
|
|
|
ratioMap.put("shortAnswer", examScoreRatioConfig.getShortAnswer()); |
|
|
|
} |
|
|
|
try { |
|
|
|
return objectMapper.writeValueAsString(ratioMap); |
|
|
|
} catch (Exception e) { |
|
|
|
log.warn(">>> [经典套题] scoreRatio 序列化失败", e); |
|
|
|
return "{}"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 将资料ID列表转为JSON数组字符串 |
|
|
|
*/ |
|
|
|
private String toJsonArray(List<Long> ids) { |
|
|
|
try { |
|
|
|
return objectMapper.writeValueAsString(ids); |
|
|
|
} catch (Exception e) { |
|
|
|
log.warn(">>> [经典套题] informationIds JSON序列化失败", e); |
|
|
|
return "[]"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 从知识点池中采样指定数量的知识点 |
|
|
|
*/ |
|
|
|
|