From f8f1d6a91b32077c69dd97334559fe3165ff79b6 Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Tue, 02 Sep 2025 13:45:20 +0800 Subject: [PATCH] feat(ai): 添加 AI 用户陪练(流式)功能 --- src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkReloadStreamDto.java | 22 +++ src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkStreamDto.java | 20 +++ src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkStreamVo.java | 39 ++++++ src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkReloadStreamVo.java | 35 +++++ src/main/java/cc/mrbird/febs/ai/service/ApiMemberTalkStreamService.java | 21 +++ src/main/java/cc/mrbird/febs/ai/service/impl/ApiMemberTalkStreamServiceImpl.java | 111 ++++++++++++++++++ src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkStreamController.java | 59 +++++++++ 7 files changed, 307 insertions(+), 0 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkStreamController.java b/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkStreamController.java new file mode 100644 index 0000000..277d56e --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkStreamController.java @@ -0,0 +1,59 @@ +package cc.mrbird.febs.ai.controller.memberTalk; + +import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto; +import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkReloadStreamDto; +import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkStreamDto; +import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkItemVo; +import cc.mrbird.febs.ai.res.memberTalkStream.ApiMemberTalkReloadStreamVo; +import cc.mrbird.febs.ai.res.memberTalkStream.ApiMemberTalkStreamVo; +import cc.mrbird.febs.ai.service.ApiMemberTalkStreamService; +import cc.mrbird.febs.common.entity.FebsResponse; +import io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * @author Administrator + */ +@Slf4j +@Validated +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/api/ai/memberTalkStream") +@Api(value = "ApiMemberTalkStreamController", tags = "AI-用户陪练(流式)") +public class ApiMemberTalkStreamController { + + private final ApiMemberTalkStreamService apiMemberTalkStreamService; + + @ApiOperation("生成题目") + @ApiResponses({ + @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), + }) + @PostMapping("/start") + public FebsResponse start(@RequestBody @Validated ApiMemberTalkStreamDto dto) { + return apiMemberTalkStreamService.start(dto); + } + + @ApiOperation(value = "再练一次(重新回答)", notes = "再练一次(重新回答)") + @ApiResponses({ + @ApiResponse(code = 200, message = "success", response = ApiMemberTalkReloadStreamVo.class) + }) + @PostMapping(value = "/reload") + public FebsResponse reload(@RequestBody @Validated ApiMemberTalkReloadStreamDto dto) { + + return apiMemberTalkStreamService.reload(dto); + } + + @ApiOperation(value = "对话记录分页查询", notes = "对话记录分页查询") + @ApiResponses({ + @ApiResponse(code = 200, message = "success", response = ApiMemberTalkItemVo.class) + }) + @PostMapping(value = "/historyPage") + public FebsResponse historyPage(@RequestBody @Validated ApiMemberTalkItemPageDto dto) { + + return apiMemberTalkStreamService.historyPage(dto); + } + +} diff --git a/src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkReloadStreamDto.java b/src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkReloadStreamDto.java new file mode 100644 index 0000000..6a2ddae --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkReloadStreamDto.java @@ -0,0 +1,22 @@ +package cc.mrbird.febs.ai.req.memberTalkStream; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiMemberTalkReloadStreamDto", description = "参数") +public class ApiMemberTalkReloadStreamDto { + + /** + * 用户对话ID (UUID) + */ + @NotBlank(message = "会话ID不能为空") + @ApiModelProperty(value = "会话ID", example = "10") + private String memberTalkId; +} diff --git a/src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkStreamDto.java b/src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkStreamDto.java new file mode 100644 index 0000000..c21b724 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkStreamDto.java @@ -0,0 +1,20 @@ +package cc.mrbird.febs.ai.req.memberTalkStream; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiMemberTalkStreamDto", description = "参数") +public class ApiMemberTalkStreamDto { + + @NotBlank(message = "ID不能为空") + @ApiModelProperty(value = "产品ID", example = "10") + private String id; + +} diff --git a/src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkReloadStreamVo.java b/src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkReloadStreamVo.java new file mode 100644 index 0000000..dd0be0b --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkReloadStreamVo.java @@ -0,0 +1,35 @@ +package cc.mrbird.febs.ai.res.memberTalkStream; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiMemberTalkReloadStreamVo", description = "参数") +public class ApiMemberTalkReloadStreamVo { + + /** + * 用户对话ID (UUID) + */ + + @ApiModelProperty(value = "会话ID") + private String memberTalkId; + + /** + * 类型 1-AI提问 2-用户回答 3-AI分析结果 + */ + + @ApiModelProperty(value = "类型 1-AI提问 2-用户回答 3-AI分析结果") + private Integer type; + + /** + * 内容 + */ + + @ApiModelProperty(value = "内容(文本格式)") + private String context; + +} diff --git a/src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkStreamVo.java b/src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkStreamVo.java new file mode 100644 index 0000000..748cf4d --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/res/memberTalkStream/ApiMemberTalkStreamVo.java @@ -0,0 +1,39 @@ +package cc.mrbird.febs.ai.res.memberTalkStream; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiMemberTalkStreamVo", description = "参数") +public class ApiMemberTalkStreamVo { + /** + * 用户对话ID (UUID) + */ + + @ApiModelProperty(value = "会话ID") + private String memberTalkItemId; + + @ApiModelProperty(value = "会话ID") + private String memberTalkId; + + /** + * 类型 1-AI提问 2-用户回答 3-AI分析结果 + */ + + @ApiModelProperty(value = "类型 1-AI提问 2-用户回答 3-AI分析结果") + private Integer type; + + /** + * 内容 + */ + + @ApiModelProperty(value = "内容(文本格式)") + private String context; + + @ApiModelProperty(value = "内容亮点、建议、参考答案、核心知识点雷达图表数据(数据对象)") + private String report; +} diff --git a/src/main/java/cc/mrbird/febs/ai/service/ApiMemberTalkStreamService.java b/src/main/java/cc/mrbird/febs/ai/service/ApiMemberTalkStreamService.java new file mode 100644 index 0000000..ee5e950 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/service/ApiMemberTalkStreamService.java @@ -0,0 +1,21 @@ +package cc.mrbird.febs.ai.service; + +import cc.mrbird.febs.ai.entity.AiMemberTalk; +import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto; +import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkReloadStreamDto; +import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkStreamDto; +import cc.mrbird.febs.common.entity.FebsResponse; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface ApiMemberTalkStreamService extends IService<AiMemberTalk> { + /** + * 生成题目(流式) + * @param dto + * @return + */ + FebsResponse start(ApiMemberTalkStreamDto dto); + + FebsResponse reload(ApiMemberTalkReloadStreamDto dto); + + FebsResponse historyPage(ApiMemberTalkItemPageDto dto); +} diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/ApiMemberTalkStreamServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/ApiMemberTalkStreamServiceImpl.java new file mode 100644 index 0000000..e620a93 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/ApiMemberTalkStreamServiceImpl.java @@ -0,0 +1,111 @@ +package cc.mrbird.febs.ai.service.impl; + +import cc.mrbird.febs.ai.entity.AiMemberTalk; +import cc.mrbird.febs.ai.entity.AiMemberTalkItem; +import cc.mrbird.febs.ai.entity.AiProductQuestion; +import cc.mrbird.febs.ai.entity.AiProductRoleLink; +import cc.mrbird.febs.ai.enumerates.AiTypeEnum; +import cc.mrbird.febs.ai.mapper.AiMemberTalkMapper; +import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto; +import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkReloadStreamDto; +import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkStreamDto; +import cc.mrbird.febs.ai.res.memberTalkStream.ApiMemberTalkReloadStreamVo; +import cc.mrbird.febs.ai.res.memberTalkStream.ApiMemberTalkStreamVo; +import cc.mrbird.febs.ai.service.*; +import cc.mrbird.febs.common.entity.FebsResponse; +import cc.mrbird.febs.common.exception.FebsException; +import cc.mrbird.febs.common.utils.LoginUserUtil; +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.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** + * AI用户对话训练记录 Service实现类 + * + * @author yourname + * @date 2025-07-29 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class ApiMemberTalkStreamServiceImpl extends ServiceImpl<AiMemberTalkMapper, AiMemberTalk> implements ApiMemberTalkStreamService { + + private final AiMemberTalkMapper aiMemberTalkMapper; + private final AiProductRoleLinkService aiProductRoleLinkService; + private final AiMemberTalkService aiMemberTalkService; + private final AiMemberTalkItemService aiMemberTalkItemService; + private final AiProductQuestionService aiProductQuestionService; + private final AiService aiService; + + + @Override + public FebsResponse start(ApiMemberTalkStreamDto dto) { + + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + String productId = dto.getId(); + LambdaQueryWrapper<AiProductRoleLink> productLinkQuery = Wrappers.lambdaQuery(AiProductRoleLink.class); + productLinkQuery.eq(AiProductRoleLink::getProductId,productId); + productLinkQuery.last("limit 1"); + AiProductRoleLink aiProductRoleLink = aiProductRoleLinkService.getByQuery(productLinkQuery); + if(ObjectUtil.isNull(aiProductRoleLink)){ + throw new FebsException("产品AI陪练不存在"); + } + + Date nowTime = new Date(); + LambdaQueryWrapper<AiMemberTalk> query = Wrappers.lambdaQuery(AiMemberTalk.class); + query.eq(AiMemberTalk::getMemberId,memberUuid); + query.eq(AiMemberTalk::getProductId,productId); + query.last("limit 1"); + AiMemberTalk aiMemberTalk = aiMemberTalkService.getByQuery(query); + if (ObjectUtil.isNull(aiMemberTalk)){ + aiMemberTalk = aiMemberTalkService.add(memberUuid,productId,nowTime); + } + + ApiMemberTalkStreamVo apiMemberTalkVo = new ApiMemberTalkStreamVo(); + String title = "加载时间过程,请重试!"; + AiProductQuestion question = aiProductQuestionService.createQuestion(productId); + if (ObjectUtil.isNotNull(question)){ + AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.add(memberUuid, aiMemberTalk.getId(), 1, title, nowTime); + apiMemberTalkVo.setMemberTalkItemId(aiMemberTalkItem.getId()); + aiMemberTalkService.updateTimeUpdate(nowTime,aiMemberTalk.getId()); + question.getTitle(); + } + apiMemberTalkVo.setMemberTalkId(aiMemberTalk.getId()); + apiMemberTalkVo.setType(1); + apiMemberTalkVo.setContext(title); + return new FebsResponse().success().data(apiMemberTalkVo); + } + + @Override + public FebsResponse reload(ApiMemberTalkReloadStreamDto dto) { + + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + ApiMemberTalkReloadStreamVo apiMemberTalkReloadVo = new ApiMemberTalkReloadStreamVo(); + String memberTalkId = dto.getMemberTalkId(); + LambdaQueryWrapper<AiMemberTalkItem> queryWrapper = Wrappers.lambdaQuery(AiMemberTalkItem.class); + queryWrapper.eq(AiMemberTalkItem::getMemberTalkId,memberTalkId); + queryWrapper.eq(AiMemberTalkItem::getType,AiTypeEnum.QUESTION_ANSWER.getCode()); + queryWrapper.orderByDesc(AiMemberTalkItem::getCreatedTime); + queryWrapper.last("limit 1"); + AiMemberTalkItem byQuery = aiMemberTalkItemService.getByQuery(queryWrapper); + if (ObjectUtil.isNotNull(byQuery)){ + apiMemberTalkReloadVo.setContext(byQuery.getContext()); + apiMemberTalkReloadVo.setMemberTalkId(memberTalkId); + apiMemberTalkReloadVo.setType(AiTypeEnum.QUESTION_ANSWER.getCode()); + } + return new FebsResponse().success().data(apiMemberTalkReloadVo); + } + + @Override + public FebsResponse historyPage(ApiMemberTalkItemPageDto dto) { + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + dto.setMemberUuid(memberUuid); + return new FebsResponse().success().data(aiMemberTalkItemService.historyPage(dto)); + } +} -- Gitblit v1.9.1