Explorar el Código

对接Deepseek

tsurumure hace 6 meses
padre
commit
3b61a537a1

+ 32 - 0
src/main/java/com/backendsys/modules/ai/deepSeek/controller/DeepSeekController.java

@@ -0,0 +1,32 @@
+package com.backendsys.modules.ai.deepSeek.controller;
+
+import com.backendsys.modules.ai.deepSeek.entity.DeepSeekParam;
+import com.backendsys.modules.ai.deepSeek.utils.OllamaUtil;
+import com.backendsys.modules.common.config.security.utils.SecurityUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@Validated
+@RestController
+@Tag(name = "DeepSeek")
+public class DeepSeekController {
+
+    @Autowired
+    private OllamaUtil ollamaUtil;
+
+    @Operation(summary = "提问")
+    @PostMapping("/api/deepSeek/ask")
+    public String ask(@Validated @RequestBody DeepSeekParam param) {
+        Long userId = SecurityUtil.getUserId();
+        System.out.println("userId = " + userId);
+
+        ollamaUtil.chatDeepSeek("deepseek-r1:1.5b", param.getQuestion(), userId);
+        return "ok";
+    }
+
+}

+ 12 - 0
src/main/java/com/backendsys/modules/ai/deepSeek/entity/DeepSeekParam.java

@@ -0,0 +1,12 @@
+package com.backendsys.modules.ai.deepSeek.entity;
+
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+
+@Data
+public class DeepSeekParam {
+
+    @NotEmpty(message="问题不能为空")
+    private String question;
+
+}

+ 104 - 0
src/main/java/com/backendsys/modules/ai/deepSeek/utils/OllamaUtil.java

@@ -0,0 +1,104 @@
+package com.backendsys.modules.ai.deepSeek.utils;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.backendsys.exception.CustException;
+import com.backendsys.modules.common.config.security.utils.SecurityUtil;
+import com.backendsys.modules.sse.entity.SseResponse;
+import com.backendsys.modules.sse.entity.SseResponseEnum;
+import com.backendsys.modules.sse.utils.SseUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+@Component
+public class OllamaUtil {
+
+    @Autowired
+    private SseUtil sseUtil;
+
+    @Value("${spring.application.name}")
+    private String APPLICATION_NAME;
+
+    @Value("${ai.config.deepseek.domain}")
+    private String DOMAIN;
+
+    /**
+     * 流式对话
+     */
+    public void chatDeepSeek(String model, String question, Long userId) {
+
+        System.out.println("提问: " + question);
+
+        // 创建一个 CompletableFuture 来执行异步任务
+        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+
+            String emitterKey = APPLICATION_NAME + "-userid-" + Convert.toStr(userId);
+
+            ObjectMapper objectMapper = new ObjectMapper();
+            try (CloseableHttpClient client = HttpClients.createDefault()) {
+
+                HttpPost request = new HttpPost(DOMAIN + "/api/generate");
+                Map<String, Object> requestMap = new HashMap<>();
+                requestMap.put("model", model);
+                requestMap.put("prompt", question);
+                requestMap.put("stream", true);
+
+                String requestBody = objectMapper.writeValueAsString(requestMap);
+                request.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));
+
+                try (CloseableHttpResponse response = client.execute(request);
+                     BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8)))
+                {
+                    String line;
+                    while ((line = reader.readLine()) != null) {
+                        // 每行数据可以是一个JSON对象,根据实际情况处理
+                        JSONObject resJson = JSONObject.parseObject(line);
+                        String responseContent = resJson.getString("response");
+
+                        System.out.println("content: " + responseContent);
+
+                        String dataStr = (new SseResponse(SseResponseEnum.DEEPSEEK, responseContent)).toJsonStr();
+                        sseUtil.send(emitterKey, dataStr);
+
+                    }
+
+                    String dataStr = (new SseResponse(SseResponseEnum.DEEPSEEK, "end")).toJsonStr();
+                    sseUtil.send(emitterKey, dataStr);
+
+                } catch (Exception e) {
+                    System.out.println("处理 Deepseek 请求时发生错误: " + e.getMessage());
+                    String dataStr = (new SseResponse(SseResponseEnum.DEEPSEEK, e.getMessage())).toJsonStr();
+                    sseUtil.send(emitterKey, dataStr);
+                    e.printStackTrace();
+                }
+            } catch (Exception e) {
+                System.out.println("处理 Deepseek 请求时发生错误: " + e.getMessage());
+                String dataStr = (new SseResponse(SseResponseEnum.DEEPSEEK, e.getMessage())).toJsonStr();
+                sseUtil.send(emitterKey, dataStr);
+                e.printStackTrace();
+            }
+
+        });
+
+    }
+}

+ 2 - 1
src/main/java/com/backendsys/modules/sse/entity/SseResponseEnum.java

@@ -5,7 +5,8 @@ public enum SseResponseEnum {
     CONNECT("connect", "建立连接"),
     DISCONNECT("disconnect", "断开连接"),
     NOTICE("notice", "通知"),
-    UPLOAD("upload", "上传");
+    UPLOAD("upload", "上传"),
+    DEEPSEEK("deepseek", "Deepseek");
 
     private String type;
     private String message;

+ 4 - 0
src/main/resources/application-local.yml

@@ -161,3 +161,7 @@ baidu:
     client-id: VtEo9VpnMzRzuefomiZcLv9W
     client-secret: VzHHaGdBnVM5cTrwG71x9N6ddVqTTPh8
 
+ai:
+  config:
+    deepseek:
+      domain: http://localhost:11434

+ 4 - 0
src/main/resources/application-prod.yml

@@ -153,3 +153,7 @@ baidu:
     client-id: VtEo9VpnMzRzuefomiZcLv9W
     client-secret: VzHHaGdBnVM5cTrwG71x9N6ddVqTTPh8
 
+ai:
+  config:
+    deepseek:
+      domain: http://localhost:11434