package cc.mrbird.febs.ai.service.impl; import cc.mrbird.febs.ai.entity.*; import cc.mrbird.febs.ai.enumerates.AiTalkOutputEnum; 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.*; 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.ai.strategy.LlmStrategyFactory; import cc.mrbird.febs.ai.strategy.enumerates.LlmStrategyEnum; import cc.mrbird.febs.ai.strategy.param.LlmStrategyDto; 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 cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.alibaba.dashscope.common.Role; 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 reactor.core.publisher.Flux; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; /** * AI用户对话训练记录 Service实现类 * * @author yourname * @date 2025-07-29 */ @Slf4j @Service @RequiredArgsConstructor public class ApiMemberTalkStreamServiceImpl extends ServiceImpl implements ApiMemberTalkStreamService { private final AiMemberTalkMapper aiMemberTalkMapper; private final AiProductRoleLinkService aiProductRoleLinkService; private final AiProductRoleService aiProductRoleService; private final AiMemberTalkService aiMemberTalkService; private final AiMemberTalkItemService aiMemberTalkItemService; private final AiProductQuestionService aiProductQuestionService; private final LlmStrategyFactory llmStrategyFactory; private final AiService aiService; @Override public FebsResponse start(ApiMemberTalkStreamDto dto) { String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); String productId = dto.getId(); LambdaQueryWrapper 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陪练不存在"); } String companyId = aiProductRoleLink.getCompanyId(); Date nowTime = new Date(); LambdaQueryWrapper 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,companyId,productId,nowTime); } ApiMemberTalkStreamVo apiMemberTalkVo = new ApiMemberTalkStreamVo(); String title = "加载时间过程,请重试!"; AiProductQuestion question = aiProductQuestionService.createQuestion(productId); if (ObjectUtil.isNotNull(question)){ title = question.getTitle(); AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.add(memberUuid, aiMemberTalk.getId(),companyId, 1, title, nowTime); apiMemberTalkVo.setMemberTalkItemId(aiMemberTalkItem.getId()); aiMemberTalkService.updateTimeUpdate(nowTime,aiMemberTalk.getId()); } 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 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)); } @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("对话不存在"); } this.updateMemberTalkUpdateTime(aiMemberTalk.getId(), new Date()); String companyId = aiMemberTalk.getCompanyId(); aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),companyId,2,content,new Date()); return new FebsResponse().success(); } @Override public Flux answer(AiTalkAnswerStreamDto dto) { String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); Integer type = dto.getType(); String memberTalkId = dto.getId(); AiMemberTalk aiMemberTalk = this.getById(memberTalkId); if (ObjectUtil.isNull(aiMemberTalk)){ throw new FebsException("对话不存在"); } LambdaQueryWrapper productLinkQuery = Wrappers.lambdaQuery(AiProductRoleLink.class); productLinkQuery.eq(AiProductRoleLink::getProductId,aiMemberTalk.getProductId()); productLinkQuery.last("limit 1"); AiProductRoleLink aiProductRoleLink = aiProductRoleLinkService.getByQuery(productLinkQuery); if(ObjectUtil.isNull(aiProductRoleLink)){ throw new FebsException("产品没有关联AI陪练"); } String productRoleId = aiProductRoleLink.getProductRoleId(); AiProductRole aiProductRole = aiProductRoleService.getById(productRoleId); if (ObjectUtil.isNull(aiProductRole)){ throw new FebsException("产品AI陪练不存在"); } String reqContext = dto.getReqContext(); LambdaQueryWrapper memberTalkItemQuery = Wrappers.lambdaQuery(AiMemberTalkItem.class); memberTalkItemQuery.eq(AiMemberTalkItem::getMemberId,memberUuid); memberTalkItemQuery.eq(AiMemberTalkItem::getMemberTalkId,memberTalkId); memberTalkItemQuery.eq(AiMemberTalkItem::getType,1); memberTalkItemQuery.orderByDesc(AiMemberTalkItem::getCreatedTime); memberTalkItemQuery.last("limit 1"); AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getByQuery(memberTalkItemQuery); String question = aiMemberTalkItem.getContext(); String prompt = this.buildPrompt(question,reqContext,aiProductRole.getPromptHead(), aiProductRole.getPromptTemplate(), type); List llmStrategyDtoList = new ArrayList<>(); LlmStrategyDto llmStrategyDto = this.buildLlmStrategyDtoList(prompt, 1); llmStrategyDtoList.add(llmStrategyDto); llmStrategyDto = this.buildLlmStrategyDtoList(question, 3); llmStrategyDtoList.add(llmStrategyDto); llmStrategyDto = this.buildLlmStrategyDtoList(reqContext, 2); llmStrategyDtoList.add(llmStrategyDto); String modelName = LlmStrategyEnum.getName(aiService.getSystemSetAiType()); return llmStrategyFactory.getCalculationStrategyMap().get(modelName).llmInvokeStreamingNoThink(llmStrategyDtoList); } @Override public Flux answerV2(AiTalkAnswerStreamDto dto) { String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid(); Integer type = dto.getType(); String memberTalkId = dto.getId(); AiMemberTalk aiMemberTalk = this.getById(memberTalkId); if (ObjectUtil.isNull(aiMemberTalk)){ throw new FebsException("对话不存在"); } LambdaQueryWrapper productLinkQuery = Wrappers.lambdaQuery(AiProductRoleLink.class); productLinkQuery.eq(AiProductRoleLink::getProductId,aiMemberTalk.getProductId()); productLinkQuery.last("limit 1"); AiProductRoleLink aiProductRoleLink = aiProductRoleLinkService.getByQuery(productLinkQuery); if(ObjectUtil.isNull(aiProductRoleLink)){ throw new FebsException("产品没有关联AI陪练"); } String productRoleId = aiProductRoleLink.getProductRoleId(); AiProductRole aiProductRole = aiProductRoleService.getById(productRoleId); if (ObjectUtil.isNull(aiProductRole)){ throw new FebsException("产品AI陪练不存在"); } LambdaQueryWrapper memberTalkItemQuery = Wrappers.lambdaQuery(AiMemberTalkItem.class); memberTalkItemQuery.eq(AiMemberTalkItem::getMemberId,memberUuid); memberTalkItemQuery.eq(AiMemberTalkItem::getMemberTalkId,memberTalkId); memberTalkItemQuery.eq(AiMemberTalkItem::getType,1); memberTalkItemQuery.orderByDesc(AiMemberTalkItem::getCreatedTime); memberTalkItemQuery.last("limit 1"); AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getByQuery(memberTalkItemQuery); String question = aiMemberTalkItem.getContext(); String promptHead = aiProductRole.getPromptHead(); String answer = dto.getReqContext(); List llmStrategyDtoList = new ArrayList<>(); LlmStrategyDto llmStrategyDto = this.buildLlmStrategyDtoList(promptHead, 1); llmStrategyDtoList.add(llmStrategyDto); llmStrategyDto = this.buildLlmStrategyDtoList(question, 3); llmStrategyDtoList.add(llmStrategyDto); llmStrategyDto = this.buildLlmStrategyDtoList(answer, 2); llmStrategyDtoList.add(llmStrategyDto); llmStrategyDto = this.buildLlmStrategyDtoList(String.valueOf(type), 4); llmStrategyDtoList.add(llmStrategyDto); String modelName = LlmStrategyEnum.getName(aiService.getSystemSetAiType()); return llmStrategyFactory.getCalculationStrategyMap().get(modelName).llmInvokeStreamingNoThink(llmStrategyDtoList); } private String buildPrompt(String question,String answer,String promptHead, String promptTemplate,Integer type){ AiPromptJsonReq aiPromptJsonReq = new AiPromptJsonReq(); // aiPromptJsonReq.setQuestion( question); aiPromptJsonReq.setTask( promptHead); aiPromptJsonReq.setRule( promptTemplate); String contentByCode = AiTalkOutputEnum.HIGH_LIGHT.getContentByType(type); aiPromptJsonReq.setOutputFormat(contentByCode); return JSONUtil.toJsonStr(aiPromptJsonReq); } private LlmStrategyDto buildLlmStrategyDtoList(String Str, Integer type){ LlmStrategyDto llmStrategyDto = new LlmStrategyDto(); if (type == 1){ llmStrategyDto.setRole(Role.SYSTEM.getValue()); } if (type == 2){ llmStrategyDto.setRole(Role.USER.getValue()); } if (type == 3){ llmStrategyDto.setRole(Role.ASSISTANT.getValue()); } if (type == 4){ llmStrategyDto.setRole(Role.TOOL.getValue()); } llmStrategyDto.setContent(Str); return llmStrategyDto; } @Override public FebsResponse saveAnswer(ApiMemberTalkAnswerSavaDto 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(aiMemberTalk.getId(), new Date()); String companyId = aiMemberTalk.getCompanyId(); Integer type = dto.getType(); String memberTalkItemId; String contentByCode = AiTalkOutputEnum.HIGH_LIGHT.getCodeByType(type); if(StrUtil.isEmpty(dto.getMemberTalkItemId())){ HashMap stringStringHashMap = new HashMap<>(); stringStringHashMap.put(contentByCode,content); AiMemberTalkItem add = aiMemberTalkItemService.add(memberUuid, memberTalkId,companyId, 3, JSONUtil.toJsonStr(stringStringHashMap), new Date()); memberTalkItemId = add.getId(); }else{ memberTalkItemId = dto.getMemberTalkItemId(); AiMemberTalkItem aiMemberTalkItem = aiMemberTalkItemService.getById(memberTalkItemId); String context = aiMemberTalkItem.getContext(); HashMap stringStringHashMap = JSONUtil.toBean(context, HashMap.class); stringStringHashMap.put(contentByCode,content); aiMemberTalkItemService.update(null, Wrappers.lambdaUpdate(AiMemberTalkItem.class) .set(AiMemberTalkItem::getContext,JSONUtil.toJsonStr(stringStringHashMap)) .set(AiMemberTalkItem::getUpdatedTime,new Date()) .set(AiMemberTalkItem::getRevision,aiMemberTalkItem.getRevision()+1) .eq(AiMemberTalkItem::getId,memberTalkItemId) ); } HashMap stringStringHashMap = new HashMap<>(); stringStringHashMap.put("memberTalkItemId",memberTalkItemId); return new FebsResponse().success().data(stringStringHashMap); } @Override public void updateMemberTalkUpdateTime(String memberTalkId, Date updateTime) { aiMemberTalkMapper.update(null, Wrappers.lambdaUpdate(AiMemberTalk.class) .set(AiMemberTalk::getUpdatedTime,updateTime) .eq(AiMemberTalk::getId,memberTalkId) ); } }