ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatSessionBo.java
@@ -29,13 +29,11 @@ /** * 用户id */ @NotNull(message = "用户id不能为空", groups = { AddGroup.class, EditGroup.class }) private Long userId; /** * 会话标题 */ @NotBlank(message = "会话标题不能为空", groups = { AddGroup.class, EditGroup.class }) private String sessionTitle; /** @@ -47,7 +45,6 @@ /** * 备注 */ @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class }) private String remark; ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatMessageServiceImpl.java
@@ -2,6 +2,7 @@ import org.ruoyi.common.core.utils.MapstructUtils; 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.PageQuery; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -45,6 +46,10 @@ */ @Override public TableDataInfo<ChatMessageVo> queryPageList(ChatMessageBo bo, PageQuery pageQuery) { if(!LoginHelper.isLogin()){ return TableDataInfo.build(); } bo.setUserId(LoginHelper.getUserId()); LambdaQueryWrapper<ChatMessage> lqw = buildQueryWrapper(bo); Page<ChatMessageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); return TableDataInfo.build(result); @@ -64,9 +69,8 @@ LambdaQueryWrapper<ChatMessage> lqw = Wrappers.lambdaQuery(); lqw.eq(bo.getUserId() != null, ChatMessage::getUserId, bo.getUserId()); lqw.eq(StringUtils.isNotBlank(bo.getContent()), ChatMessage::getContent, bo.getContent()); lqw.eq(StringUtils.isNotBlank(bo.getRole()), ChatMessage::getRole, bo.getRole()); lqw.eq(bo.getDeductCost() != null, ChatMessage::getDeductCost, bo.getDeductCost()); lqw.eq(bo.getTotalTokens() != null, ChatMessage::getTotalTokens, bo.getTotalTokens()); lqw.eq(bo.getSessionId() != null, ChatMessage::getSessionId, bo.getSessionId()); lqw.like(StringUtils.isNotBlank(bo.getRole()), ChatMessage::getRole, bo.getRole()); lqw.like(StringUtils.isNotBlank(bo.getModelName()), ChatMessage::getModelName, bo.getModelName()); return lqw; } ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatSessionController.java
@@ -8,6 +8,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission; import org.ruoyi.common.excel.utils.ExcelUtil; import org.ruoyi.common.idempotent.annotation.RepeatSubmit; import org.ruoyi.common.satoken.utils.LoginHelper; import org.ruoyi.core.page.TableDataInfo; import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.vo.ChatSessionVo; @@ -42,6 +43,12 @@ @SaCheckPermission("system:session:list") @GetMapping("/list") public TableDataInfo<ChatSessionVo> list(ChatSessionBo bo, PageQuery pageQuery) { if(!LoginHelper.isLogin()){ // 如果用户没有登录,返回空会话列表 return TableDataInfo.build(); } // 默认查询当前用户会话 bo.setUserId(LoginHelper.getUserId()); return chatSessionService.queryPageList(bo, pageQuery); } ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -1,19 +1,14 @@ package org.ruoyi.chat.service.chat.impl; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.google.protobuf.ServiceException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import okhttp3.ResponseBody; import org.ruoyi.chat.enums.ChatModeType; import org.ruoyi.chat.factory.ChatServiceFactory; import org.ruoyi.chat.service.chat.IChatCostService; import org.ruoyi.chat.service.chat.IChatService; import org.ruoyi.chat.service.chat.ISseService; import org.ruoyi.chat.util.IpUtil; import org.ruoyi.chat.util.SSEUtil; import org.ruoyi.common.chat.config.LocalCache; import org.ruoyi.common.chat.entity.Tts.TextToSpeech; @@ -26,15 +21,14 @@ import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.core.utils.file.FileUtils; 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.QueryVectorBo; import org.ruoyi.domain.vo.ChatModelVo; 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.IChatSessionService; import org.ruoyi.service.IKnowledgeInfoService; import org.ruoyi.service.VectorStoreService; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; @@ -49,10 +43,12 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; import java.util.List; /** * @author ageer */ @Service @Slf4j @RequiredArgsConstructor @@ -81,10 +77,7 @@ try { // 构建消息列表 buildChatMessageList(chatRequest); if (!StpUtil.isLogin()) { // 未登录用户限制对话次数 checkUnauthenticatedUserChatLimit(request); }else { LocalCache.CACHE.put("userId", chatCostService.getUserId()); chatRequest.setUserId(chatCostService.getUserId()); // 保存会话信息 @@ -98,7 +91,6 @@ } // 保存消息记录 并扣除费用 chatCostService.deductToken(chatRequest); } // 根据模型分类调用不同的处理逻辑 IChatService chatService = chatServiceFactory.getChatService(chatModelVo.getCategory()); chatService.chat(chatRequest, sseEmitter); @@ -123,33 +115,6 @@ } else { // 如果长度不足10,返回整个字符串 return str; } } /** * 检查未登录用户是否超过当日对话次数限制 * * @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); } } ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java
@@ -330,10 +330,11 @@ } } } /** * 第一步 定时 拆解PDF文件中的图片 */ @Scheduled(fixedDelay = 15000) // 每3秒执行一次 //@Scheduled(fixedDelay = 15000) // 每3秒执行一次 public void dealKnowledgeAttachPic() throws Exception { //处理 拆解PDF文件中的图片的记录 List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList( @@ -349,10 +350,11 @@ } } } /** * 第二步 定时 解析图片内容 */ @Scheduled(fixedDelay = 15000) //@Scheduled(fixedDelay = 15000) public void dealKnowledgeAttachPicAnys() throws Exception { //获取未处理的图片记录 List<KnowledgeAttachPic> knowledgeAttachPics = picMapper.selectList( @@ -369,7 +371,7 @@ /** * 第三步 定时 处理 附件上传后上传向量数据库 */ @Scheduled(fixedDelay = 30000) // 每3秒执行一次 //@Scheduled(fixedDelay = 30000) // 每3秒执行一次 public void dealKnowledgeAttachVector() throws Exception { //处理 需要上传向量数据库的记录 List<KnowledgeAttach> knowledgeAttaches = attachMapper.selectList( @@ -388,7 +390,7 @@ /** * 第四步 定时 处理 失败数据 */ @Scheduled(fixedDelay = 30 * 60 * 1000) //@Scheduled(fixedDelay = 30 * 60 * 1000) public void dealKnowledge40Status() throws Exception { //拆解PDF失败 重新设置状态 attachMapper.update(new LambdaUpdateWrapper<KnowledgeAttach>()