feat(ai): 新增 AI 陪练相关功能
- 新增 AiMemberAnswerService 接口及实现类,用于处理成员答案相关操作
- 新增 AiMemberPointService 接口及实现类,用于处理成员积分相关操作
- 新增 AiMemberService 接口及实现类,用于处理成员信息相关操作
- 新增 AiMemberTalkService 接口及实现类,用于处理成员对话相关操作
- 新增 AiMemberTalkStreamService接口及实现类,用于处理成员对话流相关操作
- 新增 AiProductCategoryService 接口及实现类,用于处理产品分类相关操作
- 新增 AiServiceImpl 类,用于实现 AI 服务相关功能
29 files modified
6 files added
3 files renamed
| | |
| | | import cc.mrbird.febs.ai.enumerates.AiPromptEnum; |
| | | import cc.mrbird.febs.ai.mapper.AiMemberMapper; |
| | | import cc.mrbird.febs.ai.req.talk.AiTalkAnswerStream; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVoOld; |
| | | import cc.mrbird.febs.ai.service.AiService; |
| | | import cc.mrbird.febs.ai.strategy.enumerates.LlmStrategyEnum; |
| | | import cc.mrbird.febs.ai.strategy.LlmStrategyFactory; |
| | |
| | | |
| | | @ApiOperation("提问AI(流式)V2") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @PostMapping("/answer-streamV2") |
| | | public Flux<FebsResponse> answerStreamV2(@RequestBody @Validated AiTalkAnswerStream dto) { |
| | |
| | | |
| | | @ApiOperation("提问AI(流式)V3") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @PostMapping("/answerStreamV3") |
| | | public Flux<FebsResponse> answerStreamV3(@RequestBody @Validated AiTalkAnswerStream dto) { |
| | |
| | | |
| | | @ApiOperation("提问AI(非流式响应)V4") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "非流式响应", response = ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "非流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @PostMapping("/answerStreamV4") |
| | | public FebsResponse answerStreamV4(@RequestBody @Validated AiTalkAnswerStream dto) { |
| | |
| | | package cc.mrbird.febs.ai.controller.member; |
| | | |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberPageDto; |
| | | import cc.mrbird.febs.ai.req.memberPoint.ApiMemberPointDto; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberPageVo; |
| | | import cc.mrbird.febs.ai.res.memberAnswer.ApiMemberAnswerVoV2; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamPageDto; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamPracticeDto; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamStudyDto; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberTeamPageVo; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberTeamPracticeVo; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberTeamStudyVo; |
| | | import cc.mrbird.febs.ai.service.AiMemberService; |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | | import io.swagger.annotations.Api; |
| | |
| | | |
| | | @ApiOperation(value = "我的团队", notes = "我的团队") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "success", response = ApiMemberPageVo.class) |
| | | @ApiResponse(code = 200, message = "success", response = ApiMemberTeamPageVo.class) |
| | | }) |
| | | @PostMapping(value = "/myTeam") |
| | | public FebsResponse myTeam(@RequestBody @Validated ApiMemberPageDto dto) { |
| | | public FebsResponse myTeam(@RequestBody @Validated ApiMemberTeamPageDto dto) { |
| | | |
| | | return aiMemberService.myTeam(dto); |
| | | } |
| | | |
| | | @ApiOperation(value = "练习次数", notes = "练习次数") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "success", response = ApiMemberTeamPracticeVo.class) |
| | | }) |
| | | @PostMapping(value = "/practice") |
| | | public FebsResponse practice(@RequestBody @Validated ApiMemberTeamPracticeDto dto) { |
| | | |
| | | return aiMemberService.practice(dto); |
| | | } |
| | | |
| | | @ApiOperation(value = "学习时长", notes = "学习时长") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "success", response = ApiMemberTeamStudyVo.class) |
| | | }) |
| | | @PostMapping(value = "/study") |
| | | public FebsResponse study(@RequestBody @Validated ApiMemberTeamStudyDto dto) { |
| | | |
| | | return aiMemberService.study(dto); |
| | | } |
| | | } |
| | |
| | | import cc.mrbird.febs.ai.req.memberTalk.*; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkItemVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkReloadVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVoOld; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkVo; |
| | | import cc.mrbird.febs.ai.service.AiMemberTalkService; |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | |
| | | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; |
| | | import reactor.core.publisher.Flux; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author Administrator |
| | |
| | | // 修改接口定义 |
| | | @ApiOperation("开始AI对话(流式)") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @GetMapping("/answer-stream") |
| | | public Flux<FebsResponse> answerStream(@RequestParam String question) { |
| | |
| | | import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto; |
| | | import cc.mrbird.febs.ai.req.memberTalkStream.*; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkItemVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkMemberAnswerSavaVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVoOld; |
| | | import cc.mrbird.febs.ai.res.memberTalkStream.ApiMemberTalkReloadStreamVo; |
| | | import cc.mrbird.febs.ai.res.memberTalkStream.ApiMemberTalkStreamVo; |
| | | import cc.mrbird.febs.ai.service.AiMemberTalkStreamService; |
| | |
| | | } |
| | | |
| | | @ApiOperation(value = "保存用户回答", notes = "保存答案") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "success", response = ApiMemberTalkMemberAnswerSavaVo.class) |
| | | }) |
| | | @PostMapping(value = "/saveMemberAnswer") |
| | | public FebsResponse saveMemberAnswer(@RequestBody @Validated ApiMemberTalkMemberAnswerSavaDto dto) { |
| | | |
| | |
| | | |
| | | @ApiOperation("回答(流式)") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @PostMapping("/answer") |
| | | public Flux<FebsResponse> answer(@RequestBody @Validated AiTalkAnswerStreamDto dto) { |
| | |
| | | |
| | | @ApiOperation("回答(流式)") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @PostMapping("/answerV2") |
| | | public Flux<FebsResponse> answerV2(@RequestBody @Validated AiTalkAnswerStreamDto dto) { |
| | |
| | | return aiMemberTalkStreamService.saveAnswer(dto); |
| | | } |
| | | |
| | | @ApiOperation(value = "保存AI陪练总结报告", notes = "保存AI陪练总结报告") |
| | | @PostMapping(value = "/saveReport") |
| | | public FebsResponse saveReport(@RequestBody @Validated ApiMemberTalkReportSavaDto dto) { |
| | | |
| | | return aiMemberTalkStreamService.saveReport(dto); |
| | | } |
| | | |
| | | } |
| | |
| | | @PostMapping(value = "/list") |
| | | public FebsResponse list(@RequestBody @Validated ApiProductCategoryPageDto dto) { |
| | | |
| | | return aiProductCategoryService.categoryList(dto); |
| | | return aiProductCategoryService.categoryChildList(dto); |
| | | } |
| | | } |
| | |
| | | package cc.mrbird.febs.ai.controller.talk; |
| | | |
| | | import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkAnswerDto; |
| | | import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkDto; |
| | | import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto; |
| | | import cc.mrbird.febs.ai.req.talk.AiTalkAnswerStream; |
| | | import cc.mrbird.febs.ai.req.talk.ApiTalkDto; |
| | | import cc.mrbird.febs.ai.req.talk.ApiTalkItemPageDto; |
| | | import cc.mrbird.febs.ai.req.talk.ApiTalkPageDto; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkItemVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVoOld; |
| | | import cc.mrbird.febs.ai.res.talk.ApiTalkItemPageVo; |
| | | import cc.mrbird.febs.ai.res.talk.ApiTalkPageVo; |
| | | import cc.mrbird.febs.ai.res.talk.ApiTalkQuestionVo; |
| | | import cc.mrbird.febs.ai.res.talk.ApiTalkVo; |
| | | import cc.mrbird.febs.ai.service.AiMemberTalkService; |
| | | import cc.mrbird.febs.ai.service.AiTalkService; |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | | import cn.hutool.core.util.StrUtil; |
| | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; |
| | | import reactor.core.publisher.Flux; |
| | | |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * @author Administrator |
| | |
| | | |
| | | @ApiOperation("提问AI(流式)") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @GetMapping("/answer-stream") |
| | | public Flux<FebsResponse> answerStream(@RequestParam String question) { |
| | |
| | | |
| | | @ApiOperation("提问AI(流式)V2") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @PostMapping("/answer-streamV2") |
| | | public Flux<FebsResponse> answerStreamV2(@RequestBody @Validated AiTalkAnswerStream dto) { |
| | |
| | | |
| | | @ApiOperation("提问AI(流式带思考过程)V3") |
| | | @ApiResponses({ |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), |
| | | @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVoOld.class), |
| | | }) |
| | | @PostMapping("/answer-streamV3") |
| | | public Flux<FebsResponse> answerStreamV3(@RequestBody @Validated AiTalkAnswerStream dto) { |
| | |
| | | * 用户ID (UUID) |
| | | */ |
| | | private String memberId; |
| | | |
| | | /** |
| | | * 状态 0-进行中 1-已结束 |
| | | */ |
| | | private Integer state; |
| | | |
| | | /** |
| | | * 分析结果 |
| | | */ |
| | | private String analysis; |
| | | |
| | | /** |
| | | * 题目数量 |
| | | */ |
| | | private Integer questionCnt; |
| | | |
| | | /** |
| | | * 作答数量 |
| | | */ |
| | | private Integer doneCnt; |
| | | } |
| | |
| | | public enum AiTypeEnum { |
| | | |
| | | /** |
| | | * ai陪练的消息记录 |
| | | */ |
| | | MESSAGES(1,"MESSAGES"), |
| | | |
| | | AI_MEMBER_ANSWER_STATE_ING(0,"题目练习进行中"), |
| | | AI_MEMBER_ANSWER_STATE_DONE(1,"题目练习已完成"), |
| | | |
| | | AI_MEMBER_TALK_STATE_ING(0,"AI陪练进行中"), |
| | | AI_MEMBER_TALK_STATE_DONE(1,"AI陪练已完成"), |
| | | |
| | | /** |
| | | * 1:用户提问 |
| | | * 2:AI回答 |
| | | */ |
File was renamed from src/main/java/cc/mrbird/febs/ai/req/member/ApiMemberPageDto.java |
| | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberPageDto", description = "参数") |
| | | public class ApiMemberPageDto { |
| | | @ApiModel(value = "ApiMemberTeamPageDto", description = "参数") |
| | | public class ApiMemberTeamPageDto { |
| | | |
| | | @NotNull(message = "页码不能为空") |
| | | @ApiModelProperty(value = "页码", example = "1") |
New file |
| | |
| | | package cc.mrbird.febs.ai.req.member; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberTeamPracticeDto", description = "参数") |
| | | public class ApiMemberTeamPracticeDto { |
| | | |
| | | @NotBlank(message = "用户ID不能为空") |
| | | @ApiModelProperty(value = "用户ID") |
| | | private String memberUuid; |
| | | } |
New file |
| | |
| | | package cc.mrbird.febs.ai.req.member; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberTeamStudyDto", description = "参数") |
| | | public class ApiMemberTeamStudyDto { |
| | | |
| | | @NotBlank(message = "用户ID不能为空") |
| | | @ApiModelProperty(value = "用户ID") |
| | | private String memberUuid; |
| | | } |
| | |
| | | public class AiTalkAnswerStreamDto { |
| | | |
| | | |
| | | @ApiModelProperty(value = "状态:1-总结 0-回答问题", example = "10") |
| | | private Integer state; |
| | | |
| | | |
| | | @ApiModelProperty(value = "类型 1:亮点 2:建议 3:参考答案 4:知识点总结", example = "10") |
| | | private Integer type; |
| | | |
New file |
| | |
| | | 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; |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberTalkReportSavaDto", description = "参数") |
| | | public class ApiMemberTalkReportSavaDto { |
| | | /** |
| | | * 用户对话ID (UUID) |
| | | */ |
| | | @NotBlank(message = "会话ID不能为空") |
| | | @ApiModelProperty(value = "会话ID", example = "10") |
| | | private String memberTalkId; |
| | | |
| | | @NotBlank(message = "回复内容不能为空") |
| | | @ApiModelProperty(value = "回复内容", example = "10") |
| | | private String content; |
| | | |
| | | @NotNull(message = "类型ID不能为空") |
| | | @ApiModelProperty(value = "类型 1:亮点 2:建议 3:参考答案 4:知识点总结", example = "10") |
| | | private Integer type; |
| | | } |
| | |
| | | @ApiModel(value = "ApiProductCategoryPageDto", description = "参数") |
| | | public class ApiProductCategoryPageDto { |
| | | |
| | | @NotNull(message = "页码不能为空") |
| | | @ApiModelProperty(value = "页码", example = "1") |
| | | private Integer pageNow; |
| | | |
| | | @NotNull(message = "每页数量不能为空") |
| | | @ApiModelProperty(value = "每页数量", example = "10") |
| | | private Integer pageSize; |
| | | |
| | | |
| | | @NotBlank(message = "父分类不能为空") |
| | | @ApiModelProperty(value = "父分类ID", example = "123") |
| | | private String parentId; |
File was renamed from src/main/java/cc/mrbird/febs/ai/res/member/ApiMemberPageVo.java |
| | |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberPageVo", description = "参数") |
| | | public class ApiMemberPageVo { |
| | | @ApiModel(value = "ApiMemberTeamPageVo", description = "参数") |
| | | public class ApiMemberTeamPageVo { |
| | | |
| | | @ApiModelProperty(value = "用户ID") |
| | | private String memberUuid; |
| | | |
| | | @ApiModelProperty(value = "类型 1-本人 0-不是本人") |
| | | private Integer type; |
| | | |
| | | @ApiModelProperty(value = "微信名") |
| | | private String nickName; |
| | |
| | | @ApiModelProperty(value = "联系次数") |
| | | private Integer practiceCnt; |
| | | |
| | | @ApiModelProperty(value = "学习时长") |
| | | private Integer studyTime; |
| | | @ApiModelProperty(value = "学习时长(分钟)") |
| | | private String studyTime; |
| | | } |
New file |
| | |
| | | package cc.mrbird.febs.ai.res.member; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.Date; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberTeamPracticeVo", description = "参数") |
| | | public class ApiMemberTeamPracticeVo { |
| | | |
| | | @ApiModelProperty(value = "名称") |
| | | private String name; |
| | | |
| | | @ApiModelProperty(value = "目标") |
| | | private String target; |
| | | |
| | | @ApiModelProperty(value = "题目练习次数") |
| | | private Integer answerCnt; |
| | | |
| | | @ApiModelProperty(value = "AI陪练次数") |
| | | private Integer talkCnt; |
| | | |
| | | } |
New file |
| | |
| | | package cc.mrbird.febs.ai.res.member; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberTeamStudyVo", description = "参数") |
| | | public class ApiMemberTeamStudyVo { |
| | | |
| | | |
| | | @ApiModelProperty(value = "名称") |
| | | private String title; |
| | | |
| | | |
| | | @ApiModelProperty(value = "总时长分钟") |
| | | private String totalTime; |
| | | } |
New file |
| | |
| | | package cc.mrbird.febs.ai.res.memberTalk; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel(value = "ApiMemberTalkMemberAnswerSavaVo", description = "参数") |
| | | public class ApiMemberTalkMemberAnswerSavaVo { |
| | | |
| | | |
| | | @ApiModelProperty(value = "题目数量") |
| | | private Integer questionCnt; |
| | | |
| | | @ApiModelProperty(value = "作答数量") |
| | | private Integer doneCnt; |
| | | } |
File was renamed from src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkStreamVo.java |
| | |
| | | * @author Administrator |
| | | */ |
| | | @Data |
| | | @ApiModel(value = "ApiMemberTalkStreamVo", description = "参数") |
| | | public class ApiMemberTalkStreamVo { |
| | | @ApiModel(value = "ApiMemberTalkStreamVoOld", description = "参数") |
| | | public class ApiMemberTalkStreamVoOld { |
| | | |
| | | @ApiModelProperty(value = "消息") |
| | | private String content; |
| | |
| | | |
| | | @ApiModelProperty(value = "内容亮点、建议、参考答案、核心知识点雷达图表数据(数据对象)") |
| | | private String report; |
| | | |
| | | @ApiModelProperty(value = "题目数量") |
| | | private Integer questionCnt; |
| | | |
| | | @ApiModelProperty(value = "作答数量") |
| | | private Integer doneCnt; |
| | | } |
| | |
| | | FebsResponse myWork(ApiMemberProductWorkPageDto dto); |
| | | |
| | | void updateMemberAnswerUpdateTime(String memberAnswerId, Date updateTime); |
| | | |
| | | List<AiMemberAnswer> getListByCompanyId(String companyId); |
| | | |
| | | List<AiMemberAnswer> getListByCompanyIdAndMemberUuid(String companyId, String memberUuid); |
| | | } |
| | |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | |
| | | import java.util.List; |
| | | |
| | | public interface AiMemberPointService extends IService<AiMemberPoint> { |
| | | |
| | | AiMemberPoint getById(String id); |
| | | |
| | | AiMemberPoint add(String memberUuid, String productPointId, String companyId, Integer totalTime); |
| | | |
| | | |
| | | |
| | | FebsResponse saveTime(ApiMemberPointDto dto); |
| | | |
| | | List<AiMemberPoint> getListByCompanyId(String companyId); |
| | | |
| | | List<AiMemberPoint> getListByCompanyIdAndMemberUuid(String companyId, String memberUuid); |
| | | } |
| | |
| | | package cc.mrbird.febs.ai.service; |
| | | |
| | | import cc.mrbird.febs.ai.entity.AiMember; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberPageDto; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamPageDto; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamPracticeDto; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamStudyDto; |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | |
| | |
| | | |
| | | AiMember getById(String id); |
| | | |
| | | FebsResponse myTeam(ApiMemberPageDto dto); |
| | | FebsResponse myTeam(ApiMemberTeamPageDto dto); |
| | | |
| | | FebsResponse practice(ApiMemberTeamPracticeDto dto); |
| | | |
| | | FebsResponse study(ApiMemberTeamStudyDto dto); |
| | | } |
| | |
| | | |
| | | AiMemberTalkItem add(String memberUuid, String id, String companyId, int type, String resContext, Date createdTime); |
| | | |
| | | AiMemberTalkItem getByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery); |
| | | AiMemberTalkItem getOneByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery); |
| | | |
| | | List<AiMemberTalkItem> getListByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery); |
| | | |
| | | IPage<ApiMemberTalkItemVo> historyPage(ApiMemberTalkItemPageDto dto); |
| | | |
| | |
| | | |
| | | FebsResponse answer(ApiMemberTalkAnswerDto dto); |
| | | |
| | | AiMemberTalk add(String memberUuid,String companyId, String productId, Date nowTime); |
| | | AiMemberTalk add(String memberUuid,String companyId, String productId, Date nowTime,Integer questionCount); |
| | | |
| | | FebsResponse historyPage(ApiMemberTalkItemPageDto dto); |
| | | |
| | | Flux<FebsResponse> answerStream(String question); |
| | | |
| | | List<AiMemberTalk> getListByCompanyId(String companyId); |
| | | |
| | | List<AiMemberTalk> getListByCompanyIdAndMemberUuid(String companyId, String memberUuid); |
| | | } |
| | |
| | | |
| | | FebsResponse saveAnswer(ApiMemberTalkAnswerSavaDto dto); |
| | | |
| | | void updateMemberTalkUpdateTime(String memberTalkId, Date updateTime); |
| | | void updateMemberTalkUpdateTime(Integer state,Integer doneCnt,String memberTalkId, Date updateTime); |
| | | |
| | | FebsResponse saveReport(ApiMemberTalkReportSavaDto dto); |
| | | } |
| | |
| | | |
| | | FebsResponse hotV2(ApiProductCategoryHotDto dto); |
| | | |
| | | FebsResponse categoryList(ApiProductCategoryPageDto dto); |
| | | FebsResponse categoryChildList(ApiProductCategoryPageDto dto); |
| | | |
| | | String getDefaultProductCategoryId(); |
| | | |
| | |
| | | package cc.mrbird.febs.ai.service.impl; |
| | | |
| | | import cc.mrbird.febs.ai.entity.*; |
| | | import cc.mrbird.febs.ai.enumerates.AiTypeEnum; |
| | | import cc.mrbird.febs.ai.mapper.AiMemberAnswerMapper; |
| | | import cc.mrbird.febs.ai.req.memberAnswer.*; |
| | | import cc.mrbird.febs.ai.res.memberAnswer.*; |
| | |
| | | .eq(AiMemberAnswer::getId,memberAnswerId) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public List<AiMemberAnswer> getListByCompanyId(String companyId) { |
| | | return aiMemberAnswerMapper.selectList( |
| | | Wrappers.lambdaQuery(AiMemberAnswer.class) |
| | | .eq(AiMemberAnswer::getCompanyId, companyId) |
| | | .eq(AiMemberAnswer::getState, AiTypeEnum.AI_MEMBER_ANSWER_STATE_DONE.getCode()) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public List<AiMemberAnswer> getListByCompanyIdAndMemberUuid(String companyId, String memberUuid) { |
| | | return aiMemberAnswerMapper.selectList( |
| | | Wrappers.lambdaQuery(AiMemberAnswer.class) |
| | | .eq(AiMemberAnswer::getCompanyId, companyId) |
| | | .eq(AiMemberAnswer::getMemberId, memberUuid) |
| | | .eq(AiMemberAnswer::getState, AiTypeEnum.AI_MEMBER_ANSWER_STATE_DONE.getCode()) |
| | | ); |
| | | } |
| | | } |
| | |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | @Slf4j |
| | | @Service |
| | |
| | | |
| | | AiMemberPoint aiMemberPoint = this.getById(productPointId); |
| | | if (ObjectUtil.isNull(aiMemberPoint)){ |
| | | aiMemberPoint = this.add(memberUuid, productPointId, companyId, totalTime); |
| | | this.add(memberUuid, productPointId, companyId, totalTime); |
| | | }else{ |
| | | Integer oldTotalTime = aiMemberPoint.getTotalTime(); |
| | | aiMemberPointMapper.update( |
| | |
| | | } |
| | | return new FebsResponse().success(); |
| | | } |
| | | |
| | | @Override |
| | | public List<AiMemberPoint> getListByCompanyId(String companyId) { |
| | | return aiMemberPointMapper.selectList( |
| | | Wrappers.lambdaQuery(AiMemberPoint.class) |
| | | .eq(AiMemberPoint::getCompanyId, companyId) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public List<AiMemberPoint> getListByCompanyIdAndMemberUuid(String companyId, String memberUuid) { |
| | | return aiMemberPointMapper.selectList( |
| | | Wrappers.lambdaQuery(AiMemberPoint.class) |
| | | .eq(AiMemberPoint::getCompanyId, companyId) |
| | | .eq(AiMemberPoint::getMemberId, memberUuid) |
| | | ); |
| | | } |
| | | } |
| | |
| | | package cc.mrbird.febs.ai.service.impl; |
| | | |
| | | import cc.mrbird.febs.ai.entity.AiMember; |
| | | import cc.mrbird.febs.ai.entity.AiMemberTalk; |
| | | import cc.mrbird.febs.ai.entity.*; |
| | | import cc.mrbird.febs.ai.mapper.AiMemberMapper; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberPageDto; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberPageVo; |
| | | import cc.mrbird.febs.ai.service.AiMemberService; |
| | | import cc.mrbird.febs.ai.service.AiMemberTalkService; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamPageDto; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamPracticeDto; |
| | | import cc.mrbird.febs.ai.req.member.ApiMemberTeamStudyDto; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberTeamPageVo; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberTeamPracticeVo; |
| | | import cc.mrbird.febs.ai.res.member.ApiMemberTeamStudyVo; |
| | | import cc.mrbird.febs.ai.res.productPoint.ApiProductPointListVo; |
| | | 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 cc.mrbird.febs.mall.entity.MallMember; |
| | | import cc.mrbird.febs.mall.mapper.MallMemberMapper; |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | private final AiMemberMapper aiMemberMapper; |
| | | private final MallMemberMapper mallMemberMapper; |
| | | private final AiMemberTalkService aiMemberTalkService; |
| | | private final AiMemberAnswerService aiMemberAnswerService; |
| | | private final AiMemberPointService aiMemberPointService; |
| | | private final AiProductService aiProductService; |
| | | private final AiProductPointService aiProductPointService; |
| | | @Override |
| | | public AiMember getById(String id) { |
| | | return aiMemberMapper.selectById( id); |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse myTeam(ApiMemberPageDto dto) { |
| | | List<ApiMemberPageVo> objects = new ArrayList<>(); |
| | | public FebsResponse myTeam(ApiMemberTeamPageDto dto) { |
| | | List<ApiMemberTeamPageVo> objects = new ArrayList<>(); |
| | | |
| | | String companyId = LoginUserUtil.getLoginUser().getCompanyId(); |
| | | String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); |
| | | Integer checkOrder = LoginUserUtil.getLoginUser().getCheckOrder(); |
| | | if (1 != checkOrder){ |
| | | throw new FebsException("非管理员,无权限查看"); |
| | | } |
| | | |
| | | // 创建分页对象,传入当前页和每页大小 |
| | | Page<AiMember> page = new Page<>(dto.getPageNow(), dto.getPageSize()); |
| | |
| | | Page<AiMember> pageListByQuery = aiMemberMapper.selectPage(page, queryWrapper); |
| | | List<AiMember> records = pageListByQuery.getRecords(); |
| | | if (CollUtil.isNotEmpty( records)){ |
| | | objects = buildMemberPages(companyId,records,objects); |
| | | objects = buildMemberPages(memberUuid,companyId,records,objects); |
| | | } |
| | | return new FebsResponse().success().data(objects); |
| | | } |
| | | |
| | | private List<ApiMemberPageVo> buildMemberPages(String companyId,List<AiMember> records,List<ApiMemberPageVo> objects) { |
| | | private List<ApiMemberTeamPageVo> buildMemberPages(String memberUuid, String companyId, List<AiMember> records, List<ApiMemberTeamPageVo> objects) { |
| | | /** |
| | | * 获取用户信息 |
| | | */ |
| | |
| | | Map<String, MallMember> mallMemberMap = mallMembers.stream().collect(Collectors.toMap(MallMember::getMemberUuid, mallMember -> mallMember)); |
| | | |
| | | /** |
| | | * 获取用户联系次数 |
| | | * 获取用户练习次数 |
| | | * ai陪练 |
| | | * ai答题 |
| | | */ |
| | | List<AiMemberTalk> aiMemberTalks = aiMemberTalkService.getListByCompanyId(companyId); |
| | | //Stream流操作aiMemberTalks,获取一个map<memberUuid,aiMemberTalk>的对象 |
| | | //stream流操作aiMemberTalks,获取一个Map<memberId,Integer>的对象,integer代表按照memberId分组的数量 |
| | | Map<String, Integer> memberIdToCntMapTalk = aiMemberTalks.stream() |
| | | .collect(Collectors.groupingBy( |
| | | AiMemberTalk::getMemberId, |
| | | Collectors.summingInt(t -> 1) |
| | | )); |
| | | |
| | | List<AiMemberAnswer> aiMemberAnswers = aiMemberAnswerService.getListByCompanyId(companyId); |
| | | //stream流操作aiMemberAnswers,获取一个Map<memberId,Integer>的对象,integer代表按照memberId分组的数量 |
| | | Map<String, Integer> memberIdToCntMapAnswer = aiMemberAnswers.stream() |
| | | .collect(Collectors.groupingBy( |
| | | AiMemberAnswer::getMemberId, |
| | | Collectors.summingInt(a -> 1) |
| | | )); |
| | | /** |
| | | * 用户学习总时长 |
| | | */ |
| | | List<AiMemberPoint> aiMemberPoints = aiMemberPointService.getListByCompanyId(companyId); |
| | | Map<String, Integer> memberStudyTimeMap = aiMemberPoints.stream().collect(Collectors.groupingBy( |
| | | AiMemberPoint::getMemberId, |
| | | Collectors.summingInt(AiMemberPoint::getTotalTime) |
| | | )); |
| | | |
| | | |
| | | for (AiMember aiMember : records){ |
| | | ApiMemberPageVo apiMemberPageVo = new ApiMemberPageVo(); |
| | | apiMemberPageVo.setMemberUuid(aiMember.getId()); |
| | | String aiMemberId = aiMember.getId(); |
| | | ApiMemberTeamPageVo apiMemberTeamPageVo = new ApiMemberTeamPageVo(); |
| | | apiMemberTeamPageVo.setType(0); |
| | | apiMemberTeamPageVo.setMemberUuid(aiMemberId); |
| | | if (memberUuid.equals(aiMemberId)){ |
| | | apiMemberTeamPageVo.setType(1); |
| | | } |
| | | |
| | | //判断mallMemberMap中是否存在该会员 |
| | | apiMemberPageVo.setMemberName(mallMemberMap.containsKey(aiMember.getId()) ? mallMemberMap.get(aiMember.getId()).getName() : ""); |
| | | apiMemberPageVo.setNickName(mallMemberMap.containsKey(aiMember.getId()) ? mallMemberMap.get(aiMember.getId()).getName() : ""); |
| | | apiMemberTeamPageVo.setNickName(mallMemberMap.containsKey(aiMemberId) ? mallMemberMap.get(aiMemberId).getName() : ""); |
| | | apiMemberTeamPageVo.setMemberName(mallMemberMap.containsKey(aiMemberId) ? mallMemberMap.get(aiMemberId).getName() : ""); |
| | | Integer practiceCnt = 0; |
| | | if (memberIdToCntMapTalk.containsKey(aiMemberId)){ |
| | | practiceCnt = memberIdToCntMapTalk.get(aiMemberId); |
| | | } |
| | | if (memberIdToCntMapAnswer.containsKey(aiMemberId)){ |
| | | practiceCnt = memberIdToCntMapAnswer.get(aiMemberId) + practiceCnt; |
| | | } |
| | | apiMemberTeamPageVo.setPracticeCnt(practiceCnt); |
| | | |
| | | objects.add(apiMemberPageVo); |
| | | Integer studyTime = 0; |
| | | if (memberStudyTimeMap.containsKey(aiMemberId)){ |
| | | studyTime = memberStudyTimeMap.get(aiMemberId); |
| | | } |
| | | apiMemberTeamPageVo.setStudyTime(DateUtil.secondToTime(studyTime)); |
| | | objects.add(apiMemberTeamPageVo); |
| | | } |
| | | return objects; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public FebsResponse practice(ApiMemberTeamPracticeDto dto) { |
| | | List<ApiMemberTeamPracticeVo> vos = new ArrayList<>(); |
| | | |
| | | String companyId = LoginUserUtil.getLoginUser().getCompanyId(); |
| | | String memberUuid = dto.getMemberUuid(); |
| | | |
| | | List<AiMemberTalk> aiMemberTalks = aiMemberTalkService.getListByCompanyIdAndMemberUuid(companyId, memberUuid); |
| | | Map<String, List<AiMemberTalk>> aiMemberTalkMap = new HashMap<>(); |
| | | if (CollUtil.isNotEmpty(aiMemberTalks)){ |
| | | //stream操作aiMemberTalks,返回一个根据productId分组的集合 |
| | | aiMemberTalkMap = aiMemberTalks.stream().collect(Collectors.groupingBy(AiMemberTalk::getProductId)); |
| | | } |
| | | |
| | | List<AiMemberAnswer> aiMemberAnswers = aiMemberAnswerService.getListByCompanyIdAndMemberUuid(companyId, memberUuid); |
| | | Map<String, List<AiMemberAnswer>> aiMemberAnswerMap = new HashMap<>(); |
| | | if (CollUtil.isNotEmpty(aiMemberAnswers)){ |
| | | aiMemberAnswerMap = aiMemberAnswers.stream().collect(Collectors.groupingBy(AiMemberAnswer::getProductId)); |
| | | } |
| | | |
| | | // 获取aiMemberTalkMap和aiMemberAnswerMap的全部的key,并且去重 |
| | | Set<String> productIds = new HashSet<>(); |
| | | if (aiMemberTalkMap != null) { |
| | | productIds.addAll(aiMemberTalkMap.keySet()); |
| | | } |
| | | if (aiMemberAnswerMap != null) { |
| | | productIds.addAll(aiMemberAnswerMap.keySet()); |
| | | } |
| | | if (CollUtil.isEmpty(productIds)){ |
| | | return new FebsResponse().success().data(vos); |
| | | } |
| | | |
| | | List<AiProduct> aiProducts = aiProductService.getProductListByQuery( |
| | | Wrappers.lambdaQuery(AiProduct.class) |
| | | .select(AiProduct::getId,AiProduct::getName, AiProduct::getTarget) |
| | | .in(AiProduct::getId, productIds) |
| | | ); |
| | | if (CollUtil.isEmpty(aiProducts)){ |
| | | return new FebsResponse().success().data(vos); |
| | | } |
| | | |
| | | for (AiProduct aiProduct : aiProducts){ |
| | | |
| | | String productId = aiProduct.getId(); |
| | | ApiMemberTeamPracticeVo vo = new ApiMemberTeamPracticeVo(); |
| | | vo.setName(aiProduct.getName()); |
| | | vo.setTarget(aiProduct.getTarget()); |
| | | |
| | | Integer answerCnt = 0; |
| | | if (aiMemberAnswerMap.containsKey(productId)){ |
| | | answerCnt = aiMemberAnswerMap.get(productId).size(); |
| | | } |
| | | vo.setAnswerCnt(answerCnt); |
| | | |
| | | Integer talkCnt = 0; |
| | | if (aiMemberTalkMap.containsKey(productId)){ |
| | | talkCnt = aiMemberTalkMap.get(productId).size(); |
| | | } |
| | | vo.setTalkCnt(talkCnt); |
| | | |
| | | vos.add( vo); |
| | | } |
| | | |
| | | |
| | | return new FebsResponse().success().data(vos); |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse study(ApiMemberTeamStudyDto dto) { |
| | | |
| | | List<ApiMemberTeamStudyVo> vos = new ArrayList<>(); |
| | | |
| | | String companyId = LoginUserUtil.getLoginUser().getCompanyId(); |
| | | String memberUuid = dto.getMemberUuid(); |
| | | |
| | | List<AiMemberPoint> aiMemberPoints = aiMemberPointService.getListByCompanyIdAndMemberUuid(companyId, memberUuid); |
| | | if (CollUtil.isEmpty(aiMemberPoints)){ |
| | | return new FebsResponse().success().data(vos); |
| | | } |
| | | Map<String, AiMemberPoint> aiMemberPointMap = new HashMap<>(); |
| | | if (CollUtil.isNotEmpty(aiMemberPoints)){ |
| | | aiMemberPoints.forEach(aiMemberPoint -> aiMemberPointMap.put(aiMemberPoint.getProductPointId(),aiMemberPoint)); |
| | | } |
| | | |
| | | //stream流操作aiMemberPoints,返回一个productPointId的set集合 |
| | | Set<String> productPointIdSet = aiMemberPoints.stream().map(AiMemberPoint::getProductPointId).collect(Collectors.toSet()); |
| | | |
| | | List<AiProductPoint> aiProductPoints = aiProductPointService.getBaseMapper().selectList( |
| | | Wrappers.lambdaQuery(AiProductPoint.class) |
| | | .select(AiProductPoint::getId,AiProductPoint::getTitle) |
| | | .in(AiProductPoint::getId, productPointIdSet) |
| | | ); |
| | | if (CollUtil.isEmpty(aiProductPoints)){ |
| | | return new FebsResponse().success().data(vos); |
| | | } |
| | | |
| | | for (AiProductPoint aiProductPoint : aiProductPoints){ |
| | | ApiMemberTeamStudyVo vo = new ApiMemberTeamStudyVo(); |
| | | vo.setTitle(aiProductPoint.getTitle()); |
| | | Integer totalTime = 0; |
| | | if (aiMemberPointMap.containsKey(aiProductPoint.getId())){ |
| | | totalTime = aiMemberPointMap.get(aiProductPoint.getId()).getTotalTime(); |
| | | } |
| | | vo.setTotalTime(DateUtil.secondToTime(totalTime)); |
| | | |
| | | vos.add(vo); |
| | | } |
| | | |
| | | return new FebsResponse().success().data(vos); |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public AiMemberTalkItem getByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery) { |
| | | public AiMemberTalkItem getOneByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery) { |
| | | return aiMemberTalkItemMapper.selectOne(memberTalkItemQuery); |
| | | } |
| | | |
| | | @Override |
| | | public List<AiMemberTalkItem> getListByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery) { |
| | | return aiMemberTalkItemMapper.selectList(memberTalkItemQuery); |
| | | } |
| | | |
| | | @Override |
| | | public IPage<ApiMemberTalkItemVo> historyPage(ApiMemberTalkItemPageDto dto) { |
| | | // 创建分页对象,传入当前页和每页大小 |
| | | Page<ApiMemberTalkItemVo> page = new Page<>(dto.getPageNow(), dto.getPageSize()); |
| | |
| | | query.last("limit 1"); |
| | | AiMemberTalk aiMemberTalk = this.getByQuery(query); |
| | | if (ObjectUtil.isNull(aiMemberTalk)){ |
| | | aiMemberTalk = this.add(memberUuid,companyId,productId,nowTime); |
| | | aiMemberTalk = this.add(memberUuid,companyId,productId,nowTime,5); |
| | | } |
| | | |
| | | List<AiMessage> aiMessageDtoList = aiMemberTalkItemService.getQuestionUpDownContext(aiMemberTalk.getId(),AiTypeEnum.QUESTION.getCode()); |
| | |
| | | queryWrapper.eq(AiMemberTalkItem::getType,AiTypeEnum.QUESTION_ANSWER.getCode()); |
| | | queryWrapper.orderByDesc(AiMemberTalkItem::getCreatedTime); |
| | | queryWrapper.last("limit 1"); |
| | | AiMemberTalkItem byQuery = aiMemberTalkItemService.getByQuery(queryWrapper); |
| | | AiMemberTalkItem byQuery = aiMemberTalkItemService.getOneByQuery(queryWrapper); |
| | | if (ObjectUtil.isNotNull(byQuery)){ |
| | | apiMemberTalkReloadVo.setContext(byQuery.getContext()); |
| | | apiMemberTalkReloadVo.setMemberTalkId(memberTalkId); |
| | |
| | | query.last("limit 1"); |
| | | AiMemberTalk aiMemberTalk = this.getByQuery(query); |
| | | if (ObjectUtil.isNull(aiMemberTalk)) { |
| | | aiMemberTalk = this.add(memberUuid,companyId, productId, nowTime); |
| | | aiMemberTalk = this.add(memberUuid,companyId, productId, nowTime,5); |
| | | } |
| | | try { |
| | | if (aiResponse.getCode().equals("200")) { |
| | |
| | | memberTalkItemQuery.eq(AiMemberTalkItem::getType,1); |
| | | memberTalkItemQuery.orderByDesc(AiMemberTalkItem::getCreatedTime); |
| | | memberTalkItemQuery.last("limit 1"); |
| | | AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getByQuery(memberTalkItemQuery); |
| | | AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getOneByQuery(memberTalkItemQuery); |
| | | aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),companyId,2,reqContext,new Date()); |
| | | |
| | | String format = StrUtil.format(ANSWER_FORMAT, aiMemberTalkItem.getContext(), reqContext); |
| | |
| | | return new FebsResponse().success().data(apiMemberTalkVo); |
| | | } |
| | | @Override |
| | | public AiMemberTalk add(String memberUuid,String companyId, String productId, Date nowTime) { |
| | | public AiMemberTalk add(String memberUuid,String companyId, String productId, Date nowTime,Integer questionCount) { |
| | | AiMemberTalk aiMemberTalk = new AiMemberTalk(); |
| | | aiMemberTalk.setId(UUID.getSimpleUUIDString()); |
| | | aiMemberTalk.setCompanyId(companyId); |
| | | aiMemberTalk.setCreatedTime(nowTime); |
| | | aiMemberTalk.setMemberId(memberUuid); |
| | | aiMemberTalk.setProductId(productId); |
| | | aiMemberTalk.setQuestionCnt(questionCount); |
| | | aiMemberTalk.setDoneCnt(0); |
| | | aiMemberTalk.setState(AiTypeEnum.AI_MEMBER_TALK_STATE_ING.getCode()); |
| | | aiMemberTalkMapper.insert(aiMemberTalk); |
| | | return aiMemberTalk; |
| | | } |
| | |
| | | return aiMemberTalkMapper.selectList( |
| | | Wrappers.lambdaQuery(AiMemberTalk.class) |
| | | .eq(AiMemberTalk::getCompanyId, companyId) |
| | | .eq(AiMemberTalk::getState, AiTypeEnum.AI_MEMBER_TALK_STATE_DONE.getCode()) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public List<AiMemberTalk> getListByCompanyIdAndMemberUuid(String companyId, String memberUuid) { |
| | | return aiMemberTalkMapper.selectList( |
| | | Wrappers.lambdaQuery(AiMemberTalk.class) |
| | | .eq(AiMemberTalk::getCompanyId, companyId) |
| | | .eq(AiMemberTalk::getMemberId, memberUuid) |
| | | .eq(AiMemberTalk::getState, AiTypeEnum.AI_MEMBER_TALK_STATE_DONE.getCode()) |
| | | ); |
| | | } |
| | | |
| | |
| | | import cc.mrbird.febs.ai.mapper.AiMemberTalkMapper; |
| | | import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto; |
| | | import cc.mrbird.febs.ai.req.memberTalkStream.*; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkMemberAnswerSavaVo; |
| | | 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.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.json.JSONUtil; |
| | |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import reactor.core.publisher.Flux; |
| | | |
| | | import java.util.ArrayList; |
| | |
| | | public class AiMemberTalkStreamServiceImpl extends ServiceImpl<AiMemberTalkMapper, AiMemberTalk> implements AiMemberTalkStreamService { |
| | | |
| | | private final AiMemberTalkMapper aiMemberTalkMapper; |
| | | private final AiProductService aiProductService; |
| | | private final AiProductRoleLinkService aiProductRoleLinkService; |
| | | private final AiProductRoleService aiProductRoleService; |
| | | private final AiMemberTalkService aiMemberTalkService; |
| | |
| | | |
| | | |
| | | @Override |
| | | @Transactional |
| | | public FebsResponse start(ApiMemberTalkStreamDto dto) { |
| | | |
| | | String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); |
| | |
| | | throw new FebsException("产品AI陪练不存在"); |
| | | } |
| | | |
| | | AiProduct aiProduct = aiProductService.getById(productId); |
| | | Integer questionCount = aiProduct.getQuestionCount(); |
| | | |
| | | String companyId = aiProductRoleLink.getCompanyId(); |
| | | |
| | | Date nowTime = new Date(); |
| | | LambdaQueryWrapper<AiMemberTalk> query = Wrappers.lambdaQuery(AiMemberTalk.class); |
| | | query.eq(AiMemberTalk::getMemberId,memberUuid); |
| | | query.eq(AiMemberTalk::getProductId,productId); |
| | | query.eq(AiMemberTalk::getState,AiTypeEnum.AI_MEMBER_TALK_STATE_ING.getCode()); |
| | | query.last("limit 1"); |
| | | AiMemberTalk aiMemberTalk = aiMemberTalkService.getByQuery(query); |
| | | if (ObjectUtil.isNull(aiMemberTalk)){ |
| | | aiMemberTalk = aiMemberTalkService.add(memberUuid,companyId,productId,nowTime); |
| | | aiMemberTalk = aiMemberTalkService.add(memberUuid,companyId,productId,nowTime,questionCount); |
| | | } |
| | | |
| | | ApiMemberTalkStreamVo apiMemberTalkVo = new ApiMemberTalkStreamVo(); |
| | |
| | | apiMemberTalkVo.setMemberTalkId(aiMemberTalk.getId()); |
| | | apiMemberTalkVo.setType(1); |
| | | apiMemberTalkVo.setContext(title); |
| | | apiMemberTalkVo.setQuestionCnt(aiMemberTalk.getQuestionCnt()); |
| | | apiMemberTalkVo.setDoneCnt(aiMemberTalk.getDoneCnt() + 1); |
| | | return new FebsResponse().success().data(apiMemberTalkVo); |
| | | } |
| | | |
| | |
| | | queryWrapper.eq(AiMemberTalkItem::getType,AiTypeEnum.QUESTION_ANSWER.getCode()); |
| | | queryWrapper.orderByDesc(AiMemberTalkItem::getCreatedTime); |
| | | queryWrapper.last("limit 1"); |
| | | AiMemberTalkItem byQuery = aiMemberTalkItemService.getByQuery(queryWrapper); |
| | | AiMemberTalkItem byQuery = aiMemberTalkItemService.getOneByQuery(queryWrapper); |
| | | if (ObjectUtil.isNotNull(byQuery)){ |
| | | apiMemberTalkReloadVo.setContext(byQuery.getContext()); |
| | | apiMemberTalkReloadVo.setMemberTalkId(memberTalkId); |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public FebsResponse saveMemberAnswer(ApiMemberTalkMemberAnswerSavaDto dto) { |
| | | String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); |
| | | String memberTalkId = dto.getMemberTalkId(); |
| | |
| | | if (ObjectUtil.isNull(aiMemberTalk)){ |
| | | throw new FebsException("对话不存在"); |
| | | } |
| | | this.updateMemberTalkUpdateTime(aiMemberTalk.getId(), new Date()); |
| | | int doneCnt = aiMemberTalk.getDoneCnt() + 1; |
| | | Integer state = aiMemberTalk.getState(); |
| | | Integer questionCnt = aiMemberTalk.getQuestionCnt(); |
| | | this.updateMemberTalkUpdateTime(state,doneCnt,aiMemberTalk.getId(), new Date()); |
| | | |
| | | String companyId = aiMemberTalk.getCompanyId(); |
| | | aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),companyId,2,content,new Date()); |
| | | return new FebsResponse().success(); |
| | | |
| | | ApiMemberTalkMemberAnswerSavaVo apiMemberTalkMemberAnswerSavaVo = new ApiMemberTalkMemberAnswerSavaVo(); |
| | | apiMemberTalkMemberAnswerSavaVo.setQuestionCnt(questionCnt); |
| | | apiMemberTalkMemberAnswerSavaVo.setDoneCnt(doneCnt); |
| | | return new FebsResponse().success().data(apiMemberTalkMemberAnswerSavaVo); |
| | | } |
| | | |
| | | @Override |
| | |
| | | memberTalkItemQuery.eq(AiMemberTalkItem::getType,1); |
| | | memberTalkItemQuery.orderByDesc(AiMemberTalkItem::getCreatedTime); |
| | | memberTalkItemQuery.last("limit 1"); |
| | | AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getByQuery(memberTalkItemQuery); |
| | | AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getOneByQuery(memberTalkItemQuery); |
| | | String question = aiMemberTalkItem.getContext(); |
| | | |
| | | String prompt = this.buildPrompt(question,reqContext,aiProductRole.getPromptHead(), aiProductRole.getPromptTemplate(), type); |
| | |
| | | String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); |
| | | Integer type = dto.getType(); |
| | | String memberTalkId = dto.getId(); |
| | | Integer state = ObjectUtil.defaultIfNull(dto.getState(),0); |
| | | AiMemberTalk aiMemberTalk = this.getById(memberTalkId); |
| | | if (ObjectUtil.isNull(aiMemberTalk)){ |
| | | throw new FebsException("对话不存在"); |
| | |
| | | memberTalkItemQuery.eq(AiMemberTalkItem::getType,1); |
| | | memberTalkItemQuery.orderByDesc(AiMemberTalkItem::getCreatedTime); |
| | | memberTalkItemQuery.last("limit 1"); |
| | | AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getByQuery(memberTalkItemQuery); |
| | | AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getOneByQuery(memberTalkItemQuery); |
| | | |
| | | String question = aiMemberTalkItem.getContext(); |
| | | String promptHead = aiProductRole.getPromptHead(); |
| | |
| | | llmStrategyDtoList.add(llmStrategyDto); |
| | | llmStrategyDto = this.buildLlmStrategyDtoList(String.valueOf(type), 4); |
| | | llmStrategyDtoList.add(llmStrategyDto); |
| | | |
| | | LlmStrategyDto llmStrategyDtoMessage = buildMessages(state, memberTalkId); |
| | | llmStrategyDtoList.add(llmStrategyDtoMessage); |
| | | String modelName = LlmStrategyEnum.getName(aiService.getSystemSetAiType()); |
| | | |
| | | return llmStrategyFactory.getCalculationStrategyMap().get(modelName).llmInvokeStreamingNoThink(llmStrategyDtoList); |
| | | } |
| | | |
| | | private LlmStrategyDto buildMessages(Integer state, String memberTalkId) { |
| | | |
| | | LlmStrategyDto message = new LlmStrategyDto(); |
| | | if (1!= state){ |
| | | return message; |
| | | } |
| | | LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery = Wrappers.lambdaQuery(AiMemberTalkItem.class); |
| | | memberTalkItemQuery.eq(AiMemberTalkItem::getMemberTalkId,memberTalkId); |
| | | memberTalkItemQuery.orderByAsc(AiMemberTalkItem::getCreatedTime); |
| | | List<AiMemberTalkItem> aiMemberTalkItems = aiMemberTalkItemService.getListByQuery(memberTalkItemQuery); |
| | | if (CollUtil.isEmpty(aiMemberTalkItems)){ |
| | | return message; |
| | | } |
| | | |
| | | List<LlmStrategyDto> messages = new ArrayList<>(); |
| | | for (AiMemberTalkItem aiMemberTalkItem : aiMemberTalkItems){ |
| | | LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); |
| | | if (aiMemberTalkItem.getType() == 1){ |
| | | llmStrategyDto.setRole(Role.ASSISTANT.getValue()); |
| | | } |
| | | if (aiMemberTalkItem.getType() == 2){ |
| | | llmStrategyDto.setRole(Role.USER.getValue()); |
| | | } |
| | | if (aiMemberTalkItem.getType() == 3){ |
| | | llmStrategyDto.setRole(Role.ASSISTANT.getValue()); |
| | | } |
| | | llmStrategyDto.setContent(aiMemberTalkItem.getContext()); |
| | | messages.add(llmStrategyDto); |
| | | } |
| | | |
| | | message.setRole(AiTypeEnum.MESSAGES.getName()); |
| | | message.setMessages(messages); |
| | | |
| | | return message; |
| | | } |
| | | |
| | | private String buildPrompt(String question,String answer,String promptHead, String promptTemplate,Integer type){ |
| | |
| | | throw new FebsException("对话不存在"); |
| | | } |
| | | |
| | | this.updateMemberTalkUpdateTime(aiMemberTalk.getId(), new Date()); |
| | | this.updateMemberTalkUpdateTime(aiMemberTalk.getState(),aiMemberTalk.getDoneCnt(),aiMemberTalk.getId(), new Date()); |
| | | |
| | | String companyId = aiMemberTalk.getCompanyId(); |
| | | Integer type = dto.getType(); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void updateMemberTalkUpdateTime(String memberTalkId, Date updateTime) { |
| | | public void updateMemberTalkUpdateTime(Integer state,Integer doneCnt,String memberTalkId, Date updateTime) { |
| | | aiMemberTalkMapper.update(null, |
| | | Wrappers.lambdaUpdate(AiMemberTalk.class) |
| | | .set(AiMemberTalk::getUpdatedTime,updateTime) |
| | | .eq(AiMemberTalk::getId,memberTalkId) |
| | | .set(AiMemberTalk::getUpdatedTime,updateTime) |
| | | .set(AiMemberTalk::getDoneCnt,doneCnt) |
| | | .set(AiMemberTalk::getState,state) |
| | | .eq(AiMemberTalk::getId,memberTalkId) |
| | | ); |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse saveReport(ApiMemberTalkReportSavaDto dto) { |
| | | String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); |
| | | String memberTalkId = dto.getMemberTalkId(); |
| | | String content = dto.getContent(); |
| | | |
| | | AiMemberTalk aiMemberTalk = this.getById(memberTalkId); |
| | | if (ObjectUtil.isNull(aiMemberTalk)){ |
| | | throw new FebsException("对话不存在"); |
| | | } |
| | | |
| | | this.updateMemberTalkUpdateTime(AiTypeEnum.AI_MEMBER_TALK_STATE_DONE.getCode(), aiMemberTalk.getDoneCnt(),aiMemberTalk.getId(), new Date()); |
| | | |
| | | Integer type = dto.getType(); |
| | | String contentByCode = AiTalkOutputEnum.HIGH_LIGHT.getCodeByType(type); |
| | | String analysis = aiMemberTalk.getAnalysis(); |
| | | HashMap<String, String> stringStringHashMap = new HashMap<>(); |
| | | if(StrUtil.isEmpty(analysis)){ |
| | | stringStringHashMap.put(contentByCode,content); |
| | | }else{ |
| | | stringStringHashMap = JSONUtil.toBean(analysis, HashMap.class); |
| | | stringStringHashMap.put(contentByCode,content); |
| | | } |
| | | |
| | | aiMemberTalkMapper.update( |
| | | null, |
| | | Wrappers.lambdaUpdate(AiMemberTalk.class) |
| | | .set(AiMemberTalk::getAnalysis,JSONUtil.toJsonStr(stringStringHashMap)) |
| | | .eq(AiMemberTalk::getId,aiMemberTalk.getId()) |
| | | ); |
| | | |
| | | return new FebsResponse().success(); |
| | | } |
| | | |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse categoryList(ApiProductCategoryPageDto dto) { |
| | | // 创建分页对象,传入当前页和每页大小 |
| | | Page<ApiProductCategoryVo> page = new Page<>(dto.getPageNow(), dto.getPageSize()); |
| | | Page<ApiProductCategoryVo> pageListByQuery = this.getPageListByQuery(page, dto); |
| | | return new FebsResponse().success().data(pageListByQuery); |
| | | public FebsResponse categoryChildList(ApiProductCategoryPageDto dto) { |
| | | List<ApiProductCategoryVo> vos = new ArrayList<>(); |
| | | |
| | | List<AiProductCategory> aiProductCategories = aiProductCategoryMapper.selectList( |
| | | Wrappers.lambdaQuery(AiProductCategory.class) |
| | | .eq(AiProductCategory::getParentId, dto.getParentId()) |
| | | .eq(AiProductCategory::getState, 1) |
| | | .orderByAsc(AiProductCategory::getSort) |
| | | ); |
| | | if (CollUtil.isNotEmpty(aiProductCategories)){ |
| | | for (AiProductCategory aiProductCategory : aiProductCategories) { |
| | | ApiProductCategoryVo vo = new ApiProductCategoryVo(); |
| | | vo.setId(aiProductCategory.getId()); |
| | | vo.setName(aiProductCategory.getName()); |
| | | vos.add(vo); |
| | | } |
| | | } |
| | | return new FebsResponse().success().data(vos); |
| | | } |
| | | |
| | | @Override |
| | |
| | | import cc.mrbird.febs.ai.res.ai.AiResponse; |
| | | import cc.mrbird.febs.ai.res.ai.RadarDataItem; |
| | | import cc.mrbird.febs.ai.res.ai.Report; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo; |
| | | import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVoOld; |
| | | import cc.mrbird.febs.ai.service.AiProductRoleService; |
| | | import cc.mrbird.febs.ai.service.AiService; |
| | | import cc.mrbird.febs.ai.service.AiTalkItemService; |
| | |
| | | } |
| | | |
| | | |
| | | ApiMemberTalkStreamVo apiMemberTalkStreamVo = new ApiMemberTalkStreamVo(); |
| | | ApiMemberTalkStreamVoOld apiMemberTalkStreamVoOld = new ApiMemberTalkStreamVoOld(); |
| | | // 判断是否触发深度思考,触发则打印模型输出的思维链内容 |
| | | ChatMessage message = choice.getMessage(); |
| | | if (message.getReasoningContent()!= null &&!message.getReasoningContent().isEmpty()) { |
| | | apiMemberTalkStreamVo.setReasoningContent(message.getReasoningContent()); |
| | | apiMemberTalkStreamVoOld.setReasoningContent(message.getReasoningContent()); |
| | | // System.out.print(message.getReasoningContent()); |
| | | } |
| | | |
| | | String content = message.getContent() == null ? "" : message.getContent().toString(); |
| | | apiMemberTalkStreamVo.setContent(content); |
| | | apiMemberTalkStreamVoOld.setContent(content); |
| | | System.out.print(content); |
| | | return new FebsResponse().success().data(apiMemberTalkStreamVo); |
| | | return new FebsResponse().success().data(apiMemberTalkStreamVoOld); |
| | | }) |
| | | .onErrorResume(throwable -> { |
| | | log.error("流式调用AI服务失败,问题输入: {}", question, throwable); |
| | |
| | | } |
| | | |
| | | ChatMessage message = choice.getMessage(); |
| | | ApiMemberTalkStreamVo apiMemberTalkStreamVo = new ApiMemberTalkStreamVo(); |
| | | ApiMemberTalkStreamVoOld apiMemberTalkStreamVoOld = new ApiMemberTalkStreamVoOld(); |
| | | |
| | | // 处理 reasoning content |
| | | String reasoningContent = message.getReasoningContent(); |
| | | if (StrUtil.isNotEmpty(reasoningContent)) { |
| | | apiMemberTalkStreamVo.setReasoningContent(reasoningContent); |
| | | apiMemberTalkStreamVoOld.setReasoningContent(reasoningContent); |
| | | log.debug("Reasoning Content: {}", reasoningContent); |
| | | } |
| | | |
| | |
| | | if (message.getContent() != null) { |
| | | content = message.getContent().toString(); |
| | | } |
| | | apiMemberTalkStreamVo.setContent(content); |
| | | apiMemberTalkStreamVoOld.setContent(content); |
| | | System.out.print(content); |
| | | log.debug("Content: {}", content); |
| | | |
| | | return new FebsResponse().success().data(apiMemberTalkStreamVo); |
| | | return new FebsResponse().success().data(apiMemberTalkStreamVoOld); |
| | | }) |
| | | .onErrorResume(throwable -> { |
| | | log.error("流式调用AI服务失败,问题输入: {}", question, throwable); |
| | |
| | | package cc.mrbird.febs.ai.strategy.Impl; |
| | | |
| | | import cc.mrbird.febs.ai.enumerates.AiTypeEnum; |
| | | import cc.mrbird.febs.ai.strategy.LlmStrategyService; |
| | | import cc.mrbird.febs.ai.strategy.enumerates.LlmApplicationAppIdEnum; |
| | | import cc.mrbird.febs.ai.strategy.enumerates.LlmStrategyContextEnum; |
| | |
| | | } |
| | | } |
| | | return bizParamsMap; |
| | | } |
| | | |
| | | private List<Message> getMessages(List<LlmStrategyDto> dto) { |
| | | List<Message> messages = new ArrayList<>(); |
| | | for (LlmStrategyDto dtoItem : dto){ |
| | | if (StrUtil.equals(AiTypeEnum.MESSAGES.getName(), dtoItem.getRole())){ |
| | | List<LlmStrategyDto> messages1 = dtoItem.getMessages(); |
| | | for (LlmStrategyDto dtoItem1 : messages1){ |
| | | messages.add(Message.builder() |
| | | .role(dtoItem1.getRole()) |
| | | .content(dtoItem1.getContent()) |
| | | .build()); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | return messages; |
| | | } |
| | | |
| | | private String getQuery(List<LlmStrategyDto> dto) { |
| | |
| | | throw new FebsException("百炼工作流初始化异常"); |
| | | } |
| | | HashMap prompt = getPrompt(dto); |
| | | List<Message> messages = getMessages(dto); |
| | | String query = getQuery(dto); |
| | | String appId = getAppId(dto); |
| | | if (prompt == null || prompt.size() == 0){ |
| | |
| | | .appId(appId) //替换为实际的应用 ID |
| | | .flowStreamMode(FlowStreamMode.MESSAGE_FORMAT) |
| | | .prompt(query) |
| | | .messages( messages) |
| | | .bizParams(JsonUtils.toJsonObject( prompt)) |
| | | .build(); |
| | | |
| | |
| | | |
| | | private String content; |
| | | |
| | | private List<LlmStrategyDto> messages; |
| | | |
| | | } |
| | |
| | | @ApiModelProperty(value = "是否是医生") |
| | | private Integer doctorState; |
| | | |
| | | @ApiModelProperty(value = "是否是核销员 0-否 1-是") |
| | | @ApiModelProperty(value = "是否能查看我的团队 0-否 1-是") |
| | | private Integer checkOrder; |
| | | |
| | | @ApiModelProperty(value = "是否是自提核销员 0-否 1-是") |