办学质量监测教学评价系统
ageerle
2025-04-14 188dc1e55e3abbfb00397d67e2b4eed52cead356
feat: mcp 测试版本
已修改12个文件
已添加1个文件
已删除39个文件
2679 ■■■■■ 文件已修改
ruoyi-admin/src/main/resources/application.yml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules-api/ruoyi-chat-api/pom.xml 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatCostService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ChatCostServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/pom.xml 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/MailController.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisCacheController.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisLockController.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisPubSubController.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisRateLimiterController.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/SmsController.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/Swagger3DemoController.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestBatchController.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestDemoController.java 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestEncryptController.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestExcelController.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestI18nController.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestSensitiveController.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestTreeController.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/BoundedQueueController.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/DelayedQueueController.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/PriorityDemo.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/PriorityQueueController.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/TestDemo.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/TestDemoEncrypt.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/TestTree.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/bo/TestDemoBo.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/bo/TestDemoImportVo.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/bo/TestTreeBo.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/vo/TestDemoVo.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/vo/TestTreeVo.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/mapper/TestDemoEncryptMapper.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/mapper/TestDemoMapper.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/mapper/TestTreeMapper.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/ITestDemoService.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/ITestTreeService.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/impl/TestDemoServiceImpl.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/impl/TestTreeServiceImpl.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/resources/excel/单列表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/resources/excel/多列表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/GenTableColumn.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml
@@ -322,6 +322,9 @@
spring:
  ai:
    openai:
      api-key: sk-xX
      base-url: https://api.pandarobot.chat/
    ollama:
      base-url: http://localhost:11434
    mcp:
ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/request/ChatRequest.java
@@ -49,7 +49,7 @@
    /**
     * ç”¨æˆ·id
     */
    private String userId;
    private Long userId;
    /**
     * åº”用ID
ruoyi-modules-api/ruoyi-chat-api/pom.xml
@@ -60,17 +60,12 @@
<!--        <dependency>-->
<!--            <groupId>org.springframework.ai</groupId>-->
<!--            <artifactId>spring-ai-mcp</artifactId>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.ai</groupId>-->
<!--            <artifactId>spring-ai-openai</artifactId>-->
<!--            <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
ruoyi-modules/ruoyi-chat/pom.xml
@@ -113,12 +113,6 @@
            <groupId>org.ruoyi</groupId>
            <artifactId>ruoyi-system-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-ollama</artifactId>
            <version>1.0.0-M6</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java
@@ -18,7 +18,7 @@
import org.ruoyi.common.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.Objects;
@@ -34,13 +34,13 @@
public class SSEEventSourceListener extends EventSourceListener {
    @Autowired(required = false)
    public SSEEventSourceListener(ResponseBodyEmitter emitter) {
    public SSEEventSourceListener(SseEmitter emitter) {
        this.emitter = emitter;
    }
    private ResponseBodyEmitter emitter;
    private SseEmitter emitter;
    private StringBuilder stringBuffer;
    private StringBuilder stringBuffer = new StringBuilder();
    private String modelName;
@@ -61,7 +61,6 @@
    @Override
    public void onEvent(@NotNull EventSource eventSource, String id, String type, String data) {
        try {
            if ("[DONE]".equals(data)) {
                //成功响应
                emitter.complete();
@@ -72,25 +71,23 @@
                chatCostService.deductToken(chatRequest);
                return;
            }
            // è§£æžè¿”回内容
            ObjectMapper mapper = new ObjectMapper();
            ChatCompletionResponse completionResponse = mapper.readValue(data, ChatCompletionResponse.class);
            if(completionResponse == null || CollectionUtil.isEmpty(completionResponse.getChoices())){
                return;
            }
            Object content = completionResponse.getChoices().get(0).getDelta().getContent();
            if(content == null){
                content = completionResponse.getChoices().get(0).getDelta().getReasoningContent();
                if(content == null) return;
            }
            if(content != null ){
            if(StringUtils.isEmpty(modelName)){
                modelName = completionResponse.getModel();
            }
            stringBuffer.append(content);
            emitter.send(data);
                emitter.send(content);
            }
        } catch (Exception e) {
            log.error("sse信息推送失败{}内容:{}",e.getMessage(),data);
            eventSource.cancel();
            emitter.completeWithError(e);
        }
    }
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatCostService.java
@@ -40,4 +40,9 @@
     * åˆ¤æ–­ç”¨æˆ·æ˜¯å¦ä»˜è´¹
     */
    void checkUserGrade();
    /**
     * èŽ·å–ç™»å½•ç”¨æˆ·id
     */
    Long getUserId();
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatService.java
@@ -22,5 +22,5 @@
     * å®¢æˆ·ç«¯å‘送消息到服务端
     * @param chatRequest è¯·æ±‚对象
     */
    SseEmitter mcpChat(ChatRequest chatRequest,SseEmitter emitter);
    void mcpChat(ChatRequest chatRequest,SseEmitter emitter);
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ChatCostServiceImpl.java
@@ -6,6 +6,7 @@
import org.ruoyi.chat.enums.BillingType;
import org.ruoyi.chat.enums.UserGradeType;
import org.ruoyi.chat.service.chat.IChatCostService;
import org.ruoyi.common.chat.config.LocalCache;
import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.common.chat.utils.TikTokensUtil;
import org.ruoyi.common.core.domain.model.LoginUser;
@@ -96,6 +97,12 @@
            chatToken.setUserId(chatMessageBo.getUserId());
            chatTokenService.editToken(chatToken);
        }
        Object userId = LocalCache.CACHE.get("userId");
        if(userId!=null){
            chatMessageBo.setUserId((Long) userId);
        }else {
            chatMessageBo.setUserId(getUserId());
        }
        // ä¿å­˜æ¶ˆæ¯è®°å½•
        chatMessageService.insertByBo(chatMessageBo);
    }
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java
@@ -7,24 +7,13 @@
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
import io.github.ollama4j.models.generate.OllamaStreamHandler;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.chat.util.SSEUtil;
import org.ruoyi.common.chat.entity.chat.Message;
import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.IChatModelService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.ollama.api.OllamaModel;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
@@ -35,27 +24,11 @@
@Service
@Slf4j
public class OllamaServiceImpl implements IChatService {
public class OllamaServiceImpl  {
    @Autowired
    private  IChatModelService chatModelService;
    private final ChatClient chatClient;
    private final ChatMemory chatMemory = new InMemoryChatMemory();
    public OllamaServiceImpl(ChatClient.Builder chatClientBuilder,ToolCallbackProvider tools) {
        this.chatClient = chatClientBuilder
                .defaultTools(tools)
                .defaultOptions(
                        OllamaOptions.builder()
                                .model(OllamaModel.QWEN_2_5_7B)
                                .temperature(0.4)
                                .build())
                .build();
    }
    @Override
    public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) {
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        String host = chatModelVo.getApiHost();
@@ -100,44 +73,4 @@
        return emitter;
    }
    @Override
    public SseEmitter mcpChat(ChatRequest chatRequest, SseEmitter emitter) {
        List<Message> msgList = chatRequest.getMessages();
        // æ·»åŠ è®°å¿†
        for (int i = 0; i < msgList.size(); i++) {
            org.springframework.ai.chat.messages.Message springAiMessage = new UserMessage(msgList.get(i).getContent().toString());
            chatMemory.add(String.valueOf(i),springAiMessage);
        }
        var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, chatRequest.getUserId(), 10);
        this.chatClient.prompt(chatRequest.getPrompt())
                .advisors(messageChatMemoryAdvisor)
                .stream()
                .chatResponse()
                .subscribe(
                        chatResponse -> {
                            try {
                                emitter.send(chatResponse, MediaType.APPLICATION_JSON);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        },
                        error -> {
                            try {
                                emitter.completeWithError(error);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        },
                        () -> {
                            try {
                                emitter.complete();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                );
        return emitter;
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
package org.ruoyi.chat.service.chat.impl;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.common.chat.entity.chat.Message;
import org.ruoyi.common.chat.request.ChatRequest;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
import java.io.IOException;
import java.util.List;
@Service
@Slf4j
public class OpenAIServiceImpl implements IChatService {
   private final ChatClient chatClient;
    private final ChatMemory chatMemory = new InMemoryChatMemory();
    public OpenAIServiceImpl(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools) {
        this.chatClient = chatClientBuilder
                .defaultTools(tools)
                .defaultOptions(
                        OpenAiChatOptions.builder()
                                .model("gpt-4o-mini")
                                .temperature(0.4)
                                .build())
                .build();
    }
    @Override
    public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) {
        return emitter;
    }
    @Override
    public void mcpChat(ChatRequest chatRequest, SseEmitter emitter) {
        List<Message> msgList = chatRequest.getMessages();
        // æ·»åŠ è®°å¿†
        for (int i = 0; i < msgList.size(); i++) {
            org.springframework.ai.chat.messages.Message springAiMessage = new UserMessage(msgList.get(i).getContent().toString());
            chatMemory.add(String.valueOf(i), springAiMessage);
        }
        var messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory, chatRequest.getUserId().toString(), 10);
        Flux<String> content = chatClient
                .prompt(chatRequest.getPrompt())
                .advisors(messageChatMemoryAdvisor)
                .stream().content();
        content.publishOn(Schedulers.boundedElastic())
                .doOnNext(text -> {
                    try {
                        emitter.send(text);
                    } catch (IOException e) {
                        emitter.completeWithError(e);
                    }
                })
                .doOnError(error -> {
                    log.error("Error in SSE stream: ", error);
                    emitter.completeWithError(error);
                })
                .doOnComplete(emitter::complete)
                .subscribe();
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -11,11 +11,13 @@
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.ruoyi.chat.config.ChatConfig;
import org.ruoyi.chat.listener.SSEEventSourceListener;
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.request.ChatRequest;
import org.ruoyi.common.chat.entity.Tts.TextToSpeech;
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
@@ -33,7 +35,9 @@
import org.ruoyi.common.redis.utils.RedisUtils;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.EmbeddingService;
import org.ruoyi.service.IChatModelService;
import org.ruoyi.service.VectorStoreService;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
@@ -74,27 +78,35 @@
    private final IChatService chatService;
    private final IChatModelService chatModelService;
    private static final String requestIdTemplate = "company-%d";
    private static final ObjectMapper mapper = new ObjectMapper();
    private final ChatConfig chatConfig;
    @Override
    public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) {
        SseEmitter sseEmitter = new SseEmitter(0L);
        SseEmitter sseEmitter = new SseEmitter();
        try {
            // æž„建消息列表增加联网、知识库等内容
            buildChatMessageList(chatRequest);
            // æ ¹æ®æ¨¡åž‹åç§°å‰ç¼€è°ƒç”¨ä¸åŒçš„处理逻辑
            switchModelAndHandle(chatRequest,sseEmitter);
            if (!StpUtil.isLogin()) {
            // æœªç™»å½•用户限制对话次数
            checkUnauthenticatedUserChatLimit(request);
            }else {
                LocalCache.CACHE.put("userId", chatCostService.getUserId());
                chatRequest.setUserId(chatCostService.getUserId());
            // ä¿å­˜æ¶ˆæ¯è®°å½• å¹¶æ‰£é™¤è´¹ç”¨
            chatCostService.deductToken(chatRequest);
                // chatCostService.deductToken(chatRequest);
            }
            // æ ¹æ®æ¨¡åž‹åç§°å‰ç¼€è°ƒç”¨ä¸åŒçš„处理逻辑
            switchModelAndHandle(chatRequest,sseEmitter);
        } catch (Exception e) {
            String message = e.getMessage();
            SSEUtil.sendErrorEvent(sseEmitter, message);
            return sseEmitter;
            log.error(e.getMessage(),e);
            sseEmitter.completeWithError(e);
        }
        return sseEmitter;
    }
@@ -106,8 +118,7 @@
     * @throws ServiceException å¦‚果当日免费次数已用完
     */
    public void checkUnauthenticatedUserChatLimit(HttpServletRequest request) throws ServiceException {
        // æœªç™»å½•用户限制对话次数
        if (!StpUtil.isLogin()) {
            String clientIp = IpUtil.getClientIp(request);
            // è®¿å®¢æ¯å¤©é»˜è®¤åªèƒ½å¯¹è¯5次
            int timeWindowInSeconds = 5;
@@ -125,13 +136,14 @@
                count++;
                RedisUtils.setCacheObject(redisKey, count);
            }
        }
    }
    /**
     *  æ ¹æ®æ¨¡åž‹åç§°å‰ç¼€è°ƒç”¨ä¸åŒçš„处理逻辑
     */
    private void switchModelAndHandle(ChatRequest chatRequest,SseEmitter emitter) {
        SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(emitter);
        String model = chatRequest.getModel();
        // å¦‚果模型名称以ollama开头,则调用ollama中部署的本地模型
        if (model.startsWith("ollama-")) {
@@ -142,8 +154,24 @@
            } else {
                throw new IllegalArgumentException("Invalid ollama model name: " + chatRequest.getModel());
            }
        } else if (model.startsWith("gpt-4-gizmo")) {
        } else {
            if (model.startsWith("gpt-4-gizmo")) {
            chatRequest.setModel("gpt-4-gizmo");
            }
            ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
            //openAiStreamClient = chatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
            ChatCompletion completion = ChatCompletion
                    .builder()
                    .messages(chatRequest.getMessages())
                    .model(chatRequest.getModel())
                    .temperature(0.2)
                    .topP(1.0)
                    .stream(true)
                    .build();
            openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
        }
    }
@@ -151,9 +179,10 @@
     *  æž„建消息列表
     */
    private void buildChatMessageList(ChatRequest chatRequest){
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        // èŽ·å–å¯¹è¯æ¶ˆæ¯åˆ—è¡¨
        List<Message> messages = chatRequest.getMessages();
        String sysPrompt = chatRequest.getSysPrompt();
        String sysPrompt = chatModelVo.getSystemPrompt();
        if(StringUtils.isEmpty(sysPrompt)){
            sysPrompt ="你是一个由RuoYI-AI开发的人工智能助手,名字叫熊猫助手。你擅长中英文对话,能够理解并处理各种问题,提供安全、有帮助、准确的回答。" +
                    "当前时间:"+ DateUtils.getDate();
@@ -162,8 +191,9 @@
        Message sysMessage = Message.builder().content(sysPrompt).role(Message.Role.SYSTEM).build();
        messages.add(0,sysMessage);
        chatRequest.setSysPrompt(sysPrompt);
        // æŸ¥è¯¢å‘量库相关信息加入到上下文
        if(chatRequest.getKid()!=null){
        if(StringUtils.isNotEmpty(chatRequest.getKid())){
            List<Message> knMessages = new ArrayList<>();
            String content = messages.get(messages.size() - 1).getContent().toString();
            List<String> nearestList;
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java
@@ -1,6 +1,7 @@
package org.ruoyi.chat.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
@@ -19,7 +20,7 @@
     * @param sseEmitter sse事件对象
     * @param errorMessage é”™è¯¯ä¿¡æ¯
     */
    public static void sendErrorEvent(SseEmitter sseEmitter, String errorMessage) {
    public static void sendErrorEvent(ResponseBodyEmitter sseEmitter, String errorMessage) {
        SseEmitter.SseEventBuilder event = SseEmitter.event()
                .name("error")
                .data(errorMessage);
ruoyi-modules/ruoyi-demo/pom.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/MailController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisCacheController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisLockController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisPubSubController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/RedisRateLimiterController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/SmsController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/Swagger3DemoController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestBatchController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestDemoController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestEncryptController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestExcelController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestI18nController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestSensitiveController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/TestTreeController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/BoundedQueueController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/DelayedQueueController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/PriorityDemo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/controller/queue/PriorityQueueController.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/TestDemo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/TestDemoEncrypt.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/TestTree.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/bo/TestDemoBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/bo/TestDemoImportVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/bo/TestTreeBo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/vo/TestDemoVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/domain/vo/TestTreeVo.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/mapper/TestDemoEncryptMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/mapper/TestDemoMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/mapper/TestTreeMapper.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/ITestDemoService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/ITestTreeService.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/impl/TestDemoServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/java/org/ruoyi/demo/service/impl/TestTreeServiceImpl.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/resources/excel/µ¥Áбí.xlsx
Binary files differ
ruoyi-modules/ruoyi-demo/src/main/resources/excel/¶àÁбí.xlsx
Binary files differ
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-generator/src/main/java/org/ruoyi/generator/domain/GenTableColumn.java
@@ -41,7 +41,7 @@
    /**
     * åˆ—描述
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String columnComment;
    /**
@@ -63,43 +63,43 @@
    /**
     * æ˜¯å¦ä¸»é”®ï¼ˆ1是)
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isPk;
    /**
     * æ˜¯å¦è‡ªå¢žï¼ˆ1是)
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isIncrement;
    /**
     * æ˜¯å¦å¿…填(1是)
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isRequired;
    /**
     * æ˜¯å¦ä¸ºæ’入字段(1是)
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isInsert;
    /**
     * æ˜¯å¦ç¼–辑字段(1是)
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isEdit;
    /**
     * æ˜¯å¦åˆ—表字段(1是)
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isList;
    /**
     * æ˜¯å¦æŸ¥è¯¢å­—段(1是)
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isQuery;
    /**