From 97ae5a46cd54b2d5b10fca6a69c04874002162b0 Mon Sep 17 00:00:00 2001
From: ageerle <ageerle@163.com>
Date: 星期四, 05 六月 2025 16:16:32 +0800
Subject: [PATCH] feat: 调整sql脚本

---
 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java         |  151 +++++++++++++++++++++++++++++++++++++
 script/sql/ruoyi-ai.sql                                                                               |    4 
 script/sql/update/20250605.sql                                                                        |    1 
 ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java               |    6 +
 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/ChatModeType.java                         |    4 
 ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java       |    7 +
 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java |    2 
 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java           |   11 ++
 8 files changed, 181 insertions(+), 5 deletions(-)

diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java
index 86eef8d..62dbf97 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatModelService.java
@@ -53,9 +53,13 @@
      * 閫氳繃妯″瀷鍚嶇О鑾峰彇妯″瀷淇℃伅
      */
     ChatModelVo selectModelByName(String modelName);
-
+    /**
+     * 閫氳繃妯″瀷鍒嗙被鑾峰彇妯″瀷淇℃伅
+     */
+    ChatModelVo selectModelByCategory(String image);
     /**
      * 鑾峰彇ppt妯″瀷淇℃伅
      */
     ChatModel getPPT();
+
 }
diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java
index 4c82f3d..d0b5f5c 100644
--- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java
+++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatModelServiceImpl.java
@@ -129,6 +129,13 @@
     public ChatModelVo selectModelByName(String modelName) {
         return baseMapper.selectVoOne(Wrappers.<ChatModel>lambdaQuery().eq(ChatModel::getModelName, modelName));
     }
