ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java
@@ -56,6 +56,12 @@ */ private Long userId; /** * ä¼è¯id */ private Long sessionId; /** * åºç¨ID */ ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatMessage.java
@@ -35,6 +35,11 @@ private Long userId; /** * ä¼è¯id */ private Long sessionId; /** * æ¶æ¯å 容 */ private String content; ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatSession.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,51 @@ package org.ruoyi.domain; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import lombok.EqualsAndHashCode; import org.ruoyi.core.domain.BaseEntity; import java.io.Serial; /** * ä¼è¯ç®¡ç对象 chat_session * * @author ageerle * @date 2025-05-03 */ @Data @EqualsAndHashCode(callSuper = true) @TableName("chat_session") public class ChatSession extends BaseEntity { @Serial private static final long serialVersionUID = 1L; /** * ä¸»é® */ @TableId(value = "id") private Long id; /** * ç¨æ·id */ private Long userId; /** * ä¼è¯æ é¢ */ private String sessionTitle; /** * ä¼è¯å 容 */ private String sessionContent; /** * 夿³¨ */ private String remark; } ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatMessageBo.java
@@ -41,6 +41,11 @@ private String content; /** * ä¼è¯id */ private Long sessionId; /** * 对è¯è§è² */ @NotBlank(message = "对è¯è§è²ä¸è½ä¸ºç©º", groups = { AddGroup.class, EditGroup.class }) ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatSessionBo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,54 @@ package org.ruoyi.domain.bo; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; import org.ruoyi.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; import lombok.EqualsAndHashCode; import jakarta.validation.constraints.*; import org.ruoyi.domain.ChatSession; /** * ä¼è¯ç®¡çä¸å¡å¯¹è±¡ chat_session * * @author ageerle * @date 2025-05-03 */ @Data @EqualsAndHashCode(callSuper = true) @AutoMapper(target = ChatSession.class, reverseConvertGenerate = false) public class ChatSessionBo extends BaseEntity { /** * ä¸»é® */ @NotNull(message = "主é®ä¸è½ä¸ºç©º", groups = { EditGroup.class }) private Long id; /** * ç¨æ·id */ @NotNull(message = "ç¨æ·idä¸è½ä¸ºç©º", groups = { AddGroup.class, EditGroup.class }) private Long userId; /** * ä¼è¯æ é¢ */ @NotBlank(message = "ä¼è¯æ é¢ä¸è½ä¸ºç©º", groups = { AddGroup.class, EditGroup.class }) private String sessionTitle; /** * ä¼è¯å 容 */ @NotBlank(message = "ä¼è¯å 容ä¸è½ä¸ºç©º", groups = { AddGroup.class, EditGroup.class }) private String sessionContent; /** * 夿³¨ */ @NotBlank(message = "夿³¨ä¸è½ä¸ºç©º", groups = { AddGroup.class, EditGroup.class }) private String remark; } ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatMessageVo.java
@@ -42,6 +42,11 @@ private Long userId; /** * ä¼è¯id */ private Long sessionId; /** * æ¶æ¯å 容 */ @ExcelProperty(value = "æ¶æ¯å 容") ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatSessionVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,59 @@ package org.ruoyi.domain.vo; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; import org.ruoyi.domain.ChatSession; import java.io.Serial; import java.io.Serializable; /** * ä¼è¯ç®¡çè§å¾å¯¹è±¡ chat_session * * @author ageerle * @date 2025-05-03 */ @Data @ExcelIgnoreUnannotated @AutoMapper(target = ChatSession.class) public class ChatSessionVo implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * ä¸»é® */ @ExcelProperty(value = "主é®") private Long id; /** * ç¨æ·id */ @ExcelProperty(value = "ç¨æ·id") private Long userId; /** * ä¼è¯æ é¢ */ @ExcelProperty(value = "ä¼è¯æ é¢") private String sessionTitle; /** * ä¼è¯å 容 */ @ExcelProperty(value = "ä¼è¯å 容") private String sessionContent; /** * 夿³¨ */ @ExcelProperty(value = "夿³¨") private String remark; } ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatSessionMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ package org.ruoyi.mapper; import org.ruoyi.core.mapper.BaseMapperPlus; import org.ruoyi.domain.ChatSession; import org.ruoyi.domain.vo.ChatSessionVo; /** * ä¼è¯ç®¡çMapperæ¥å£ * * @author ageerle * @date 2025-05-03 */ public interface ChatSessionMapper extends BaseMapperPlus<ChatSession, ChatSessionVo> { } ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatSessionService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,48 @@ package org.ruoyi.service; import org.ruoyi.core.page.PageQuery; import org.ruoyi.core.page.TableDataInfo; import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.vo.ChatSessionVo; import java.util.Collection; import java.util.List; /** * ä¼è¯ç®¡çServiceæ¥å£ * * @author ageerle * @date 2025-05-03 */ public interface IChatSessionService { /** * æ¥è¯¢ä¼è¯ç®¡ç */ ChatSessionVo queryById(Long id); /** * æ¥è¯¢ä¼è¯ç®¡çå表 */ TableDataInfo<ChatSessionVo> queryPageList(ChatSessionBo bo, PageQuery pageQuery); /** * æ¥è¯¢ä¼è¯ç®¡çå表 */ List<ChatSessionVo> queryList(ChatSessionBo bo); /** * æ°å¢ä¼è¯ç®¡ç */ Boolean insertByBo(ChatSessionBo bo); /** * ä¿®æ¹ä¼è¯ç®¡ç */ Boolean updateByBo(ChatSessionBo bo); /** * æ ¡éªå¹¶æ¹éå é¤ä¼è¯ç®¡çä¿¡æ¯ */ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); } ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatSessionServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,111 @@ package org.ruoyi.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.ruoyi.common.core.utils.MapstructUtils; import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.core.page.TableDataInfo; import org.ruoyi.core.page.PageQuery; import lombok.RequiredArgsConstructor; import org.ruoyi.domain.ChatSession; import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.vo.ChatSessionVo; import org.ruoyi.mapper.ChatSessionMapper; import org.ruoyi.service.IChatSessionService; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; import java.util.Collection; /** * ä¼è¯ç®¡çServiceä¸å¡å±å¤ç * * @author ageerle * @date 2025-05-03 */ @RequiredArgsConstructor @Service public class ChatSessionServiceImpl implements IChatSessionService { private final ChatSessionMapper baseMapper; /** * æ¥è¯¢ä¼è¯ç®¡ç */ @Override public ChatSessionVo queryById(Long id){ return baseMapper.selectVoById(id); } /** * æ¥è¯¢ä¼è¯ç®¡çå表 */ @Override public TableDataInfo<ChatSessionVo> queryPageList(ChatSessionBo bo, PageQuery pageQuery) { LambdaQueryWrapper<ChatSession> lqw = buildQueryWrapper(bo); Page<ChatSessionVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); return TableDataInfo.build(result); } /** * æ¥è¯¢ä¼è¯ç®¡çå表 */ @Override public List<ChatSessionVo> queryList(ChatSessionBo bo) { LambdaQueryWrapper<ChatSession> lqw = buildQueryWrapper(bo); return baseMapper.selectVoList(lqw); } private LambdaQueryWrapper<ChatSession> buildQueryWrapper(ChatSessionBo bo) { Map<String, Object> params = bo.getParams(); LambdaQueryWrapper<ChatSession> lqw = Wrappers.lambdaQuery(); lqw.eq(bo.getUserId() != null, ChatSession::getUserId, bo.getUserId()); lqw.eq(StringUtils.isNotBlank(bo.getSessionTitle()), ChatSession::getSessionTitle, bo.getSessionTitle()); lqw.eq(StringUtils.isNotBlank(bo.getSessionContent()), ChatSession::getSessionContent, bo.getSessionContent()); return lqw; } /** * æ°å¢ä¼è¯ç®¡ç */ @Override public Boolean insertByBo(ChatSessionBo bo) { ChatSession add = MapstructUtils.convert(bo, ChatSession.class); validEntityBeforeSave(add); boolean flag = baseMapper.insert(add) > 0; if (flag) { bo.setId(add.getId()); } return flag; } /** * ä¿®æ¹ä¼è¯ç®¡ç */ @Override public Boolean updateByBo(ChatSessionBo bo) { ChatSession update = MapstructUtils.convert(bo, ChatSession.class); validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; } /** * ä¿ååçæ°æ®æ ¡éª */ private void validEntityBeforeSave(ChatSession entity){ //TODO åä¸äºæ°æ®æ ¡éª,å¦å¯ä¸çº¦æ } /** * æ¹éå é¤ä¼è¯ç®¡ç */ @Override public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { if(isValid){ //TODO åä¸äºä¸å¡ä¸çæ ¡éª,夿æ¯å¦éè¦æ ¡éª } return baseMapper.deleteBatchIds(ids) > 0; } } ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ChatCostServiceImpl.java
@@ -46,6 +46,7 @@ /** * æ£é¤ç¨æ·ä½é¢ */ @Override public void deductToken(ChatRequest chatRequest) { int tokens = TikTokensUtil.tokens(chatRequest.getModel(), chatRequest.getPrompt()); @@ -53,6 +54,7 @@ String modelName = chatRequest.getModel(); ChatMessageBo chatMessageBo = new ChatMessageBo(); chatMessageBo.setSessionId(chatRequest.getSessionId()); Object userId = LocalCache.CACHE.get("userId"); if(userId!=null){ ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -24,9 +24,12 @@ 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.ChatSession; import org.ruoyi.domain.bo.ChatSessionBo; import org.ruoyi.domain.vo.ChatModelVo; import org.ruoyi.service.EmbeddingService; import org.ruoyi.service.IChatModelService; import org.ruoyi.service.IChatSessionService; import org.ruoyi.service.VectorStoreService; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; @@ -65,6 +68,8 @@ private final OllamaServiceImpl ollamaService; private final IChatSessionService chatSessionService; private ChatModelVo chatModelVo; @@ -80,6 +85,15 @@ }else { LocalCache.CACHE.put("userId", chatCostService.getUserId()); chatRequest.setUserId(chatCostService.getUserId()); // ä¿åä¼è¯ä¿¡æ¯ if(chatRequest.getSessionId()==null){ ChatSessionBo chatSessionBo = new ChatSessionBo(); chatSessionBo.setUserId(chatCostService.getUserId()); chatSessionBo.setSessionTitle(getFirst10Characters(chatRequest.getPrompt())); chatSessionBo.setSessionContent(chatRequest.getPrompt()); chatSessionService.insertByBo(chatSessionBo); chatRequest.setSessionId(chatSessionBo.getId()); } // ä¿åæ¶æ¯è®°å½ å¹¶æ£é¤è´¹ç¨ chatCostService.deductToken(chatRequest); } @@ -93,6 +107,23 @@ } /** * è·åå¯¹è¯æ é¢ * * @param str åå符 * @return æªååçå符 */ public static String getFirst10Characters(String str) { // 夿å符串é¿åº¦ if (str.length() > 10) { // 妿é¿åº¦å¤§äº10ï¼æªåå10个å符 return str.substring(0, 10); } else { // 妿é¿åº¦ä¸è¶³10ï¼è¿åæ´ä¸ªå符串 return str; } } /** * æ£æ¥æªç»å½ç¨æ·æ¯å¦è¶ è¿å½æ¥å¯¹è¯æ¬¡æ°éå¶ * * @param request å½å请æ±