办学质量监测教学评价系统
ageerle
2025-04-11 37a8b7dad32dbbad4e28ecd15dabd3147be03665
feat: 对话模块重构
已重命名2个文件
已修改3个文件
已添加5个文件
402 ■■■■■ 文件已修改
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/api/ChatController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/factory/SseServiceFactory.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/factory/VectorStoreFactory.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/factory/VectorizationFactory.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/ISseService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java 174 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/api/ChatController.java
@@ -49,9 +49,6 @@
    @PostMapping("/send")
    @ResponseBody
    public SseEmitter sseChat(@RequestBody @Valid ChatRequest chatRequest, HttpServletRequest request) {
        if (chatRequest.getModel().startsWith("ollama")) {
            return sseService.ollamaChat(chatRequest);
        }
        return sseService.sseChat(chatRequest,request);
    }
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/factory/SseServiceFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package org.ruoyi.chat.factory;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.chat.service.chat.impl.OllamaServiceImpl;
import org.ruoyi.chat.service.chat.impl.OpenAIServiceImpl;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class SseServiceFactory {
    public IChatService getSseService(String type) {
        if ("openai".equals(type)) {
            return new OpenAIServiceImpl();
        } else if ("ollama".equals(type)) {
            return new OllamaServiceImpl();
        } else {
            throw new IllegalArgumentException("Unknown type: " + type);
        }
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/factory/VectorStoreFactory.java
ÎļþÃû´Ó ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorstore/VectorStoreFactory.java ÐÞ¸Ä
@@ -1,8 +1,10 @@
package org.ruoyi.chat.service.knowledge.vectorstore;
package org.ruoyi.chat.factory;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.service.knowledge.vectorstore.MilvusVectorStore;
import org.ruoyi.chat.service.knowledge.vectorstore.WeaviateVectorStore;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.mapper.KnowledgeInfoMapper;
import org.ruoyi.service.VectorStoreService;
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/factory/VectorizationFactory.java
ÎļþÃû´Ó ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/vectorizer/VectorizationFactory.java ÐÞ¸Ä
@@ -1,9 +1,11 @@
package org.ruoyi.chat.service.knowledge.vectorizer;
package org.ruoyi.chat.factory;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.service.knowledge.vectorizer.BgeLargeVectorization;
import org.ruoyi.chat.service.knowledge.vectorizer.OpenAiVectorization;
import org.ruoyi.domain.vo.KnowledgeInfoVo;
import org.ruoyi.service.IKnowledgeInfoService;
import org.ruoyi.service.VectorizationService;
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/IChatService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package org.ruoyi.chat.service.chat;
import org.ruoyi.common.chat.request.ChatRequest;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
 * å¯¹è¯Service接口
 *
 * @author ageerle
 * @date 2025-04-08
 */
public interface IChatService {
    /**
     * å®¢æˆ·ç«¯å‘送消息到服务端
     * @param chatRequest è¯·æ±‚对象
     */
    SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter);
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/ISseService.java
@@ -39,9 +39,8 @@
     */
    ResponseEntity<Resource> textToSpeed(TextToSpeech textToSpeech);
    /**
     * ä¸Šä¼ æ–‡ä»¶åˆ°api服务器
     * ä¸Šä¼ æ–‡ä»¶åˆ°æœåС噍
     *
     * @param file æ–‡ä»¶ä¿¡æ¯
     * @return è¿”回文件信息
@@ -50,19 +49,11 @@
    /**
     * ä½¿ç”¨ollama调用本地模型
     * @param chatRequest å¯¹è¯ä¿¡æ¯
     * @return æµå¼è¾“出返回内容
     */
    SseEmitter ollamaChat(ChatRequest chatRequest);
    /**
     * ä¼ä¸šåº”用回复
     * @param prompt æç¤ºè¯
     * @return å›žå¤å†…容
     */
    String wxCpChat(String prompt);
    /**
     * è”网查询
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OllamaServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
package org.ruoyi.chat.service.chat.impl;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.models.chat.OllamaChatMessage;
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
import io.github.ollama4j.models.generate.OllamaStreamHandler;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Service
@Slf4j
public class OllamaServiceImpl implements IChatService {
    @Autowired
    private  IChatModelService chatModelService;
    @Override
    public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) {
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        String host = chatModelVo.getApiHost();
        List<Message> msgList = chatRequest.getMessages();
        List<OllamaChatMessage> messages = new ArrayList<>();
        for (Message message : msgList) {
            OllamaChatMessage ollamaChatMessage = new OllamaChatMessage();
            ollamaChatMessage.setRole(OllamaChatMessageRole.USER);
            ollamaChatMessage.setContent(message.getContent().toString());
            messages.add(ollamaChatMessage);
        }
        OllamaAPI api = new OllamaAPI(host);
        api.setRequestTimeoutSeconds(100);
        OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatRequest.getModel());
        OllamaChatRequestModel requestModel = builder
                .withMessages(messages)
                .build();
        // å¼‚步执行 OllAma API è°ƒç”¨
        CompletableFuture.runAsync(() -> {
            try {
                StringBuilder response = new StringBuilder();
                OllamaStreamHandler streamHandler = (s) -> {
                    String substr = s.substring(response.length());
                    response.append(substr);
                    System.out.println(substr);
                    try {
                        emitter.send(substr);
                    } catch (IOException e) {
                        SSEUtil.sendErrorEvent(emitter, e.getMessage());
                    }
                };
                api.chat(requestModel, streamHandler);
                emitter.complete();
            } catch (Exception e) {
                SSEUtil.sendErrorEvent(emitter, e.getMessage());
            }
        });
        return emitter;
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
package org.ruoyi.chat.service.chat.impl;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.config.ChatConfig;
import org.ruoyi.chat.listener.SSEEventSourceListener;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.IChatModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@Service
@Slf4j
public class OpenAIServiceImpl implements IChatService {
    @Autowired
    private  IChatModelService chatModelService;
    @Autowired
    private ChatConfig chatConfig;
    @Autowired
    private OpenAiStreamClient openAiStreamClient;
    @Override
    public SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter) {
        SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(emitter);
        // æŸ¥è¯¢æ¨¡åž‹ä¿¡æ¯
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        if(chatModelVo!=null){
            // å»ºè¯·æ±‚客户端
            openAiStreamClient = chatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
            // è®¾ç½®é»˜è®¤æç¤ºè¯
            chatRequest.setSysPrompt(chatModelVo.getSystemPrompt());
        }
        ChatCompletion completion = ChatCompletion
                .builder()
                .messages(chatRequest.getMessages())
                .model(chatRequest.getModel())
                .stream(chatRequest.getStream())
                .build();
        openAiStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
        return emitter;
    }
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -6,22 +6,17 @@
import com.google.protobuf.ServiceException;
import com.zhipu.oapi.ClientV4;
import com.zhipu.oapi.service.v4.tools.*;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.models.chat.OllamaChatMessage;
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
import io.github.ollama4j.models.chat.OllamaChatRequestModel;
import io.github.ollama4j.models.generate.OllamaStreamHandler;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
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.factory.SseServiceFactory;
import org.ruoyi.chat.util.IpUtil;
import org.ruoyi.chat.util.SSEUtil;
import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.common.chat.entity.Tts.TextToSpeech;
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
@@ -32,15 +27,14 @@
import org.ruoyi.common.chat.entity.whisper.WhisperResponse;
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.common.core.utils.DateUtils;
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.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;
@@ -60,7 +54,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -72,10 +65,6 @@
    private final OpenAiStreamClient openAiStreamClient;
    private final ChatConfig chatConfig;
    private final IChatModelService chatModelService;
    private final EmbeddingService embeddingService;
    private final VectorStoreService vectorStore;
@@ -84,6 +73,8 @@
    private final IChatCostService chatCostService;
    private final SseServiceFactory sseServiceFactory;
    private static final String requestIdTemplate = "company-%d";
    private static final ObjectMapper mapper = new ObjectMapper();
@@ -91,78 +82,64 @@
    @Override
    public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) {
        SseEmitter sseEmitter = new SseEmitter(0L);
        SSEEventSourceListener openAIEventSourceListener = new SSEEventSourceListener(sseEmitter);
        // èŽ·å–å¯¹è¯æ¶ˆæ¯åˆ—è¡¨
        List<Message> messages = chatRequest.getMessages();
        try {
            // æŸ¥è¯¢æ¨¡åž‹ä¿¡æ¯
            ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
            OpenAiStreamClient openAiModelStreamClient;
            if(chatModelVo!=null){
                // å»ºè¯·æ±‚客户端
                openAiModelStreamClient = chatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
                // è®¾ç½®é»˜è®¤æç¤ºè¯
                chatRequest.setSysPrompt(chatModelVo.getSystemPrompt());
            }else {
                // ä½¿ç”¨é»˜è®¤å®¢æˆ·ç«¯
                openAiModelStreamClient = openAiStreamClient;
            }
            // æž„建消息列表增加联网、知识库等内容
            buildChatMessageList(chatRequest);
            // æ ¹æ®æ¨¡åž‹åç§°å‰ç¼€è°ƒç”¨ä¸åŒçš„处理逻辑
            switchModelAndHandle(chatRequest);
            switchModelAndHandle(chatRequest,sseEmitter);
            // æœªç™»å½•用户限制对话次数
            if (!StpUtil.isLogin()) {
                String clientIp = IpUtil.getClientIp(request);
                // è®¿å®¢æ¯å¤©é»˜è®¤åªèƒ½å¯¹è¯5次
                int timeWindowInSeconds = 5;
                String redisKey = "clientIp:" + clientIp;
                int count = 0;
                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);
                }
            }
            ChatCompletion completion = ChatCompletion
                    .builder()
                    .messages(messages)
                    .model(chatRequest.getModel())
                    .stream(chatRequest.getStream())
                    .build();
            openAiModelStreamClient.streamChatCompletion(completion, openAIEventSourceListener);
            checkUnauthenticatedUserChatLimit(request);
            // ä¿å­˜æ¶ˆæ¯è®°å½• å¹¶æ‰£é™¤è´¹ç”¨
            chatCostService.deductToken(chatRequest);
        } catch (Exception e) {
            String message = e.getMessage();
            sendErrorEvent(sseEmitter, message);
            SSEUtil.sendErrorEvent(sseEmitter, message);
            return sseEmitter;
        }
        return sseEmitter;
    }
    /**
     * æ£€æŸ¥æœªç™»å½•用户是否超过当日对话次数限制
     *
     * @param request å½“前请求
     * @throws ServiceException å¦‚果当日免费次数已用完
     */
    public void checkUnauthenticatedUserChatLimit(HttpServletRequest request) throws ServiceException {
        // æœªç™»å½•用户限制对话次数
        if (!StpUtil.isLogin()) {
            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);
            }
        }
    }
    /**
     *  æ ¹æ®æ¨¡åž‹åç§°å‰ç¼€è°ƒç”¨ä¸åŒçš„处理逻辑
     */
    private void switchModelAndHandle(ChatRequest chatRequest) {
    private void switchModelAndHandle(ChatRequest chatRequest,SseEmitter emitter) {
        String model = chatRequest.getModel();
        // å¦‚果模型名称以ollama开头,则调用ollama中部署的本地模型
        if (model.startsWith("ollama-")) {
            String[] parts = chatRequest.getModel().split("ollama-", 2); // é™åˆ¶åˆ†å‰²æ¬¡æ•°ä¸º2
            if (parts.length > 1) {
                chatRequest.setModel(parts[1]);
                ollamaChat(chatRequest);
                IChatService chatService = sseServiceFactory.getSseService("ollama");
                chatService.chat(chatRequest,emitter);
            } else {
                throw new IllegalArgumentException("Invalid ollama model name: " + chatRequest.getModel());
            }
@@ -177,8 +154,13 @@
    private void buildChatMessageList(ChatRequest chatRequest){
        // èŽ·å–å¯¹è¯æ¶ˆæ¯åˆ—è¡¨
        List<Message> messages = chatRequest.getMessages();
        String sysPrompt = chatRequest.getSysPrompt();
        if(StringUtils.isEmpty(sysPrompt)){
            sysPrompt ="你是一个由RuoYI-AI开发的人工智能助手,名字叫熊猫助手。你擅长中英文对话,能够理解并处理各种问题,提供安全、有帮助、准确的回答。" +
                    "当前时间:"+ DateUtils.getDate();
        }
        // è®¾ç½®ç³»ç»Ÿé»˜è®¤æç¤ºè¯
        Message sysMessage = Message.builder().content(chatRequest.getSysPrompt()).role(Message.Role.SYSTEM).build();
        Message sysMessage = Message.builder().content(sysPrompt).role(Message.Role.SYSTEM).build();
        messages.add(0,sysMessage);
        // æŸ¥è¯¢å‘量库相关信息加入到上下文
@@ -216,23 +198,6 @@
        }
    }
    /**
     * å‘送SSE错误事件的封装方法
     *
     * @param sseEmitter
     * @param errorMessage
     */
    private void sendErrorEvent(SseEmitter sseEmitter, String errorMessage) {
        SseEmitter.SseEventBuilder event = SseEmitter.event()
                .name("error")
                .data(errorMessage);
        try {
            sseEmitter.send(event);
        } catch (IOException e) {
            log.error("SSE发送失败: {}", e.getMessage());
        }
        sseEmitter.complete();
    }
    /**
     * æ–‡å­—转语音
@@ -323,51 +288,6 @@
        return file;
    }
    @Override
    public SseEmitter ollamaChat(ChatRequest chatRequest) {
        ChatModelVo chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
        final SseEmitter emitter = new SseEmitter();
        String host = chatModelVo.getApiHost();
        List<Message> msgList = chatRequest.getMessages();
        List<OllamaChatMessage> messages = new ArrayList<>();
        for (Message message : msgList) {
            OllamaChatMessage ollamaChatMessage = new OllamaChatMessage();
            ollamaChatMessage.setRole(OllamaChatMessageRole.USER);
            ollamaChatMessage.setContent(message.getContent().toString());
            messages.add(ollamaChatMessage);
        }
        OllamaAPI api = new OllamaAPI(host);
        api.setRequestTimeoutSeconds(100);
        OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatRequest.getModel());
        OllamaChatRequestModel requestModel = builder
            .withMessages(messages)
            .build();
        // å¼‚步执行 OllAma API è°ƒç”¨
        CompletableFuture.runAsync(() -> {
            try {
                StringBuilder response = new StringBuilder();
                OllamaStreamHandler streamHandler = (s) -> {
                    String substr = s.substring(response.length());
                    response.append(substr);
                    System.out.println(substr);
                    try {
                        emitter.send(substr);
                    } catch (IOException e) {
                        sendErrorEvent(emitter, e.getMessage());
                    }
                };
                api.chat(requestModel, streamHandler);
                emitter.complete();
            } catch (Exception e) {
                sendErrorEvent(emitter, e.getMessage());
            }
        });
        return emitter;
    }
    @Override
    public String wxCpChat(String prompt) {
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/SSEUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package org.ruoyi.chat.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
/**
 * sse工具类
 *
 * @author WangLe
 */
@Slf4j
public class SSEUtil {
    /**
     * å‘送SSE错误事件的封装方法
     *
     * @param sseEmitter sse事件对象
     * @param errorMessage é”™è¯¯ä¿¡æ¯
     */
    public static void sendErrorEvent(SseEmitter sseEmitter, String errorMessage) {
        SseEmitter.SseEventBuilder event = SseEmitter.event()
                .name("error")
                .data(errorMessage);
        try {
            sseEmitter.send(event);
        } catch (IOException e) {
            log.error("SSE发送失败: {}", e.getMessage());
        }
        sseEmitter.complete();
    }
}