From 33a883b0d7edbf633dcf142d2e3c5bf2e334b121 Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Mon, 25 Aug 2025 16:10:09 +0800 Subject: [PATCH] feat(ai): 添加 AI 灵通相关功能 --- src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkVo.java | 19 +++ src/main/java/cc/mrbird/febs/ai/entity/AiTalk.java | 5 src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkItemServiceImpl.java | 28 ++++ src/main/java/cc/mrbird/febs/ai/controller/talk/ApiAiTalkController.java | 68 +++++++++++ src/main/java/cc/mrbird/febs/ai/mapper/AiTalkMapper.java | 7 + src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkPageDto.java | 26 ++++ src/main/resources/mapper/modules/AiTalkMapper.xml | 12 ++ src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkPageVo.java | 26 ++++ src/main/java/cc/mrbird/febs/ai/entity/AiTalkItem.java | 2 src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkServiceImpl.java | 83 +++++++++++++ src/main/java/cc/mrbird/febs/ai/service/AiTalkItemService.java | 11 + src/main/java/cc/mrbird/febs/ai/service/AiTalkService.java | 21 +++ src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkDto.java | 27 ++++ src/main/java/cc/mrbird/febs/ai/enumerates/AiTypeEnum.java | 7 + 14 files changed, 341 insertions(+), 1 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/ai/controller/talk/ApiAiTalkController.java b/src/main/java/cc/mrbird/febs/ai/controller/talk/ApiAiTalkController.java new file mode 100644 index 0000000..a8d47bd --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/controller/talk/ApiAiTalkController.java @@ -0,0 +1,68 @@ +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.ApiTalkDto; +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.talk.ApiTalkPageVo; +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 io.swagger.annotations.*; +import lombok.RequiredArgsConstructor; +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 + */ +@Slf4j +@Validated +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/api/ai/talk") +@Api(value = "ApiAiTalkController", tags = "AI-灵通") +public class ApiAiTalkController { + + private final AiTalkService aiTalkService; + + @ApiOperation(value = "用户AI问答", notes = "用户AI问答") + @ApiResponses({ + @ApiResponse(code = 200, message = "success", response = ApiTalkVo.class) + }) + @PostMapping(value = "/talkOpen") + public FebsResponse talkOpen(@RequestBody @Validated ApiTalkDto dto) { + + return aiTalkService.talkOpen(dto); + } + + @ApiOperation(value = "用户AI问答记录分页查询", notes = "用户AI问答记录分页查询") + @ApiResponses({ + @ApiResponse(code = 200, message = "success", response = ApiTalkPageVo.class) + }) + @PostMapping(value = "/talkList") + public FebsResponse talkList(@RequestBody @Validated ApiTalkPageDto dto) { + + return aiTalkService.talkList(dto); + } + + @ApiOperation("提问AI(流式)") + @ApiResponses({ + @ApiResponse(code = 200, message = "流式响应", response = ApiMemberTalkStreamVo.class), + }) + @GetMapping("/answer-stream") + public Flux<FebsResponse> answerStream(@RequestParam String question) { + + return aiTalkService.answerStream(question); + } +} diff --git a/src/main/java/cc/mrbird/febs/ai/entity/AiTalk.java b/src/main/java/cc/mrbird/febs/ai/entity/AiTalk.java index c804e18..b324bb2 100644 --- a/src/main/java/cc/mrbird/febs/ai/entity/AiTalk.java +++ b/src/main/java/cc/mrbird/febs/ai/entity/AiTalk.java @@ -19,6 +19,11 @@ private String companyId; /** + * 主要问题 + */ + private String question; + + /** * 用户ID (UUID) */ private String memberId; diff --git a/src/main/java/cc/mrbird/febs/ai/entity/AiTalkItem.java b/src/main/java/cc/mrbird/febs/ai/entity/AiTalkItem.java index 15e95d3..8526911 100644 --- a/src/main/java/cc/mrbird/febs/ai/entity/AiTalkItem.java +++ b/src/main/java/cc/mrbird/febs/ai/entity/AiTalkItem.java @@ -25,7 +25,7 @@ /** * 用户对话ID (UUID) */ - private String memberTalkId; + private String talkId; /** * 类型 1-用户提问 2-AI回答 diff --git a/src/main/java/cc/mrbird/febs/ai/enumerates/AiTypeEnum.java b/src/main/java/cc/mrbird/febs/ai/enumerates/AiTypeEnum.java index d66f6b0..18ae5fd 100644 --- a/src/main/java/cc/mrbird/febs/ai/enumerates/AiTypeEnum.java +++ b/src/main/java/cc/mrbird/febs/ai/enumerates/AiTypeEnum.java @@ -10,6 +10,13 @@ public enum AiTypeEnum { /** + * 1:用户提问 + * 2:AI回答 + */ + MEMBER_QUESTION(1,"用户提问"), + AI_ANSWER(2,"AI回答"), + + /** * 1:AI提问 * 2:用户回答 * 3:生成答案解析 diff --git a/src/main/java/cc/mrbird/febs/ai/mapper/AiTalkMapper.java b/src/main/java/cc/mrbird/febs/ai/mapper/AiTalkMapper.java index 9196dcf..c6d1872 100644 --- a/src/main/java/cc/mrbird/febs/ai/mapper/AiTalkMapper.java +++ b/src/main/java/cc/mrbird/febs/ai/mapper/AiTalkMapper.java @@ -1,7 +1,14 @@ package cc.mrbird.febs.ai.mapper; import cc.mrbird.febs.ai.entity.AiTalk; +import cc.mrbird.febs.ai.req.talk.ApiTalkPageDto; +import cc.mrbird.febs.ai.res.talk.ApiTalkPageVo; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; public interface AiTalkMapper extends BaseMapper<AiTalk> { + + Page<ApiTalkPageVo> getPageTalkListByQuery(Page<ApiTalkPageVo> page, @Param("record")ApiTalkPageDto dto); + } diff --git a/src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkDto.java b/src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkDto.java new file mode 100644 index 0000000..f5f200e --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkDto.java @@ -0,0 +1,27 @@ +package cc.mrbird.febs.ai.req.talk; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiTalkDto", description = "参数") +public class ApiTalkDto { + + @NotBlank(message = "内容不能为空") + @ApiModelProperty(value = "内容", example = "10") + private String context; + + @NotNull(message = "类型不能为空") + @ApiModelProperty(value = "类型 1-用户提问 2-AI回答", example = "10") + private Integer type; + + @ApiModelProperty(value = "会话ID", example = "10") + private String talkId; +} diff --git a/src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkPageDto.java b/src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkPageDto.java new file mode 100644 index 0000000..e47db90 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/req/talk/ApiTalkPageDto.java @@ -0,0 +1,26 @@ +package cc.mrbird.febs.ai.req.talk; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiTalkPageDto", description = "参数") +public class ApiTalkPageDto { + + @NotNull(message = "页码不能为空") + @ApiModelProperty(value = "页码", example = "1") + private Integer pageNow; + + @NotNull(message = "每页数量不能为空") + @ApiModelProperty(value = "每页数量", example = "10") + private Integer pageSize; + + @ApiModelProperty(hidden = true) + private String memberUuid; +} diff --git a/src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkPageVo.java b/src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkPageVo.java new file mode 100644 index 0000000..5526373 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkPageVo.java @@ -0,0 +1,26 @@ +package cc.mrbird.febs.ai.res.talk; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiTalkPageVo", description = "参数") +public class ApiTalkPageVo { + + @ApiModelProperty(value = "会话ID") + private String talkId; + + @ApiModelProperty(value = "题目") + private String question; + + @ApiModelProperty(value = "时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createdTime; +} diff --git a/src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkVo.java b/src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkVo.java new file mode 100644 index 0000000..22d61aa --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/res/talk/ApiTalkVo.java @@ -0,0 +1,19 @@ +package cc.mrbird.febs.ai.res.talk; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author Administrator + */ +@Data +@ApiModel(value = "ApiTalkVo", description = "参数") +public class ApiTalkVo { + + /** + * 视频号 id,以"sph"开头的id,可在视频号助手获取 + */ + @ApiModelProperty(value = "会话ID") + private String talkId; +} diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiTalkItemService.java b/src/main/java/cc/mrbird/febs/ai/service/AiTalkItemService.java new file mode 100644 index 0000000..229f2b6 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/service/AiTalkItemService.java @@ -0,0 +1,11 @@ +package cc.mrbird.febs.ai.service; + +import cc.mrbird.febs.ai.entity.AiTalkItem; +import cn.hutool.core.date.DateTime; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface AiTalkItemService extends IService<AiTalkItem> { + + void add(String id, int code, String context, String memberUuid, DateTime date); + +} diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiTalkService.java b/src/main/java/cc/mrbird/febs/ai/service/AiTalkService.java new file mode 100644 index 0000000..d89047d --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/service/AiTalkService.java @@ -0,0 +1,21 @@ +package cc.mrbird.febs.ai.service; + +import cc.mrbird.febs.ai.entity.AiTalk; +import cc.mrbird.febs.ai.req.talk.ApiTalkDto; +import cc.mrbird.febs.ai.req.talk.ApiTalkPageDto; +import cc.mrbird.febs.common.entity.FebsResponse; +import com.baomidou.mybatisplus.extension.service.IService; +import reactor.core.publisher.Flux; + +import java.util.Date; + +public interface AiTalkService extends IService<AiTalk> { + + FebsResponse talkOpen(ApiTalkDto dto); + + AiTalk add(String memberUuid, String question, Date date); + + Flux<FebsResponse> answerStream(String question); + + FebsResponse talkList(ApiTalkPageDto dto); +} diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkItemServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkItemServiceImpl.java new file mode 100644 index 0000000..7a4a121 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkItemServiceImpl.java @@ -0,0 +1,28 @@ +package cc.mrbird.febs.ai.service.impl; + +import cc.mrbird.febs.ai.entity.AiTalkItem; +import cc.mrbird.febs.ai.mapper.AiTalkItemMapper; +import cc.mrbird.febs.ai.service.AiTalkItemService; +import cc.mrbird.febs.ai.utils.UUID; +import cn.hutool.core.date.DateTime; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AiTalkItemServiceImpl extends ServiceImpl<AiTalkItemMapper, AiTalkItem> implements AiTalkItemService { + @Override + public void add(String id, int code, String context, String memberUuid, DateTime date) { + AiTalkItem aiTalkItem = new AiTalkItem(); + aiTalkItem.setId(UUID.getSimpleUUIDString()); + aiTalkItem.setMemberId(memberUuid); + aiTalkItem.setType(code); + aiTalkItem.setTalkId(id); + aiTalkItem.setCreatedTime(date); + aiTalkItem.setContext(context); + this.baseMapper.insert(aiTalkItem); + } +} diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkServiceImpl.java new file mode 100644 index 0000000..9410135 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiTalkServiceImpl.java @@ -0,0 +1,83 @@ +package cc.mrbird.febs.ai.service.impl; + +import cc.mrbird.febs.ai.entity.AiTalk; +import cc.mrbird.febs.ai.mapper.AiTalkMapper; +import cc.mrbird.febs.ai.req.talk.ApiTalkDto; +import cc.mrbird.febs.ai.req.talk.ApiTalkPageDto; +import cc.mrbird.febs.ai.res.memberAnswer.ApiMemberProductWorkVo; +import cc.mrbird.febs.ai.res.talk.ApiTalkPageVo; +import cc.mrbird.febs.ai.res.talk.ApiTalkVo; +import cc.mrbird.febs.ai.service.AiService; +import cc.mrbird.febs.ai.service.AiTalkItemService; +import cc.mrbird.febs.ai.service.AiTalkService; +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.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +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 reactor.core.publisher.Flux; + +import java.util.Date; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AiTalkServiceImpl extends ServiceImpl<AiTalkMapper, AiTalk> implements AiTalkService { + + private final AiTalkItemService aiTalkItemService; + private final AiService aiService; + @Override + public FebsResponse talkOpen(ApiTalkDto dto) { + String talkId = dto.getTalkId(); + String context = dto.getContext(); + Integer type = dto.getType(); + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + + AiTalk aiTalk = this.getById(talkId); + DateTime date = DateUtil.date(); + if (StrUtil.isEmpty(talkId)){ + aiTalk = this.add(memberUuid,context, date); + } + + aiTalkItemService.add(aiTalk.getId(), type, context, memberUuid, date); + + ApiTalkVo apiTalkVo = new ApiTalkVo(); + apiTalkVo.setTalkId(aiTalk.getId()); + return new FebsResponse().success().data(apiTalkVo); + } + + @Override + public AiTalk add(String memberUuid, String question, Date date) { + AiTalk aiTalk = new AiTalk(); + aiTalk.setId(UUID.getSimpleUUIDString()); + aiTalk.setQuestion(question); + aiTalk.setCreatedTime(date); + aiTalk.setMemberId(memberUuid); + this.baseMapper.insert(aiTalk); + return aiTalk; + } + + @Override + public Flux<FebsResponse> answerStream(String question) { + + return aiService.answerStream(question); + } + + @Override + public FebsResponse talkList(ApiTalkPageDto dto) { + String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); + dto.setMemberUuid(memberUuid); + // 创建分页对象,传入当前页和每页大小 + Page<ApiTalkPageVo> page = new Page<>(dto.getPageNow(), dto.getPageSize()); + Page<ApiTalkPageVo> pageListByQuery = this.getBaseMapper().getPageTalkListByQuery(page, dto); + + return new FebsResponse().success().data(pageListByQuery); + } + +} diff --git a/src/main/resources/mapper/modules/AiTalkMapper.xml b/src/main/resources/mapper/modules/AiTalkMapper.xml index 22f7f0e..d2bdb52 100644 --- a/src/main/resources/mapper/modules/AiTalkMapper.xml +++ b/src/main/resources/mapper/modules/AiTalkMapper.xml @@ -1,4 +1,16 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="cc.mrbird.febs.ai.mapper.AiTalkMapper"> + + + <select id="getPageTalkListByQuery" resultType="cc.mrbird.febs.ai.res.talk.ApiTalkPageVo"> + select + a.id as talkId, + a.question as question, + a.CREATED_TIME as createdTime + from ai_talk a + where a.member_id = #{record.memberUuid} + order by a.CREATED_TIME desc + </select> + </mapper> \ No newline at end of file -- Gitblit v1.9.1