From 65f10033448a07535d610ad56a628d7b3f137480 Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Wed, 27 Aug 2025 17:22:14 +0800 Subject: [PATCH] feat(ai): 优化对话项添加逻辑并增强接口返回值 --- src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberAnswerServiceImpl.java | 367 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 365 insertions(+), 2 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberAnswerServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberAnswerServiceImpl.java index 4ece58c..58c9830 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberAnswerServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberAnswerServiceImpl.java @@ -1,15 +1,32 @@ package cc.mrbird.febs.ai.service.impl; -import cc.mrbird.febs.ai.entity.AiMemberAnswer; +import cc.mrbird.febs.ai.entity.*; import cc.mrbird.febs.ai.mapper.AiMemberAnswerMapper; -import cc.mrbird.febs.ai.service.AiMemberAnswerService; +import cc.mrbird.febs.ai.req.memberAnswer.*; +import cc.mrbird.febs.ai.res.memberAnswer.*; +import cc.mrbird.febs.ai.res.product.ApiProductVo; +import cc.mrbird.febs.ai.res.productQuestionItem.ApiMemberAnswerItemVo; +import cc.mrbird.febs.ai.service.*; +import cc.mrbird.febs.ai.utils.UUID; +import cc.mrbird.febs.common.entity.FebsResponse; +import cc.mrbird.febs.common.utils.LoginUserUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Date; import java.util.List; /** @@ -24,6 +41,352 @@ public class AiMemberAnswerServiceImpl extends ServiceImpl<AiMemberAnswerMapper, AiMemberAnswer> implements AiMemberAnswerService { private final AiMemberAnswerMapper aiMemberAnswerMapper; + private final AiMemberAnswerItemService aiMemberAnswerItemService; + private final AiProductService aiProductService; + private final AiProductQuestionService aiProductQuestionService; + private final AiProductQuestionItemService aiProductQuestionItemService; + @Override + public AiMemberAnswer getOneByQuery(LambdaQueryWrapper<AiMemberAnswer> aiMemberAnswerLambdaQueryWrapper) { + aiMemberAnswerLambdaQueryWrapper.last("limit 1"); + return aiMemberAnswerMapper.selectOne(aiMemberAnswerLambdaQueryWrapper); + } + + @Override + public FebsResponse startAnswerV2(ApiMemberAnswerDto dto) { + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + ApiMemberAnswerVoV2 apiMemberAnswerVoV2 = new ApiMemberAnswerVoV2(); + + String productId = dto.getId(); + AiProduct aiProduct = aiProductService.getById(productId); + if(ObjectUtil.isNull(aiProduct)){ + throw new RuntimeException("产品不存在"); + } + //验证产品分类下是否有题目 + String productCategoryId = aiProduct.getProductCategoryId(); + LambdaQueryWrapper<AiProductQuestion> questionLambdaQueryWrapper = Wrappers.lambdaQuery(AiProductQuestion.class); + questionLambdaQueryWrapper.eq(AiProductQuestion::getProductCategoryId,productCategoryId); + questionLambdaQueryWrapper.eq(AiProductQuestion::getState,1); + questionLambdaQueryWrapper.last("limit 1"); + List<AiProductQuestion> aiProductQuestions = aiProductQuestionService.getListByQuery(questionLambdaQueryWrapper); + if(CollUtil.isEmpty(aiProductQuestions)){ + // todo 没有题目采用AI生成题目 + throw new RuntimeException("产品没有题目"); + } + //判断该产品是否有正在进行的练习 + Date createdTime = new Date(); + LambdaQueryWrapper<AiMemberAnswer> aiMemberAnswerLambdaQueryWrapper = Wrappers.lambdaQuery(AiMemberAnswer.class); + aiMemberAnswerLambdaQueryWrapper.eq(AiMemberAnswer::getMemberId,memberUuid); + aiMemberAnswerLambdaQueryWrapper.eq(AiMemberAnswer::getProductId,aiProduct.getId()); + aiMemberAnswerLambdaQueryWrapper.eq(AiMemberAnswer::getState,0); + AiMemberAnswer aiMemberAnswer = this.getOneByQuery(aiMemberAnswerLambdaQueryWrapper); + if(ObjectUtil.isNull(aiMemberAnswer)){ + Integer questionCount = aiProduct.getQuestionCount(); + aiMemberAnswer = new AiMemberAnswer(); + aiMemberAnswer.setId(UUID.getSimpleUUIDString()); + aiMemberAnswer.setCreatedTime(createdTime); + aiMemberAnswer.setUpdatedTime(createdTime); + aiMemberAnswer.setProductId(aiProduct.getId()); + aiMemberAnswer.setMemberId(memberUuid); + aiMemberAnswer.setState(0); + aiMemberAnswer.setScore(0); + aiMemberAnswer.setQuestionCnt(questionCount); + aiMemberAnswer.setDoneCnt(0); + aiMemberAnswer.setCorrectCnt(0); + aiMemberAnswerMapper.insert(aiMemberAnswer); + List<AiMemberAnswerItem> aiMemberAnswerItems = new ArrayList<>(); + for (int i = 1; i <= questionCount; i++){ + //初始化答题记录 + AiProductQuestion aiProductQuestion = aiProductQuestionService.createQuestion(aiProduct.getId()); + AiMemberAnswerItem aiMemberAnswerItem = new AiMemberAnswerItem(); + aiMemberAnswerItem.setId(UUID.getSimpleUUIDString()); + aiMemberAnswerItem.setCreatedTime(createdTime); + aiMemberAnswerItem.setAnswerId(aiMemberAnswer.getId()); + aiMemberAnswerItem.setProductId(aiMemberAnswer.getProductId()); + aiMemberAnswerItem.setMemberId(memberUuid); + aiMemberAnswerItem.setProductQuestionId(aiProductQuestion.getId()); + aiMemberAnswerItem.setTitle(aiProductQuestion.getTitle()); + aiMemberAnswerItem.setDifficulty(aiProductQuestion.getDifficulty()); + aiMemberAnswerItem.setMemberAnswerState(0); + aiMemberAnswerItem.setSort( i ); + aiMemberAnswerItems.add(aiMemberAnswerItem); + } + aiMemberAnswerItemService.saveBatch(aiMemberAnswerItems); + apiMemberAnswerVoV2.setCurrent(1); + }else{ + if (aiMemberAnswer.getQuestionCnt() > aiMemberAnswer.getDoneCnt()){ + apiMemberAnswerVoV2.setCurrent(aiMemberAnswer.getDoneCnt() + 1); + }else{ + apiMemberAnswerVoV2.setCurrent(aiMemberAnswer.getDoneCnt()); + } + } + apiMemberAnswerVoV2.setMemberAnswerId(aiMemberAnswer.getId()); + + return new FebsResponse().success().data(apiMemberAnswerVoV2); + } + + + @Override + public FebsResponse startAnswer(ApiMemberAnswerDto dto) { + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + + String productId = dto.getId(); + AiProduct aiProduct = aiProductService.getById(productId); + if(ObjectUtil.isNull(aiProduct)){ + throw new RuntimeException("产品不存在"); + } + //验证产品分类下是否有题目 + String productCategoryId = aiProduct.getProductCategoryId(); + LambdaQueryWrapper<AiProductQuestion> questionLambdaQueryWrapper = Wrappers.lambdaQuery(AiProductQuestion.class); + questionLambdaQueryWrapper.eq(AiProductQuestion::getProductCategoryId,productCategoryId); + questionLambdaQueryWrapper.eq(AiProductQuestion::getState,1); + questionLambdaQueryWrapper.last("limit 1"); + List<AiProductQuestion> aiProductQuestions = aiProductQuestionService.getListByQuery(questionLambdaQueryWrapper); + if(CollUtil.isEmpty(aiProductQuestions)){ + // todo 没有题目采用AI生成题目 + throw new RuntimeException("产品没有题目"); + } + //判断该产品是否有正在进行的练习 + Date createdTime = new Date(); + LambdaQueryWrapper<AiMemberAnswer> aiMemberAnswerLambdaQueryWrapper = Wrappers.lambdaQuery(AiMemberAnswer.class); + aiMemberAnswerLambdaQueryWrapper.eq(AiMemberAnswer::getMemberId,memberUuid); + aiMemberAnswerLambdaQueryWrapper.eq(AiMemberAnswer::getProductId,aiProduct.getId()); + aiMemberAnswerLambdaQueryWrapper.eq(AiMemberAnswer::getState,0); + AiMemberAnswer aiMemberAnswer = this.getOneByQuery(aiMemberAnswerLambdaQueryWrapper); + if(ObjectUtil.isNull(aiMemberAnswer)){ + aiMemberAnswer = new AiMemberAnswer(); + aiMemberAnswer.setId(UUID.getSimpleUUIDString()); + aiMemberAnswer.setCreatedTime(createdTime); + aiMemberAnswer.setUpdatedTime(createdTime); + aiMemberAnswer.setProductId(aiProduct.getId()); + aiMemberAnswer.setMemberId(memberUuid); + aiMemberAnswer.setState(0); + aiMemberAnswer.setScore(0); + aiMemberAnswer.setQuestionCnt(aiProduct.getQuestionCount()); + aiMemberAnswer.setDoneCnt(0); + aiMemberAnswer.setCorrectCnt(0); + aiMemberAnswerMapper.insert(aiMemberAnswer); + } + boolean checkMemberAnswerDone = this.checkMemberAnswerDone(aiMemberAnswer); + if(!checkMemberAnswerDone){ + return new FebsResponse().fail().message("您已完成本次答题"); + } + + ApiMemberAnswerVo apiMemberAnswerVo = new ApiMemberAnswerVo(); + apiMemberAnswerVo.setMemberAnswerId(aiMemberAnswer.getId()); + apiMemberAnswerVo.setName(aiProduct.getName()); + apiMemberAnswerVo.setQuestionCnt(aiMemberAnswer.getQuestionCnt()); + apiMemberAnswerVo.setDoneCnt(aiMemberAnswer.getDoneCnt()); + apiMemberAnswerVo.setCorrectCnt(aiMemberAnswer.getCorrectCnt()); + apiMemberAnswerVo.setProductId(aiMemberAnswer.getProductId()); + + AiProductQuestion aiProductQuestion = aiProductQuestionService.createQuestion(aiProduct.getId()); + if(ObjectUtil.isNotNull(aiProductQuestion)){ + apiMemberAnswerVo.setProductQuestionId(aiProductQuestion.getId()); + apiMemberAnswerVo.setTitle(aiProductQuestion.getTitle()); + apiMemberAnswerVo.setDifficulty(aiProductQuestion.getDifficulty()); + + //初始化答题记录 + AiMemberAnswerItem aiMemberAnswerItem = new AiMemberAnswerItem(); + aiMemberAnswerItem.setId(UUID.getSimpleUUIDString()); + aiMemberAnswerItem.setCreatedTime(createdTime); + aiMemberAnswerItem.setAnswerId(aiMemberAnswer.getId()); + aiMemberAnswerItem.setProductId(aiMemberAnswer.getProductId()); + aiMemberAnswerItem.setMemberId(memberUuid); + aiMemberAnswerItem.setProductQuestionId(aiProductQuestion.getId()); + aiMemberAnswerItem.setTitle(aiProductQuestion.getTitle()); + aiMemberAnswerItem.setDifficulty(aiProductQuestion.getDifficulty()); + aiMemberAnswerItem.setMemberAnswerState(0); + aiMemberAnswerItemService.save(aiMemberAnswerItem); + apiMemberAnswerVo.setMemberAnswerState(aiMemberAnswerItem.getMemberAnswerState()); + apiMemberAnswerVo.setMemberAnswerItemId(aiMemberAnswerItem.getId()); + + List<ApiMemberAnswerItemVo> answerList = new ArrayList<>(); + LambdaQueryWrapper<AiProductQuestionItem> productQuestionItemLambdaQueryWrapper = Wrappers.lambdaQuery(AiProductQuestionItem.class); + productQuestionItemLambdaQueryWrapper.eq(AiProductQuestionItem::getProductQuestionId,aiProductQuestion.getId()); + productQuestionItemLambdaQueryWrapper.orderByAsc(AiProductQuestionItem::getCreatedTime); + List<AiProductQuestionItem> aiProductQuestionItems = aiProductQuestionItemService.getListByQuery(productQuestionItemLambdaQueryWrapper); + if (CollUtil.isNotEmpty(aiProductQuestionItems)){ + for (AiProductQuestionItem aiProductQuestionItem : aiProductQuestionItems){ + ApiMemberAnswerItemVo apiMemberAnswerItemVo = new ApiMemberAnswerItemVo(); + apiMemberAnswerItemVo.setId(aiProductQuestionItem.getId()); + apiMemberAnswerItemVo.setAnswer(aiProductQuestionItem.getAnswer()); + apiMemberAnswerItemVo.setAnswerAnalysis(aiProductQuestionItem.getAnswerAnalysis()); + apiMemberAnswerItemVo.setCorrectAnswer(aiProductQuestionItem.getCorrectAnswer()); + answerList.add(apiMemberAnswerItemVo); + } + } + apiMemberAnswerVo.setAnswerList(answerList); + } + + return new FebsResponse().success().data(apiMemberAnswerVo); + } + + @Override + public boolean checkMemberAnswerDone(AiMemberAnswer aiMemberAnswer) { + Integer doneCnt = aiMemberAnswer.getDoneCnt(); + Integer questionCnt = aiMemberAnswer.getQuestionCnt(); + if (questionCnt > doneCnt){ + return true; + } + return false; + } + + @Override + public FebsResponse answer(ApiQuestionAnswerDto dto) { + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + + ApiQuestionItemInfoVo apiQuestionItemInfoVo = new ApiQuestionItemInfoVo(); + + String productQuestionItemId = dto.getId(); + String productQuestionId = dto.getProductQuestionId(); + String memberAnswerId = dto.getMemberAnswerId(); + String memberAnswerItemId = dto.getMemberAnswerItemId(); + AiMemberAnswer aiMemberAnswer = this.getById(memberAnswerId); + + if(ObjectUtil.isNull(aiMemberAnswer)){ + throw new RuntimeException("答题记录不存在"); + } + + Date createdTime = new Date(); + AiMemberAnswerItem aiMemberAnswerItem = aiMemberAnswerItemService.getById(memberAnswerItemId); + aiMemberAnswerItem.setUpdatedTime(createdTime); + AiProductQuestion aiProductQuestion = aiProductQuestionService.getById(productQuestionId); + + LambdaQueryWrapper<AiProductQuestionItem> productQuestionItemLambdaQueryWrapper = Wrappers.lambdaQuery(AiProductQuestionItem.class); + productQuestionItemLambdaQueryWrapper.eq(AiProductQuestionItem::getProductQuestionId,aiProductQuestion.getId()); + productQuestionItemLambdaQueryWrapper.eq(AiProductQuestionItem::getCorrectAnswer,1); + List<AiProductQuestionItem> listByQuery = aiProductQuestionItemService.getListByQuery(productQuestionItemLambdaQueryWrapper); + if(CollUtil.isNotEmpty(listByQuery)){ + AiProductQuestionItem aiProductQuestionItem = listByQuery.get(0); + aiMemberAnswerItem.setAnswer(aiProductQuestionItem.getId()); + aiMemberAnswerItem.setCorrectAnswer(aiProductQuestionItem.getCorrectAnswer()); + aiMemberAnswerItem.setAnswerAnalysis(aiProductQuestionItem.getAnswerAnalysis()); + + apiQuestionItemInfoVo.setAnswerID(aiProductQuestionItem.getId()); + apiQuestionItemInfoVo.setAnswer(aiProductQuestionItem.getAnswer()); + } + aiMemberAnswerItem.setMemberAnswerQuestionId(productQuestionItemId); + aiMemberAnswerItem.setMemberAnswerState( + ObjectUtil.equal(aiMemberAnswerItem.getMemberAnswerQuestionId(),aiMemberAnswerItem.getAnswer()) ? 1 : 2 + ); + if (aiMemberAnswerItem.getMemberAnswerState() == 2){ + aiMemberAnswerItem.setIsCollected(1); + }else{ + aiMemberAnswerItem.setIsCollected(0); + } + aiMemberAnswerItemService.updateById(aiMemberAnswerItem); + + aiMemberAnswer.setDoneCnt(aiMemberAnswer.getDoneCnt() + 1); + if (aiMemberAnswerItem.getMemberAnswerState() == 1){ + aiMemberAnswer.setCorrectCnt(aiMemberAnswer.getCorrectCnt() + 1); + } + aiMemberAnswer.setUpdatedTime(createdTime); + aiMemberAnswerMapper.updateById(aiMemberAnswer); + + apiQuestionItemInfoVo.setAnswerAnalysis(aiMemberAnswerItem.getAnswerAnalysis()); + apiQuestionItemInfoVo.setMemberAnswerState(aiMemberAnswerItem.getMemberAnswerState()); + apiQuestionItemInfoVo.setQuestionCnt(aiMemberAnswer.getQuestionCnt()); + apiQuestionItemInfoVo.setDoneCnt(aiMemberAnswer.getDoneCnt()); + return new FebsResponse().success().data(apiQuestionItemInfoVo); + } + + @Override + public FebsResponse insure(ApiMemberAnswerInsureDto dto) { + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + + ApiMemberAnswerInsureVo apiMemberAnswerInsureVo = new ApiMemberAnswerInsureVo(); + String memberAnswerId = dto.getMemberAnswerId(); + AiMemberAnswer aiMemberAnswer = this.getById(memberAnswerId); + Integer questionCnt = aiMemberAnswer.getQuestionCnt(); + Integer correctCnt = aiMemberAnswer.getCorrectCnt(); + Date createdTime = aiMemberAnswer.getCreatedTime(); + Date updatedTime = aiMemberAnswer.getUpdatedTime(); + apiMemberAnswerInsureVo.setCorrectCnt(correctCnt); + + BigDecimal divide = new BigDecimal(correctCnt).divide(new BigDecimal(questionCnt), 2, RoundingMode.HALF_DOWN); + // 转换为百分比字符串 + BigDecimal percentage = divide.multiply(new BigDecimal(100)); + String percentageStr = percentage.setScale(2, RoundingMode.HALF_DOWN).toString() + "%"; + apiMemberAnswerInsureVo.setCorrectCntPercent(percentageStr); + + long between = DateUtil.between(createdTime, updatedTime, DateUnit.MINUTE); + apiMemberAnswerInsureVo.setUseTime(between); + apiMemberAnswerInsureVo.setProductId(aiMemberAnswer.getProductId()); + + aiMemberAnswerMapper.update(null, + Wrappers.lambdaUpdate(AiMemberAnswer.class) + .set(AiMemberAnswer::getUpdatedTime, new Date()) + .set(AiMemberAnswer::getState, 1) + .set(AiMemberAnswer::getScore, percentage.intValue()) + .eq(AiMemberAnswer::getId, memberAnswerId) + ); + return new FebsResponse().success().data(apiMemberAnswerInsureVo); + } + + @Override + public FebsResponse previous(ApiMemberAnswerPreviousDto dto) { + + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + + // 创建分页对象,传入当前页和每页大小 + Page<ApiMemberAnswerPreviousVo> page = new Page<>(dto.getPageNow(), dto.getPageSize()); + Page<ApiMemberAnswerPreviousVo> pageListByQuery = aiMemberAnswerItemService.getPageListByQuery(page, dto); + List<ApiMemberAnswerPreviousVo> records = pageListByQuery.getRecords(); + if (CollUtil.isNotEmpty(records)){ + ApiMemberAnswerPreviousVo apiMemberAnswerPreviousVo = records.get(0); + + String memberAnswerId = apiMemberAnswerPreviousVo.getMemberAnswerId(); + AiMemberAnswer aiMemberAnswer = this.getById(memberAnswerId); + String productId = aiMemberAnswer.getProductId(); + AiProduct aiProduct = aiProductService.getById(productId); + apiMemberAnswerPreviousVo.setName(aiProduct.getName()); + apiMemberAnswerPreviousVo.setQuestionCnt(aiMemberAnswer.getQuestionCnt()); + apiMemberAnswerPreviousVo.setDoneCnt(aiMemberAnswer.getDoneCnt()); + + String productQuestionId = apiMemberAnswerPreviousVo.getProductQuestionId(); + AiProductQuestion aiProductQuestion = aiProductQuestionService.getById(productQuestionId); + apiMemberAnswerPreviousVo.setTitle(aiProductQuestion.getTitle()); + apiMemberAnswerPreviousVo.setDifficulty(aiProductQuestion.getDifficulty()); + + List<ApiMemberAnswerPreviousItemVo> answerList = new ArrayList<>(); + LambdaQueryWrapper<AiProductQuestionItem> productQuestionItemLambdaQueryWrapper = Wrappers.lambdaQuery(AiProductQuestionItem.class); + productQuestionItemLambdaQueryWrapper.eq(AiProductQuestionItem::getProductQuestionId,productQuestionId); + productQuestionItemLambdaQueryWrapper.orderByAsc(AiProductQuestionItem::getCreatedTime); + List<AiProductQuestionItem> listByQuery = aiProductQuestionItemService.getListByQuery(productQuestionItemLambdaQueryWrapper); + if(CollUtil.isNotEmpty(listByQuery)){ + for (AiProductQuestionItem aiProductQuestionItem : listByQuery){ + ApiMemberAnswerPreviousItemVo apiMemberAnswerPreviousItemVo = new ApiMemberAnswerPreviousItemVo(); + apiMemberAnswerPreviousItemVo.setId(aiProductQuestionItem.getId()); + apiMemberAnswerPreviousItemVo.setAnswer(aiProductQuestionItem.getAnswer()); + apiMemberAnswerPreviousItemVo.setAnswerAnalysis(aiProductQuestionItem.getAnswerAnalysis()); + apiMemberAnswerPreviousItemVo.setCorrectAnswer(aiProductQuestionItem.getCorrectAnswer()); + answerList.add(apiMemberAnswerPreviousItemVo); + } + apiMemberAnswerPreviousVo.setAnswerList(answerList); + } + } + return new FebsResponse().success().data(pageListByQuery); + } + + @Override + public FebsResponse wrongPage(ApiMemberAnswerWrongPageDto dto) { + + + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + dto.setMemberUuid(memberUuid); + return aiMemberAnswerItemService.wrongPage(dto); + } + + @Override + public FebsResponse myWork(ApiMemberProductWorkPageDto dto) { + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + dto.setMemberUuid(memberUuid); + // 创建分页对象,传入当前页和每页大小 + Page<ApiMemberProductWorkVo> page = new Page<>(dto.getPageNow(), dto.getPageSize()); + Page<ApiMemberProductWorkVo> pageListByQuery = this.getBaseMapper().getPageMyWorkListByQuery(page, dto); + + return new FebsResponse().success().data(pageListByQuery); + } } -- Gitblit v1.9.1