Administrator
2025-09-02 fa296a6e4d2f7356f53b9a33d0b05d48522436bc
feat(ai): 优化 AI 对话功能

- 在 AiPromptJsonReq 中添加 question 字段
- 更新 AiTalkOutputEnum 的描述
- 新增 ApiMemberTalkMemberAnswerSavaDto 类用于保存用户回答- 在 ApiMemberTalkStreamController 中添加保存用户回答的接口
- 在 ApiMemberTalkStreamService 中添加保存用户回答的方法
- 优化 ApiMemberTalkStreamServiceImpl 中的保存用户回答逻辑
- 调整 buildPrompt 方法以支持问题和回答
5 files modified
1 files added
83 ■■■■ changed files
src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkStreamController.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/ai/enumerates/AiTalkOutputEnum.java 8 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/AiPromptJsonReq.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkMemberAnswerSavaDto.java 27 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/ai/service/ApiMemberTalkStreamService.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/ai/service/impl/ApiMemberTalkStreamServiceImpl.java 25 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkStreamController.java
@@ -1,10 +1,7 @@
package cc.mrbird.febs.ai.controller.memberTalk;
import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto;
import cc.mrbird.febs.ai.req.memberTalkStream.AiTalkAnswerStreamDto;
import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkAnswerSavaDto;
import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkReloadStreamDto;
import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkStreamDto;
import cc.mrbird.febs.ai.req.memberTalkStream.*;
import cc.mrbird.febs.ai.req.talk.AiTalkAnswerStream;
import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkItemVo;
import cc.mrbird.febs.ai.res.memberTalkStream.ApiMemberTalkReloadStreamVo;
@@ -67,6 +64,13 @@
        return apiMemberTalkStreamService.historyPage(dto);
    }
    @ApiOperation(value = "保存用户回答", notes = "保存答案")
    @PostMapping(value = "/saveMemberAnswer")
    public FebsResponse saveMemberAnswer(@RequestBody @Validated ApiMemberTalkMemberAnswerSavaDto dto) {
        return apiMemberTalkStreamService.saveMemberAnswer(dto);
    }
    @ApiOperation("回答(流式)")
    @ApiResponses({
            @ApiResponse(code = 200, message = "流式响应", response = cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkStreamVo.class),
@@ -79,7 +83,7 @@
        return apiMemberTalkStreamService.answer(dto);
    }
    @ApiOperation(value = "保存答案", notes = "保存答案")
    @ApiOperation(value = "保存AI回答", notes = "保存AI回答")
    @PostMapping(value = "/saveAnswer")
    public FebsResponse saveAnswer(@RequestBody @Validated ApiMemberTalkAnswerSavaDto dto) {
src/main/java/cc/mrbird/febs/ai/enumerates/AiTalkOutputEnum.java
@@ -9,13 +9,13 @@
@Getter
public enum AiTalkOutputEnum {
    KEY_KNOWLEDGE(4,"只输出知识点总结","KEY_KNOWLEDGE"),
    KEY_KNOWLEDGE(4,"根据问题和用户输入的内容,进行知识点总结。","KEY_KNOWLEDGE"),
    REFERENCE_ANSWER(3,"只输出参考答案","REFERENCE_ANSWER"),
    REFERENCE_ANSWER(3,"根据问题和用户输入的内容,输出参考答案。","REFERENCE_ANSWER"),
    SUGGESTION(2,"只输出建议","SUGGESTION"),
    SUGGESTION(2,"根据问题和用户输入的内容,给出建议并文字输出。","SUGGESTION"),
    HIGH_LIGHT(1,"只输出亮点","HIGH_LIGHT");
    HIGH_LIGHT(1,"根据问题和用户输入的内容,分析答案的亮点并文字输出。","HIGH_LIGHT");
    private final int type;
    private final String content;
src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/AiPromptJsonReq.java
@@ -12,6 +12,8 @@
    private String task;
    private String question;
    private String rule;
    private String outputFormat;
src/main/java/cc/mrbird/febs/ai/req/memberTalkStream/ApiMemberTalkMemberAnswerSavaDto.java
New file
@@ -0,0 +1,27 @@
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 = "ApiMemberTalkMemberAnswerSavaDto", description = "参数")
public class ApiMemberTalkMemberAnswerSavaDto {
    /**
     * 用户对话ID (UUID)
     */
    @NotBlank(message = "会话ID不能为空")
    @ApiModelProperty(value = "会话ID", example = "10")
    private String memberTalkId;
    @NotBlank(message = "回复内容不能为空")
    @ApiModelProperty(value = "回复内容", example = "10")
    private String content;
}
src/main/java/cc/mrbird/febs/ai/service/ApiMemberTalkStreamService.java
@@ -2,10 +2,7 @@
import cc.mrbird.febs.ai.entity.AiMemberTalk;
import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkItemPageDto;
import cc.mrbird.febs.ai.req.memberTalkStream.AiTalkAnswerStreamDto;
import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkAnswerSavaDto;
import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkReloadStreamDto;
import cc.mrbird.febs.ai.req.memberTalkStream.ApiMemberTalkStreamDto;
import cc.mrbird.febs.ai.req.memberTalkStream.*;
import cc.mrbird.febs.common.entity.FebsResponse;
import com.baomidou.mybatisplus.extension.service.IService;
import reactor.core.publisher.Flux;
@@ -22,6 +19,8 @@
    FebsResponse historyPage(ApiMemberTalkItemPageDto dto);
    FebsResponse saveMemberAnswer(ApiMemberTalkMemberAnswerSavaDto dto);
    Flux<FebsResponse> answer(AiTalkAnswerStreamDto dto);
    FebsResponse saveAnswer(ApiMemberTalkAnswerSavaDto dto);
src/main/java/cc/mrbird/febs/ai/service/impl/ApiMemberTalkStreamServiceImpl.java
@@ -119,6 +119,20 @@
    }
    @Override
    public FebsResponse saveMemberAnswer(ApiMemberTalkMemberAnswerSavaDto 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("对话不存在");
        }
        aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),2,content,new Date());
        return new FebsResponse().success();
    }
    @Override
    public Flux<FebsResponse> answer(AiTalkAnswerStreamDto dto) {
        String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid();
@@ -151,9 +165,7 @@
        memberTalkItemQuery.orderByDesc(AiMemberTalkItem::getCreatedTime);
        memberTalkItemQuery.last("limit 1");
        AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getByQuery(memberTalkItemQuery);
        aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),2,reqContext,new Date());
        String prompt = this.buildPrompt(aiProductRole.getPromptHead(), aiProductRole.getPromptTemplate(), type);
        String prompt = this.buildPrompt(aiMemberTalkItem.getContext(),reqContext,aiProductRole.getPromptHead(), aiProductRole.getPromptTemplate(), type);
        List<LlmStrategyDto> llmStrategyDtoList = new ArrayList<>();
@@ -166,10 +178,11 @@
        return llmStrategyFactory.getCalculationStrategyMap().get(modelName).llmInvokeStreamingNoThink(llmStrategyDtoList);
    }
    private String buildPrompt(String promptHead, String promptTemplate,Integer type){
    private String buildPrompt(String question,String answer,String promptHead, String promptTemplate,Integer type){
        AiPromptJsonReq aiPromptJsonReq = new AiPromptJsonReq();
        aiPromptJsonReq.setTask(promptHead);
        aiPromptJsonReq.setRule(promptTemplate);
        aiPromptJsonReq.setQuestion( question);
        aiPromptJsonReq.setTask( promptHead);
        aiPromptJsonReq.setRule( promptTemplate);
        String contentByCode = AiTalkOutputEnum.HIGH_LIGHT.getContentByType(type);
        aiPromptJsonReq.setOutputFormat(contentByCode);