From 0a73cb4e1725592470d446a9d2a09e95e27868ca Mon Sep 17 00:00:00 2001
From: 酒亦 <mobaitongxue@163.com>
Date: 星期四, 05 六月 2025 12:05:28 +0800
Subject: [PATCH] 上传图片支持使用后台image分类下通义千问模型

---
 /dev/null                                                                                            |   75 ------------------
 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageQianwenServiceImpl.java |  140 +++++++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+), 75 deletions(-)

diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageOpenAiServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageOpenAiServiceImpl.java
deleted file mode 100644
index 11b4c1e..0000000
--- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageOpenAiServiceImpl.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.ruoyi.chat.service.chat.impl;
-
-import io.modelcontextprotocol.client.McpSyncClient;
-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.ai.chat.client.ChatClient;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-
-import java.util.List;
-
-/**
- * 鍥剧墖璇嗗埆妯″瀷
- */
-@Service
-@Slf4j
-public class ImageOpenAiServiceImpl implements IChatService {
-
-    @Autowired
-    private IChatModelService chatModelService;
-
-    private final ChatClient chatClient;
-
-    public ImageOpenAiServiceImpl(ChatClient.Builder chatClientBuilder) {
-        this.chatClient = chatClientBuilder.build();
-    }
-
-    @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/ImageQianwenServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageQianwenServiceImpl.java
new file mode 100644
index 0000000..aefd62f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/ImageQianwenServiceImpl.java
@@ -0,0 +1,140 @@
+package org.ruoyi.chat.service.chat.impl;
+
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
+import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
+import com.alibaba.dashscope.common.MultiModalMessage;
+import com.alibaba.dashscope.common.ResultCallback;
+import com.alibaba.dashscope.common.Role;
+import com.alibaba.dashscope.exception.NoApiKeyException;
+import com.alibaba.dashscope.exception.UploadFileException;
+import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel;
+import dev.langchain4j.community.model.dashscope.QwenStreamingResponseBuilder;
+import dev.langchain4j.data.message.ChatMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.internal.Utils;
+import dev.langchain4j.model.chat.StreamingChatModel;
+import dev.langchain4j.model.chat.response.ChatResponse;
+import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
+import io.modelcontextprotocol.client.McpSyncClient;
+import io.reactivex.Flowable;
+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.ai.chat.client.ChatClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.*;
+
+/**
+ * 鍥剧墖璇嗗埆妯″瀷
+ */
+@Service
+@Slf4j
+public class ImageQianwenServiceImpl 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 String getCategory() {
+        return ChatModeType.IMAGE.getCode();
+    }
+}

--
Gitblit v1.9.3