+    /**
+     * 閫氳繃妯″瀷鍒嗙被鑾峰彇妯″瀷淇℃伅
+     */
+    @Override
+    public ChatModelVo selectModelByCategory(String  category) {
+        return baseMapper.selectVoOne(Wrappers.<ChatModel>lambdaQuery().eq(ChatModel::getCategory, category));
+    }
 
     @Override
     public ChatModel getPPT() {
diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/ChatModeType.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/ChatModeType.java
index 8388ad2..13a39d9 100644
--- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/ChatModeType.java
+++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/enums/ChatModeType.java
@@ -15,7 +15,9 @@
 
     QIANWEN("qianwen", "閫氫箟鍗冮棶"),
 
-    VECTOR("vector", "鐭ヨ瘑搴撳悜閲忔ā鍨�");
+    VECTOR("vector", "鐭ヨ瘑搴撳悜閲忔ā鍨�"),
+
+    IMAGE("image", "鍥剧墖璇嗗埆妯″瀷");
 
     private final String code;
     private final String description;
diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java
new file mode 100644
index 0000000..a7eee8e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageServiceImpl.java
@@ -0,0 +1,151 @@
+package org.ruoyi.chat.service.chat.impl;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.ruoyi.chat.config.ChatConfig;
+import org.ruoyi.chat.enums.ChatModeType;
+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.entity.chat.Message;
+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;
+
+import java.util.*;
+
+/**
+ * 鍥剧墖璇嗗埆妯″瀷
+ */
+@Service
+@Slf4j
+public class ImageServiceImpl implements IChatService {
+
+    @Autowired
+    private IChatModelService chatModelService;
+
+    @SneakyThrows
+//    @Override
+//    public SseEmitter chat(ChatRequest chatRequest, SseEmitter emitter) {
+//        ChatModelVo chatModelVo = chatModelService.selectModelByCategory("image");
+//
+//        // 鍙戦�佹祦寮忔秷鎭�
+//
+//            MultiModalConversation conv = new MultiModalConversation();
+//            MultiModalMessage systemMessage = MultiModalMessage.builder().role(Role.SYSTEM.getValue())
+//                    .content(Arrays.asList(
+//                            Collections.singletonMap("text",chatRequest.getSysPrompt()))).build();
+//            // 鑾峰彇鐢ㄦ埛娑堟伅鍐呭
+//            List<Message> messages = chatRequest.getMessages();
+//            MultiModalMessage userMessage = null;
+//            //婕暱鐨勬牸寮忚浆鎹�
+//            // 閬嶅巻娑堟伅鍒楄〃锛屾彁鍙栨枃鏈唴瀹�
+//        if (messages != null && !messages.isEmpty()) {
+//            Object content = messages.get(messages.size() - 1).getContent();
+//            List<Map<String, Object>> contentList = new ArrayList<>();
+//            StringBuilder textContent = new StringBuilder();
+//            if (content instanceof List<?>) {
+//                for (Object item : (List<?>) content) {
+//                    if (item instanceof Map<?, ?> mapItem) {
+//                        String type = (String) mapItem.get("type");
+//                        if ("text".equals(type)) {
+//                            String text = (String) mapItem.get("text");
+//                            if (text != null) {
+//                                textContent.append(text).append(" ");
+//                            }
+//                        } else if ("image_url".equals(type)) {
+//                            Map<String, String> imageUrl  = (Map<String, String>) mapItem.get("image_url");
+//                                contentList.add(Collections.singletonMap("image", imageUrl.get("url")));
+//                        }
+//                    }
+//                }
+//            }
+//            // 灏嗘嫾鎺ュ悗鐨勬枃鏈唴瀹规坊鍔犲埌 contentList
+//            if (textContent.length() > 0) {
+//                contentList.add(Collections.singletonMap("text", textContent.toString().trim()));
+//            }
+//            userMessage = MultiModalMessage.builder()
+//                    .role(Role.USER.getValue())
+//                    .content(contentList)
+//                    .build();
+//        }
+//            MultiModalConversationParam param = MultiModalConversationParam.builder()
+//                    .apiKey(chatModelVo.getApiKey())
+//                    .model(chatModelVo.getModelName())
+//                    .messages(Arrays.asList(systemMessage, userMessage))
+//                    .incrementalOutput(true)
+//                    .build();
+//
+//
+//        try {
+//            final QwenStreamingResponseBuilder responseBuilder = new QwenStreamingResponseBuilder(param.getModel(),param.getIncrementalOutput() );
+//            conv.streamCall(param, new ResultCallback<>() {
+//                @SneakyThrows
+//                public void onEvent(MultiModalConversationResult result) {
+//
+//                    String delta = responseBuilder.append(result);
+//                    if (Utils.isNotNullOrEmpty(delta)) {
+//
+//                        emitter.send(delta);
+//                        log.info("鏀跺埌娑堟伅鐗囨: {}", delta);
+//                    }
+//                }
+//                public void onComplete() {
+//                    emitter.complete();
+//                    log.info("娑堟伅缁撴潫", responseBuilder.build());
+//                }
+//                public void onError(Exception e) {
+//                    log.info("璇锋眰澶辫触", e.getMessage());
+//                }
+//            });
+//        } catch (NoApiKeyException e) {
+//            emitter.send("璇峰厛閰嶇疆API瀵嗛挜");
+//            throw new RuntimeException(e);
+//        } catch (UploadFileException e) {
+//            throw new RuntimeException(e);
+//        }
+//
+//
+//        return emitter;
+//    }
+
+    @Override
+    public SseEmitter chat(ChatRequest chatRequest, SseEmitter emitter) {
+        // 浠庢暟鎹簱鑾峰彇 image 绫诲瀷鐨勬ā鍨嬮厤缃�
+        ChatModelVo chatModelVo = chatModelService.selectModelByCategory(ChatModeType.IMAGE.getCode());
+        if (chatModelVo == null) {
+            log.error("鏈壘鍒� image 绫诲瀷鐨勬ā鍨嬮厤缃�");
+            emitter.completeWithError(new IllegalStateException("鏈壘鍒� image 绫诲瀷鐨勬ā鍨嬮厤缃�"));
+            return emitter;
+        }
+
+        // 鍒涘缓 OpenAI 娴佸鎴风
+        OpenAiStreamClient openAiStreamClient = ChatConfig.createOpenAiStreamClient(chatModelVo.getApiHost(), chatModelVo.getApiKey());
+        List<Message> messages = chatRequest.getMessages();
+
+        // 鍒涘缓 SSE 浜嬩欢婧愮洃鍚櫒
+        SSEEventSourceListener listener = new SSEEventSourceListener(emitter, chatRequest.getUserId(), chatRequest.getSessionId());
+
+        // 鏋勫缓鑱婂ぉ瀹屾垚璇锋眰
+        ChatCompletion completion = ChatCompletion
+                .builder()
+                .messages(messages)
+                .model(chatModelVo.getModelName()) // 浣跨敤鏁版嵁搴撲腑閰嶇疆鐨勬ā鍨嬪悕绉�
+                .stream(true)
+                .build();
+
+        // 鍙戣捣娴佸紡鑱婂ぉ瀹屾垚璇锋眰
+        openAiStreamClient.streamChatCompletion(completion, listener);
+
+        return emitter;
+    }
+
+    @Override
+    public String getCategory() {
+        return ChatModeType.IMAGE.getCode();
+    }
+}
diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java
index 1d6e061..850ebf6 100644
--- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java
+++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/QianWenAiChatServiceImpl.java
@@ -35,6 +35,8 @@
                 .modelName(chatModelVo.getModelName())
                 .build();
 
+
+
         // 鍙戦�佹祦寮忔秷鎭�
         try {
             model.chat(chatRequest.getPrompt(), new StreamingChatResponseHandler() {
diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
index 472fd7b..d8c61a9 100644
--- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
+++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -125,7 +125,16 @@
      */
     private void buildChatMessageList(ChatRequest chatRequest){
         String sysPrompt;
-        chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
+        // 鐭妯″瀷鍚嶇О 濡傛灉鏄痝pt-image 鍒欐煡璇mage绫诲瀷妯″瀷 鑾峰彇妯″瀷鍚嶇О
+        if(chatRequest.getModel().equals("gpt-image")) {
+            chatModelVo = chatModelService.selectModelByCategory("image");
+            if (chatModelVo == null) {
+                log.error("鏈壘鍒癷mage绫诲瀷鐨勬ā鍨嬮厤缃�");
+                throw new IllegalStateException("鏈壘鍒癷mage绫诲瀷鐨勬ā鍨嬮厤缃�");
+            }
+        }else{
+            chatModelVo = chatModelService.selectModelByName(chatRequest.getModel());
+        }
         // 鑾峰彇瀵硅瘽娑堟伅鍒楄〃
         List<Message> messages = chatRequest.getMessages();
         // 鏌ヨ鍚戦噺搴撶浉鍏充俊鎭姞鍏ュ埌涓婁笅鏂�
diff --git a/script/sql/ruoyi-ai.sql b/script/sql/ruoyi-ai.sql
index ed5eb31..f4356fd 100644
--- a/script/sql/ruoyi-ai.sql
+++ b/script/sql/ruoyi-ai.sql
@@ -132,8 +132,8 @@
 INSERT INTO `chat_model` VALUES (1828324413241466881, '000000', 'vector', 'baai/bge-m3', 'baai/bge-m3', 0.01, '2', '1', NULL, 'https://api.ppinfra.com/v3/openai', 'sk-xx', NULL, 103, 1, '2024-08-27 14:51:23', 1, '2025-05-24 17:33:11', 'BGE-M3 鏄竴娆惧叿澶囧缁村害鑳藉姏鐨勬枃鏈祵鍏ユā鍨嬶紝鍙悓鏃跺疄鐜板瘑闆嗘绱€�佸鍚戦噺妫�绱㈠拰绋�鐤忔绱笁澶ф牳蹇冨姛鑳姐�傝妯″瀷璁捐涓婂吋瀹硅秴杩�100绉嶈瑷�锛屽苟鏀寔浠庣煭鍙ュ埌闀胯揪8192璇嶅厓鐨勯暱鏂囨湰绛夊绉嶈緭鍏ュ舰寮忋�傚湪璺ㄨ瑷�妫�绱换鍔′腑锛孊GE-M3灞曠幇鍑烘樉钁椾紭鍔匡紝鍏舵�ц兘鍦∕IRACL銆丮KQA绛夊浗闄呭熀鍑嗘祴璇曚腑浣嶅眳鍓嶅垪銆傛澶栵紝閽堝闀挎枃妗f绱㈠満鏅紝璇ユā鍨嬪湪MLDR銆丯arritiveQA绛夋暟鎹泦涓婄殑琛ㄧ幇鍚屾牱杈惧埌琛屼笟棰嗗厛姘村钩銆�');
 INSERT INTO `chat_model` VALUES (1859570229117022211, '000000', 'chat', 'deepseek/deepseek-v3-0324', 'deepseek/deepseek-v3-0324', 0.1, '1', '0', '', 'https://api.ppinfra.com/v3/openai/chat/completions', 'sk-xx', NULL, 103, 1, '2024-11-21 20:11:06', 1, '2025-05-24 17:56:22', 'DeepSeek V3 0324 鏄繁搴︽眰绱紙DeepSeek锛夊洟闃熸棗鑸扮骇瀵硅瘽妯″瀷绯诲垪鐨勬渶鏂扮増鏈紝閲囩敤娣峰悎涓撳锛圡ixture-of-Experts, MoE锛夋灦鏋勶紝鍙傛暟閲忚揪685B鍙傛暟銆�');
 INSERT INTO `chat_model` VALUES (1859570229117022212, '000000', 'chat', 'deepseek/deepseek-r1', 'deepseek/deepseek-r1', 0.1, '1', '0', '', 'https://api.ppinfra.com/v3/openai/chat/completions', 'sk-xx', NULL, 103, 1, '2024-11-21 20:11:06', 1, '2025-05-24 17:56:14', 'DeepSeek R1鏄疍eepSeek鍥㈤槦鍙戝竷鐨勬渶鏂板紑婧愭ā鍨嬶紝鍏峰闈炲父寮烘倣鐨勬帹鐞嗘�ц兘锛屽挨鍏跺湪鏁板銆佺紪绋嬪拰鎺ㄧ悊浠诲姟涓婅揪鍒颁簡涓嶰penAI鐨刼1妯″瀷鐩稿綋鐨勬按骞炽��');
-INSERT INTO `chat_model` VALUES (1926215622017482754, '000000', 'chat', 'gpt-4o-mini', 'gpt-4o-mini', 0.1, '1', '0', NULL, 'https://api.pandarobot.chat/v1/chat/completions/', 'sk-xx', NULL, 103, 1, '2025-05-24 17:56:06', 1, '2025-05-24 17:56:06', 'gpt 澶氭ā鎬佹ā鍨�');
-INSERT INTO `chat_model` VALUES (1926215622017482755, '000000', 'chat', 'gpt-4-all', 'gpt-4-all', 0.5, '2', '0', NULL, 'https://api.pandarobot.chat/v1/chat/completions/', 'sk-xx', NULL, 103, 1, '2025-05-24 17:56:06', 1, '2025-05-24 17:59:21', 'gpt 閫嗗悜澶氭ā鎬佹ā鍨�');
+INSERT INTO `chat_model` VALUES (1930184891812147202, '000000', 'image', 'qwen/qwen2.5-vl-72b-instruct', 'qwen/qwen2.5-vl-72b-instruct', 0.003, '2', '0', NULL, 'https://api.ppinfra.com/v3/openai/chat/completions', 'xx', NULL, 103, 1, '2025-06-04 16:48:34', 1, '2025-06-04 16:48:34', '瑙嗚妯″瀷');
+
 
 -- ----------------------------
 -- Table structure for chat_pay_order
diff --git a/script/sql/update/20250605.sql b/script/sql/update/20250605.sql
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/script/sql/update/20250605.sql
@@ -0,0 +1 @@
+

--
Gitblit v1.9.3