From f7a1b1996d92d96004a7a1ab1bf289516732c7e4 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 05 Aug 2025 17:04:20 +0800
Subject: [PATCH] feat(ai): 添加 AI 用户陪练功能
---
src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java | 6
src/main/java/cc/mrbird/febs/mall/controller/HSController.java | 2
src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java | 18 +
src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java | 5
src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java | 16 +
src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java | 137 +++++++++++++++
src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java | 54 ++++++
src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java | 8
src/main/resources/application-test.yml | 8
src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java | 21 ++
src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java | 18 ++
src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java | 147 ++++++++++++++++
src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java | 26 ++
src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java | 35 +++
src/main/java/cc/mrbird/febs/ai/service/AiService.java | 14 +
15 files changed, 510 insertions(+), 5 deletions(-)
diff --git a/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java b/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java
new file mode 100644
index 0000000..66212da
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/controller/memberTalk/ApiMemberTalkController.java
@@ -0,0 +1,54 @@
+package cc.mrbird.febs.ai.controller.memberTalk;
+
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkAnswerDto;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkDto;
+import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkVo;
+import cc.mrbird.febs.ai.service.AiMemberTalkService;
+import cc.mrbird.febs.common.entity.FebsResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Validated
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(value = "/api/ai/memberTalk")
+@Api(value = "ApiMemberTalkController", tags = "AI-用户陪练")
+public class ApiMemberTalkController {
+
+ private final AiMemberTalkService aiMemberTalkService;
+
+
+ @ApiOperation(value = "开始陪练", notes = "开始陪练")
+ @ApiResponses({
+ @ApiResponse(code = 200, message = "success", response = ApiMemberTalkVo.class)
+ })
+ @PostMapping(value = "/start")
+ public FebsResponse start(@RequestBody @Validated ApiMemberTalkDto dto) {
+
+ return aiMemberTalkService.start(dto);
+ }
+
+
+ @ApiOperation(value = "回答", notes = "回答")
+ @ApiResponses({
+ @ApiResponse(code = 200, message = "success", response = ApiMemberTalkVo.class)
+ })
+ @PostMapping(value = "/answer")
+ public FebsResponse answer(@RequestBody @Validated ApiMemberTalkAnswerDto dto) {
+
+ return aiMemberTalkService.answer(dto);
+ }
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java
new file mode 100644
index 0000000..09da7ba
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkAnswerDto.java
@@ -0,0 +1,26 @@
+package cc.mrbird.febs.ai.req.memberTalk;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "ApiMemberTalkAnswerDto", description = "参数")
+public class ApiMemberTalkAnswerDto {
+
+
+ @NotBlank(message = "会话ID不能为空")
+ @ApiModelProperty(value = "会话ID", example = "10")
+ private String id;
+
+
+ @NotBlank(message = "回答不能为空")
+ @ApiModelProperty(value = "回答", example = "10")
+ private String reqContext;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java
new file mode 100644
index 0000000..761c995
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/req/memberTalk/ApiMemberTalkDto.java
@@ -0,0 +1,21 @@
+package cc.mrbird.febs.ai.req.memberTalk;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "ApiMemberTalkDto", description = "参数")
+public class ApiMemberTalkDto {
+
+
+ @NotBlank(message = "ID不能为空")
+ @ApiModelProperty(value = "产品ID", example = "10")
+ private String id;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java b/src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java
new file mode 100644
index 0000000..14cf671
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/res/ai/AiResponse.java
@@ -0,0 +1,16 @@
+package cc.mrbird.febs.ai.res.ai;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "AiResponse", description = "参数")
+public class AiResponse {
+
+ private String code;
+ private String description;
+ private String resContext;
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java b/src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java
new file mode 100644
index 0000000..a93dd7d
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/res/memberTalk/ApiMemberTalkVo.java
@@ -0,0 +1,35 @@
+package cc.mrbird.febs.ai.res.memberTalk;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "ApiMemberTalkVo", description = "参数")
+public class ApiMemberTalkVo {
+
+ /**
+ * 用户对话ID (UUID)
+ */
+
+ @ApiModelProperty(value = "会话ID")
+ private String memberTalkId;
+
+ /**
+ * 类型 1-AI提问 2-用户回答 3-AI分析结果
+ */
+
+ @ApiModelProperty(value = "类型 1-AI提问 2-用户回答 3-AI分析结果")
+ private Integer type;
+
+ /**
+ * 内容
+ */
+
+ @ApiModelProperty(value = "内容")
+ private String context;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java
index 9e23d1a..c3a151e 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkItemService.java
@@ -1,7 +1,10 @@
package cc.mrbird.febs.ai.service;
import cc.mrbird.febs.ai.entity.AiMemberTalkItem;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.Date;
import java.util.List;
/**
@@ -13,4 +16,7 @@
public interface AiMemberTalkItemService extends IService<AiMemberTalkItem> {
+ void add(String memberUuid, String id, int type, String resContext, Date createdTime);
+
+ AiMemberTalkItem getByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery);
}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java
index 4ad489a..1101850 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiMemberTalkService.java
@@ -1,8 +1,13 @@
package cc.mrbird.febs.ai.service;
import cc.mrbird.febs.ai.entity.AiMemberTalk;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkAnswerDto;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkDto;
+import cc.mrbird.febs.common.entity.FebsResponse;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
-import java.util.List;
+
+import java.util.Date;
/**
* AI用户对话训练记录 Service接口
@@ -13,4 +18,15 @@
public interface AiMemberTalkService extends IService<AiMemberTalk> {
+ AiMemberTalk getById(String id);
+
+ FebsResponse start(ApiMemberTalkDto dto);
+
+ AiMemberTalk getByQuery(LambdaQueryWrapper<AiMemberTalk> query);
+
+ void updateTimeUpdate(Date nowTime, String id);
+
+ FebsResponse answer(ApiMemberTalkAnswerDto dto);
+
+ AiMemberTalk add(String memberUuid, String productId, Date nowTime);
}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java b/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java
index 40a8602..e3cdaf0 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductRoleLinkService.java
@@ -1,10 +1,15 @@
package cc.mrbird.febs.ai.service;
+import cc.mrbird.febs.ai.entity.AiMemberTalk;
import cc.mrbird.febs.ai.entity.AiProductRoleLink;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author Administrator
*/
public interface AiProductRoleLinkService extends IService<AiProductRoleLink> {
+
+ AiProductRoleLink getByQuery(LambdaQueryWrapper<AiProductRoleLink> query);
+
}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiService.java b/src/main/java/cc/mrbird/febs/ai/service/AiService.java
new file mode 100644
index 0000000..116094d
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/service/AiService.java
@@ -0,0 +1,14 @@
+package cc.mrbird.febs.ai.service;
+
+import cc.mrbird.febs.ai.res.ai.AiResponse;
+
+/**
+ * @author Administrator
+ */
+public interface AiService {
+
+
+ AiResponse start(String productRoleId, String content);
+
+ AiResponse question(String promptTemplate,String linkId,String content);
+}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java
index fe9f1ab..c3dc6d5 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkItemServiceImpl.java
@@ -3,6 +3,7 @@
import cc.mrbird.febs.ai.entity.AiMemberTalkItem;
import cc.mrbird.febs.ai.mapper.AiMemberTalkItemMapper;
import cc.mrbird.febs.ai.service.AiMemberTalkItemService;
+import cc.mrbird.febs.ai.utils.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
@@ -10,6 +11,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.util.Date;
import java.util.List;
/**
@@ -26,4 +28,20 @@
private final AiMemberTalkItemMapper aiMemberTalkItemMapper;
+ @Override
+ public void add(String memberUuid, String id, int type, String resContext,Date createdTime) {
+ AiMemberTalkItem aiMemberTalkItem = new AiMemberTalkItem();
+ aiMemberTalkItem.setId(UUID.getSimpleUUIDString());
+ aiMemberTalkItem.setCreatedTime(createdTime);
+ aiMemberTalkItem.setMemberId(memberUuid);
+ aiMemberTalkItem.setMemberTalkId(id);
+ aiMemberTalkItem.setType(type);
+ aiMemberTalkItem.setContext(resContext);
+ aiMemberTalkItemMapper.insert(aiMemberTalkItem);
+ }
+
+ @Override
+ public AiMemberTalkItem getByQuery(LambdaQueryWrapper<AiMemberTalkItem> memberTalkItemQuery) {
+ return aiMemberTalkItemMapper.selectOne(memberTalkItemQuery);
+ }
}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java
index 2008dae..ddec2bb 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiMemberTalkServiceImpl.java
@@ -1,16 +1,30 @@
package cc.mrbird.febs.ai.service.impl;
import cc.mrbird.febs.ai.entity.AiMemberTalk;
+import cc.mrbird.febs.ai.entity.AiMemberTalkItem;
+import cc.mrbird.febs.ai.entity.AiProductRoleLink;
import cc.mrbird.febs.ai.mapper.AiMemberTalkMapper;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkAnswerDto;
+import cc.mrbird.febs.ai.req.memberTalk.ApiMemberTalkDto;
+import cc.mrbird.febs.ai.res.ai.AiResponse;
+import cc.mrbird.febs.ai.res.memberTalk.ApiMemberTalkVo;
+import cc.mrbird.febs.ai.service.AiMemberTalkItemService;
import cc.mrbird.febs.ai.service.AiMemberTalkService;
+import cc.mrbird.febs.ai.service.AiProductRoleLinkService;
+import cc.mrbird.febs.ai.service.AiService;
+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.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
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 org.springframework.transaction.annotation.Transactional;
-import java.util.List;
+import java.util.Date;
/**
* AI用户对话训练记录 Service实现类
@@ -24,6 +38,125 @@
public class AiMemberTalkServiceImpl extends ServiceImpl<AiMemberTalkMapper, AiMemberTalk> implements AiMemberTalkService {
private final AiMemberTalkMapper aiMemberTalkMapper;
+ private final AiProductRoleLinkService aiProductRoleLinkService;
+ private final AiMemberTalkItemService aiMemberTalkItemService;
+ private final AiService aiService;
+ @Override
+ public AiMemberTalk getById(String id) {
+ return aiMemberTalkMapper.selectById( id);
+ }
+
+ @Override
+ public FebsResponse start(ApiMemberTalkDto dto) {
+
+ String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid();
+ String productId = dto.getId();
+
+ LambdaQueryWrapper<AiProductRoleLink> productLinkQuery = Wrappers.lambdaQuery(AiProductRoleLink.class);
+ productLinkQuery.eq(AiProductRoleLink::getProductId,productId);
+ productLinkQuery.last("limit 1");
+ AiProductRoleLink aiProductRoleLink = aiProductRoleLinkService.getByQuery(productLinkQuery);
+ if(ObjectUtil.isNull(aiProductRoleLink)){
+ throw new RuntimeException("产品AI陪练不存在");
+ }
+
+ Date nowTime = new Date();
+ LambdaQueryWrapper<AiMemberTalk> query = Wrappers.lambdaQuery(AiMemberTalk.class);
+ query.eq(AiMemberTalk::getMemberId,memberUuid);
+ query.eq(AiMemberTalk::getProductId,productId);
+ query.last("limit 1");
+ AiMemberTalk aiMemberTalk = this.getByQuery(query);
+ if (ObjectUtil.isNull(aiMemberTalk)){
+ aiMemberTalk = this.add(memberUuid,productId,nowTime);
+ }
+
+ AiResponse aiResponse = aiService.start(aiProductRoleLink.getProductRoleId(),"开始出题");
+ if(aiResponse.getCode().equals("200")){
+ aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),1,aiResponse.getResContext(),nowTime);
+ this.updateTimeUpdate(nowTime,aiMemberTalk.getId());
+ }else{
+ throw new RuntimeException(aiResponse.getDescription());
+ }
+ ApiMemberTalkVo apiMemberTalkVo = new ApiMemberTalkVo();
+ apiMemberTalkVo.setMemberTalkId(aiMemberTalk.getId());
+ apiMemberTalkVo.setType(1);
+ apiMemberTalkVo.setContext(aiResponse.getResContext());
+
+ return new FebsResponse().success().data(apiMemberTalkVo);
+ }
+
+ @Override
+ public AiMemberTalk getByQuery(LambdaQueryWrapper<AiMemberTalk> query) {
+ return aiMemberTalkMapper.selectOne( query);
+ }
+
+ @Override
+ public void updateTimeUpdate(Date nowTime, String id) {
+ aiMemberTalkMapper.update(
+ null,
+ Wrappers.lambdaUpdate(AiMemberTalk.class)
+ .set(AiMemberTalk::getUpdatedTime,nowTime)
+ .eq(AiMemberTalk::getId,id));
+ }
+
+
+ public static final String ANSWER_FORMAT = "{}/n回答:{}/n请根据回答给出以下四个方面的总结,这个四个方面分别是亮点、建议、参考答案和核心知识点回顾。重点:四个方面的总结都是必须要有内容。";
+ @Override
+ public FebsResponse answer(ApiMemberTalkAnswerDto dto) {
+ String memberUuid = LoginUserUtil.getLoginUser().getMemberUuid();
+ String memberTalkId = dto.getId();
+ AiMemberTalk aiMemberTalk = this.getById(memberTalkId);
+ if (ObjectUtil.isNull(aiMemberTalk)){
+ throw new RuntimeException("产品AI陪练对话不存在");
+ }
+
+ LambdaQueryWrapper<AiProductRoleLink> 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 RuntimeException("产品AI陪练不存在");
+ }
+
+ String reqContext = dto.getReqContext();
+
+ LambdaQueryWrapper<AiMemberTalkItem> 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);
+ aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),2,reqContext,new Date());
+
+ String format = StrUtil.format(ANSWER_FORMAT, aiMemberTalkItem.getContext(), reqContext);
+ log.info("format:{}",format);
+ AiResponse aiResponse = aiService.start(aiProductRoleLink.getProductRoleId(), format);
+ if(aiResponse.getCode().equals("200")){
+ Date nowTime = new Date();
+ aiMemberTalkItemService.add(memberUuid,aiMemberTalk.getId(),3,aiResponse.getResContext(),nowTime);
+ this.updateTimeUpdate(nowTime,aiMemberTalk.getId());
+ }else{
+ throw new RuntimeException(aiResponse.getDescription());
+ }
+ ApiMemberTalkVo apiMemberTalkVo = new ApiMemberTalkVo();
+ apiMemberTalkVo.setMemberTalkId(aiMemberTalk.getId());
+ apiMemberTalkVo.setType(1);
+ apiMemberTalkVo.setContext(aiResponse.getResContext());
+
+ return new FebsResponse().success().data(apiMemberTalkVo);
+ }
+
+ @Override
+ public AiMemberTalk add(String memberUuid, String productId, Date nowTime) {
+ AiMemberTalk aiMemberTalk = new AiMemberTalk();
+ aiMemberTalk.setId(UUID.getSimpleUUIDString());
+ aiMemberTalk.setCreatedTime(nowTime);
+ aiMemberTalk.setMemberId(memberUuid);
+ aiMemberTalk.setProductId(productId);
+ aiMemberTalkMapper.insert(aiMemberTalk);
+ return aiMemberTalk;
+ }
}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java
index 680f6c0..0568bb7 100644
--- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductRoleLinkServiceImpl.java
@@ -1,8 +1,10 @@
package cc.mrbird.febs.ai.service.impl;
+import cc.mrbird.febs.ai.entity.AiMemberTalk;
import cc.mrbird.febs.ai.entity.AiProductRoleLink;
import cc.mrbird.febs.ai.mapper.AiProductRoleLinkMapper;
import cc.mrbird.febs.ai.service.AiProductRoleLinkService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -15,4 +17,10 @@
@Service
@RequiredArgsConstructor
public class AiProductRoleLinkServiceImpl extends ServiceImpl<AiProductRoleLinkMapper, AiProductRoleLink> implements AiProductRoleLinkService {
+
+ private final AiProductRoleLinkMapper aiProductRoleLinkMapper;
+ @Override
+ public AiProductRoleLink getByQuery(LambdaQueryWrapper<AiProductRoleLink> query) {
+ return aiProductRoleLinkMapper.selectOne( query);
+ }
}
diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java
new file mode 100644
index 0000000..0ef2ae9
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiServiceImpl.java
@@ -0,0 +1,147 @@
+package cc.mrbird.febs.ai.service.impl;
+
+import cc.mrbird.febs.ai.entity.AiProductRole;
+import cc.mrbird.febs.ai.res.ai.AiResponse;
+import cc.mrbird.febs.ai.service.AiProductRoleService;
+import cc.mrbird.febs.ai.service.AiService;
+import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionChoice;
+import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
+import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
+import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
+import com.volcengine.ark.runtime.service.ArkService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.ConnectionPool;
+import okhttp3.Dispatcher;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class AiServiceImpl implements AiService {
+
+ private static final String CODE_SUCCESS = "200";
+ private static final String CODE_NOT_FOUND = "201";
+ private static final String CODE_ERROR = "500";
+
+ private final AiProductRoleService aiProductRoleService;
+
+ @Value("${ai.service.ak}")
+ private String ak;
+
+ @Value("${ai.service.sk}")
+ private String sk;
+
+ @Value("${ai.service.base-url}")
+ private String baseUrl;
+
+ private ArkService service;
+
+ @PostConstruct
+ public void init() {
+ ConnectionPool connectionPool = new ConnectionPool(10, 30, TimeUnit.SECONDS);
+ Dispatcher dispatcher = new Dispatcher();
+ this.service = ArkService.builder()
+ .dispatcher(dispatcher)
+ .connectionPool(connectionPool)
+ .baseUrl(baseUrl)
+ .ak(ak)
+ .sk(sk)
+ .build();
+ }
+
+ @PreDestroy
+ public void destroy() {
+ if (service != null) {
+ service.shutdownExecutor();
+ }
+ }
+
+ @Override
+ public AiResponse start(String productRoleId, String content) {
+ if (!StringUtils.hasText(productRoleId)) {
+ log.warn("productRoleId 不能为空");
+ return buildErrorResponse(CODE_NOT_FOUND, "AI陪练不存在");
+ }
+
+ AiProductRole aiProductRole = aiProductRoleService.getById(productRoleId);
+ if (aiProductRole == null) {
+ log.warn("未找到对应的角色配置,productRoleId: {}", productRoleId);
+ return buildErrorResponse(CODE_NOT_FOUND, "AI陪练不存在");
+ }
+
+ String promptTemplate = aiProductRole.getPromptTemplate();
+ String linkId = aiProductRole.getLinkId();
+
+ if (!StringUtils.hasText(promptTemplate) || !StringUtils.hasText(linkId)) {
+ log.warn("角色配置不完整,promptTemplate 或 linkId 为空,productRoleId: {}", productRoleId);
+ return buildErrorResponse(CODE_ERROR, "角色配置不完整");
+ }
+
+ return question(promptTemplate, linkId, content);
+ }
+
+ @Override
+ public AiResponse question(String promptTemplate, String linkId, String content) {
+ if (!StringUtils.hasText(promptTemplate) || !StringUtils.hasText(linkId) || !StringUtils.hasText(content)) {
+ log.warn("请求参数不完整,promptTemplate: {}, linkId: {}, content: {}", promptTemplate, linkId, content);
+ return buildErrorResponse(CODE_ERROR, "请求参数不完整");
+ }
+
+ final List<ChatMessage> messages = new ArrayList<>();
+ final ChatMessage systemMessage = ChatMessage.builder().role(ChatMessageRole.SYSTEM).content(promptTemplate).build();
+ final ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER).content(content).build();
+ messages.add(systemMessage);
+ messages.add(userMessage);
+
+ ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
+ .model(linkId)
+ .messages(messages)
+ .temperature(1.0)
+ .topP(0.7)
+ .maxTokens(4096)
+ .frequencyPenalty(0.0)
+ .build();
+
+ try {
+ List<ChatCompletionChoice> choices = service.createChatCompletion(chatCompletionRequest).getChoices();
+ String result = choices.stream()
+ .map(choice -> choice.getMessage().getContent())
+ .filter(contentObj -> contentObj != null)
+ .map(Object::toString)
+ .collect(Collectors.joining());
+
+ return buildSuccessResponse(result);
+ } catch (Exception e) {
+ log.error("调用AI服务失败,modelId: {}, content: {}", linkId, content, e);
+ return buildErrorResponse(CODE_ERROR, "AI服务调用失败");
+ }
+ }
+
+ private AiResponse buildErrorResponse(String code, String description) {
+ AiResponse response = new AiResponse();
+ response.setCode(code);
+ response.setDescription(description);
+ return response;
+ }
+
+ private AiResponse buildSuccessResponse(String result) {
+ AiResponse response = new AiResponse();
+ response.setCode(CODE_SUCCESS);
+ response.setDescription("成功");
+ response.setResContext(result);
+ return response;
+ }
+}
diff --git a/src/main/java/cc/mrbird/febs/mall/controller/HSController.java b/src/main/java/cc/mrbird/febs/mall/controller/HSController.java
index 638717a..95235d0 100644
--- a/src/main/java/cc/mrbird/febs/mall/controller/HSController.java
+++ b/src/main/java/cc/mrbird/febs/mall/controller/HSController.java
@@ -18,7 +18,7 @@
// 从环境变量中获取您的Key鉴权。此为默认方式,您可根据需要进行修改
private static String ak = "AKLTZTQxZjMyZTUxMWJmNDEyNDkzNWExOGQ3ODllNzhhNmQ";
private static String sk = "TmpFeE1qZ3haREExTW1JeE5HRTBZVGc1WlRRNVlqWXpORGd5TWpsak5HWQ==";
- private static String ep_id = "ep-20250728114932-429wg";
+ private static String ep_id = "ep-20250805124033-lhxbf";
// 此为默认路径,您可根据业务所在地域进行配置
static String baseUrl = "https://ark.cn-beijing.volces.com/api/v3";
static ConnectionPool connectionPool = new ConnectionPool(5, 1, TimeUnit.SECONDS);
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
index 0d6fbb2..7fb08b0 100644
--- a/src/main/resources/application-test.yml
+++ b/src/main/resources/application-test.yml
@@ -89,4 +89,10 @@
path: /mnt/sdc/webresource/file/
system:
- job: false
\ No newline at end of file
+ job: false
+
+ai:
+ service:
+ ak: AKLTZTQxZjMyZTUxMWJmNDEyNDkzNWExOGQ3ODllNzhhNmQ
+ sk: TmpFeE1qZ3haREExTW1JeE5HRTBZVGc1WlRRNVlqWXpORGd5TWpsak5HWQ==
+ base-url: https://ark.cn-beijing.volces.com/api/v3
\ No newline at end of file
--
Gitblit v1.9.1