feat: 优化会话管理查询逻辑

This commit is contained in:
ageer
2025-05-16 23:52:43 +08:00
parent 096fc11313
commit 158a0190b5
5 changed files with 38 additions and 63 deletions

View File

@@ -29,13 +29,11 @@ public class ChatSessionBo extends BaseEntity {
/** /**
* 用户id * 用户id
*/ */
@NotNull(message = "用户id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long userId; private Long userId;
/** /**
* 会话标题 * 会话标题
*/ */
@NotBlank(message = "会话标题不能为空", groups = { AddGroup.class, EditGroup.class })
private String sessionTitle; private String sessionTitle;
/** /**
@@ -47,7 +45,6 @@ public class ChatSessionBo extends BaseEntity {
/** /**
* 备注 * 备注
*/ */
@NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remark; private String remark;

View File

@@ -2,6 +2,7 @@ package org.ruoyi.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils; import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.core.page.TableDataInfo; import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.core.page.PageQuery; import org.ruoyi.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -45,6 +46,10 @@ public class ChatMessageServiceImpl implements IChatMessageService {
*/ */
@Override @Override
public TableDataInfo<ChatMessageVo> queryPageList(ChatMessageBo bo, PageQuery pageQuery) { public TableDataInfo<ChatMessageVo> queryPageList(ChatMessageBo bo, PageQuery pageQuery) {
if(!LoginHelper.isLogin()){
return TableDataInfo.build();
}
bo.setUserId(LoginHelper.getUserId());
LambdaQueryWrapper<ChatMessage> lqw = buildQueryWrapper(bo); LambdaQueryWrapper<ChatMessage> lqw = buildQueryWrapper(bo);
Page<ChatMessageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); Page<ChatMessageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result); return TableDataInfo.build(result);
@@ -64,9 +69,8 @@ public class ChatMessageServiceImpl implements IChatMessageService {
LambdaQueryWrapper<ChatMessage> lqw = Wrappers.lambdaQuery(); LambdaQueryWrapper<ChatMessage> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getUserId() != null, ChatMessage::getUserId, bo.getUserId()); lqw.eq(bo.getUserId() != null, ChatMessage::getUserId, bo.getUserId());
lqw.eq(StringUtils.isNotBlank(bo.getContent()), ChatMessage::getContent, bo.getContent()); lqw.eq(StringUtils.isNotBlank(bo.getContent()), ChatMessage::getContent, bo.getContent());
lqw.eq(StringUtils.isNotBlank(bo.getRole()), ChatMessage::getRole, bo.getRole()); lqw.eq(bo.getSessionId() != null, ChatMessage::getSessionId, bo.getSessionId());
lqw.eq(bo.getDeductCost() != null, ChatMessage::getDeductCost, bo.getDeductCost()); lqw.like(StringUtils.isNotBlank(bo.getRole()), ChatMessage::getRole, bo.getRole());
lqw.eq(bo.getTotalTokens() != null, ChatMessage::getTotalTokens, bo.getTotalTokens());
lqw.like(StringUtils.isNotBlank(bo.getModelName()), ChatMessage::getModelName, bo.getModelName()); lqw.like(StringUtils.isNotBlank(bo.getModelName()), ChatMessage::getModelName, bo.getModelName());
return lqw; return lqw;
} }

View File

@@ -8,6 +8,7 @@ import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import org.ruoyi.common.excel.utils.ExcelUtil; import org.ruoyi.common.excel.utils.ExcelUtil;
import org.ruoyi.common.idempotent.annotation.RepeatSubmit; import org.ruoyi.common.idempotent.annotation.RepeatSubmit;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.core.page.TableDataInfo; import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.bo.ChatSessionBo;
import org.ruoyi.domain.vo.ChatSessionVo; import org.ruoyi.domain.vo.ChatSessionVo;
@@ -42,6 +43,12 @@ public class ChatSessionController extends BaseController {
@SaCheckPermission("system:session:list") @SaCheckPermission("system:session:list")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo<ChatSessionVo> list(ChatSessionBo bo, PageQuery pageQuery) { public TableDataInfo<ChatSessionVo> list(ChatSessionBo bo, PageQuery pageQuery) {
if(!LoginHelper.isLogin()){
// 如果用户没有登录,返回空会话列表
return TableDataInfo.build();
}
// 默认查询当前用户会话
bo.setUserId(LoginHelper.getUserId());
return chatSessionService.queryPageList(bo, pageQuery); return chatSessionService.queryPageList(bo, pageQuery);
} }

View File

@@ -1,19 +1,14 @@
package org.ruoyi.chat.service.chat.impl; package org.ruoyi.chat.service.chat.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.protobuf.ServiceException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import org.ruoyi.chat.enums.ChatModeType;
import org.ruoyi.chat.factory.ChatServiceFactory; import org.ruoyi.chat.factory.ChatServiceFactory;
import org.ruoyi.chat.service.chat.IChatCostService; import org.ruoyi.chat.service.chat.IChatCostService;
import org.ruoyi.chat.service.chat.IChatService; import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.chat.service.chat.ISseService; import org.ruoyi.chat.service.chat.ISseService;
import org.ruoyi.chat.util.IpUtil;
import org.ruoyi.chat.util.SSEUtil; import org.ruoyi.chat.util.SSEUtil;
import org.ruoyi.common.chat.config.LocalCache; import org.ruoyi.common.chat.config.LocalCache;
import org.ruoyi.common.chat.entity.Tts.TextToSpeech; import org.ruoyi.common.chat.entity.Tts.TextToSpeech;
@@ -26,15 +21,14 @@ import org.ruoyi.common.core.utils.DateUtils;
import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.core.utils.file.FileUtils; import org.ruoyi.common.core.utils.file.FileUtils;
import org.ruoyi.common.core.utils.file.MimeTypeUtils; import org.ruoyi.common.core.utils.file.MimeTypeUtils;
import org.ruoyi.common.redis.utils.RedisUtils;
import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.bo.ChatSessionBo;
import org.ruoyi.domain.bo.QueryVectorBo; import org.ruoyi.domain.bo.QueryVectorBo;
import org.ruoyi.domain.vo.ChatModelVo; import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.domain.vo.KnowledgeInfoVo; import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.service.IKnowledgeInfoService;
import org.ruoyi.service.VectorStoreService;
import org.ruoyi.service.IChatModelService; import org.ruoyi.service.IChatModelService;
import org.ruoyi.service.IChatSessionService; import org.ruoyi.service.IChatSessionService;
import org.ruoyi.service.IKnowledgeInfoService;
import org.ruoyi.service.VectorStoreService;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@@ -49,10 +43,12 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/**
* @author ageer
*/
@Service @Service
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -81,24 +77,20 @@ public class SseServiceImpl implements ISseService {
try { try {
// 构建消息列表 // 构建消息列表
buildChatMessageList(chatRequest); buildChatMessageList(chatRequest);
if (!StpUtil.isLogin()) {
// 未登录用户限制对话次数 LocalCache.CACHE.put("userId", chatCostService.getUserId());
checkUnauthenticatedUserChatLimit(request); chatRequest.setUserId(chatCostService.getUserId());
}else { // 保存会话信息
LocalCache.CACHE.put("userId", chatCostService.getUserId()); if(chatRequest.getSessionId()==null){
chatRequest.setUserId(chatCostService.getUserId()); ChatSessionBo chatSessionBo = new ChatSessionBo();
// 保存会话信息 chatSessionBo.setUserId(chatCostService.getUserId());
if(chatRequest.getSessionId()==null){ chatSessionBo.setSessionTitle(getFirst10Characters(chatRequest.getPrompt()));
ChatSessionBo chatSessionBo = new ChatSessionBo(); chatSessionBo.setSessionContent(chatRequest.getPrompt());
chatSessionBo.setUserId(chatCostService.getUserId()); chatSessionService.insertByBo(chatSessionBo);
chatSessionBo.setSessionTitle(getFirst10Characters(chatRequest.getPrompt())); chatRequest.setSessionId(chatSessionBo.getId());
chatSessionBo.setSessionContent(chatRequest.getPrompt());
chatSessionService.insertByBo(chatSessionBo);
chatRequest.setSessionId(chatSessionBo.getId());
}
// 保存消息记录 并扣除费用
chatCostService.deductToken(chatRequest);
} }
// 保存消息记录 并扣除费用
chatCostService.deductToken(chatRequest);
// 根据模型分类调用不同的处理逻辑 // 根据模型分类调用不同的处理逻辑
IChatService chatService = chatServiceFactory.getChatService(chatModelVo.getCategory()); IChatService chatService = chatServiceFactory.getChatService(chatModelVo.getCategory());
chatService.chat(chatRequest, sseEmitter); chatService.chat(chatRequest, sseEmitter);
@@ -126,33 +118,6 @@ public class SseServiceImpl implements ISseService {
} }
} }
/**
* 检查未登录用户是否超过当日对话次数限制
*
* @param request 当前请求
* @throws ServiceException 如果当日免费次数已用完
*/
public void checkUnauthenticatedUserChatLimit(HttpServletRequest request) throws ServiceException {
String clientIp = IpUtil.getClientIp(request);
// 访客每天默认只能对话5次
int timeWindowInSeconds = 5;
String redisKey = "clientIp:" + clientIp;
int count = 0;
// 检查Redis中的对话次数
if (RedisUtils.getCacheObject(redisKey) == null) {
// 缓存有效时间1天
RedisUtils.setCacheObject(redisKey, count, Duration.ofSeconds(86400));
} else {
count = RedisUtils.getCacheObject(redisKey);
if (count >= timeWindowInSeconds) {
throw new ServiceException("当日免费次数已用完");
}
count++;
RedisUtils.setCacheObject(redisKey, count);
}
}
/** /**
* 构建消息列表 * 构建消息列表
*/ */

View File

@@ -330,10 +330,11 @@ public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService {
} }
} }
} }
/** /**
* 第一步 定时 拆解PDF文件中的图片 * 第一步 定时 拆解PDF文件中的图片
*/ */
@Scheduled(fixedDelay = 15000) // 每3秒执行一次 //@Scheduled(fixedDelay = 15000) // 每3秒执行一次
public void dealKnowledgeAttachPic() throws Exception { public void dealKnowledgeAttachPic() throws Exception {
//处理 拆解PDF文件中的图片的记录 //处理 拆解PDF文件中的图片的记录
List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList( List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList(
@@ -349,10 +350,11 @@ public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService {
} }
} }
} }
/** /**
* 第二步 定时 解析图片内容 * 第二步 定时 解析图片内容
*/ */
@Scheduled(fixedDelay = 15000) //@Scheduled(fixedDelay = 15000)
public void dealKnowledgeAttachPicAnys() throws Exception { public void dealKnowledgeAttachPicAnys() throws Exception {
//获取未处理的图片记录 //获取未处理的图片记录
List<KnowledgeAttachPic> knowledgeAttachPics = picMapper.selectList( List<KnowledgeAttachPic> knowledgeAttachPics = picMapper.selectList(
@@ -369,7 +371,7 @@ public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService {
/** /**
* 第三步 定时 处理 附件上传后上传向量数据库 * 第三步 定时 处理 附件上传后上传向量数据库
*/ */
@Scheduled(fixedDelay = 30000) // 每3秒执行一次 //@Scheduled(fixedDelay = 30000) // 每3秒执行一次
public void dealKnowledgeAttachVector() throws Exception { public void dealKnowledgeAttachVector() throws Exception {
//处理 需要上传向量数据库的记录 //处理 需要上传向量数据库的记录
List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList( List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList(
@@ -388,7 +390,7 @@ public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService {
/** /**
* 第四步 定时 处理 失败数据 * 第四步 定时 处理 失败数据
*/ */
@Scheduled(fixedDelay = 30 * 60 * 1000) //@Scheduled(fixedDelay = 30 * 60 * 1000)
public void dealKnowledge40Status() throws Exception { public void dealKnowledge40Status() throws Exception {
//拆解PDF失败 重新设置状态 //拆解PDF失败 重新设置状态
attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>() attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>()