Parcourir la source

通过自然语言生成sql查询数据库

Gaokun Wang il y a 5 mois
Parent
commit
8a28e7eabb

+ 17 - 0
eco-ai/ai-ollama-api/src/main/java/org/eco/vip/ai/ollama/api/api/IOllamaApi.java

@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2025 GaoKunW
+ *
+ */
+
+package org.eco.vip.ai.ollama.api.api;
+
+
+/**
+ * @description IOllamaApi
+ *
+ * @author GaoKunW
+ * @date 2025/3/12 23:10
+ */
+public interface IOllamaApi {
+    String syncChat(String prompt);
+}

+ 30 - 0
eco-ai/ai-ollama-biz/src/main/java/org/eco/vip/ai/ollama/api/OllamaApi.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025 GaoKunW
+ *
+ */
+
+package org.eco.vip.ai.ollama.api;
+
+
+import jakarta.annotation.Resource;
+import org.eco.vip.ai.ollama.api.api.IOllamaApi;
+import org.eco.vip.ai.ollama.service.IOllamaService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @description IOllamaApi
+ *
+ * @author GaoKunW
+ * @date 2025/3/12 23:11
+ */
+@Service
+public class OllamaApi implements IOllamaApi {
+
+    @Resource
+    private IOllamaService ollamaService;
+
+    @Override
+    public String syncChat(String prompt) {
+        return ollamaService.syncChat(prompt);
+    }
+}

+ 3 - 26
eco-ai/ai-ollama-biz/src/main/java/org/eco/vip/ai/ollama/controller/OllamaController.java

@@ -6,39 +6,16 @@
 package org.eco.vip.ai.ollama.controller;
 
 
-import io.github.pigmesh.ai.deepseek.core.DeepSeekClient;
-import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse;
-import jakarta.annotation.Resource;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-import reactor.core.publisher.Flux;
-
-import java.util.Map;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
- * @description OllamaController
- *
  * @author GaoKunW
+ * @description OllamaController
  * @date 2025/3/12 17:53
  */
 @RestController
 @RequestMapping("/ai/ollama")
 public class OllamaController {
 
-    @Autowired
-    private DeepSeekClient deepSeekClient;
-    /**
-     * @description: 本地大模型问答
-     * @param: map
-     * @return String
-     **/
-    @PostMapping("/chat")
-    public String chat(@RequestBody Map<String, String> map) {
-
-        return "hello";
-    }
-    @GetMapping("/chat1")
-    public Flux<ChatCompletionResponse> chat(String prompt) {
-        return deepSeekClient.chatFluxCompletion(prompt);
-    }
 }

+ 17 - 0
eco-ai/ai-ollama-biz/src/main/java/org/eco/vip/ai/ollama/service/IOllamaService.java

@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2025 GaoKunW
+ *
+ */
+
+package org.eco.vip.ai.ollama.service;
+
+
+/**
+ * @description IOllamaService
+ *
+ * @author GaoKunW
+ * @date 2025/3/12 23:02
+ */
+public interface IOllamaService {
+    String syncChat(String prompt);
+}

+ 39 - 0
eco-ai/ai-ollama-biz/src/main/java/org/eco/vip/ai/ollama/service/OllamaService.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2025 GaoKunW
+ *
+ */
+
+package org.eco.vip.ai.ollama.service;
+
+
+import io.github.pigmesh.ai.deepseek.core.DeepSeekClient;
+import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionChoice;
+import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionRequest;
+import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+/**
+ * @description OllamaService
+ *
+ * @author GaoKunW
+ * @date 2025/3/12 23:02
+ */
+@Service
+public class OllamaService implements IOllamaService {
+
+    @Resource
+    private DeepSeekClient deepSeekClient;
+
+    @Override
+    public String syncChat(String prompt) {
+        ChatCompletionRequest request = ChatCompletionRequest.builder()
+                // 根据渠道模型名称动态修改这个参数
+                .model("qwen2.5:3b")
+//                .addAssistantMessage("我是一个sql生成专家,根据用户需求,生成mysql可执行的sql语句,只输出sql语句不需要任何格式")
+                .addUserMessage(prompt).build();
+        ChatCompletionResponse response = deepSeekClient.chatCompletion(request).execute();
+        ChatCompletionChoice completionChoice = response.choices().getFirst();
+        return completionChoice.message().content();
+    }
+}

+ 5 - 0
eco-ai/ai-text-sql-biz/pom.xml

@@ -20,6 +20,11 @@
             <artifactId>ai-text-sql-api</artifactId>
             <version>${revision}</version>
         </dependency>
+        <dependency>
+            <groupId>org.eco.vip</groupId>
+            <artifactId>ai-ollama-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
         <dependency>
             <groupId>org.eco.vip</groupId>
             <artifactId>com-web</artifactId>

+ 8 - 7
eco-ai/ai-text-sql-biz/src/main/java/org/eco/vip/ai/text2sql/controller/ChatSqlController.java

@@ -28,15 +28,15 @@ public class ChatSqlController {
     private IText2SqlService text2SqlService;
 
     /**
-     * @description:
+     * @description: text2sql
      * @param map 问题
      * @return List<Map<String,Object>>
      **/
-    @GetMapping("/chat")
+    @PostMapping("/chat")
     public JSONArray chatSql(@RequestBody Map<String, String> map) {
         String question = map.get("question");
         if (StrUtil.isNotBlank(question)) {
-            return text2SqlService.getCommentData(question);
+            return text2SqlService.getAnswer(question);
         }
         return null;
     }
@@ -46,13 +46,14 @@ public class ChatSqlController {
         return text2SqlService.executeSql("show create table sys_dept");
     }
 
-    @GetMapping("/test1")
-    public List<Map<String, Object>> test1() {
-        return text2SqlService.tableNameByNl("");
+    @PostMapping("/getTableName")
+    public String test1(@RequestBody Map<String, String> map) {
+        String question = map.get("question");
+        return text2SqlService.tableNameByNl(question);
     }
 
     @PostMapping("/test2")
     public JSONArray test2(@RequestBody Map<String, String> map) {
-        return text2SqlService.getCommentData("");
+        return null;
     }
 }

+ 3 - 1
eco-ai/ai-text-sql-biz/src/main/java/org/eco/vip/ai/text2sql/mapper/Text2SqlMapper.java

@@ -23,9 +23,11 @@ import java.util.Map;
 @Mapper
 public interface Text2SqlMapper {
 
-//    @Select("${sqlText}")
     List<Map<String, Object>> executeSql(@Param("sqlText") String sqlText);
 
+    @Select("show create table ${tableName} ")
+    Map<String, String> selectTableDdl(@Param("tableName") String tableName);
+
     @Select("select column_name as name, column_comment as comment  from information_schema.COLUMNS where table_schema = #{schema} and table_name = #{tableName}")
     List<CommentVo> selectCommentsByMysql(@Param("schema") String schema, @Param("tableName") String tableName);
 

+ 10 - 2
eco-ai/ai-text-sql-biz/src/main/java/org/eco/vip/ai/text2sql/service/IText2SqlService.java

@@ -33,7 +33,7 @@ public interface IText2SqlService {
      *
      * @return List<Map<Object,Object>>
      **/
-    List<Map<String, Object>> tableNameByNl(String question);
+    String tableNameByNl(String question);
 
     /**
      * @description: 通过表查询字段注释
@@ -43,10 +43,18 @@ public interface IText2SqlService {
      **/
     List<CommentVo> commentByTableName(String schema, String tableName);
 
+    /**
+     * @description: 获取带字段注释的表数据
+     * @param mapList 数据
+     * @param tableNames 表头信息
+     * @return List<Map<Object,Object>>
+     **/
+    JSONArray getCommentData(List<Map<String, Object>> mapList, List<CommentVo> tableNames);
+
     /**
      * @description: 获取带字段注释的表数据
      * @param question 问题
      * @return List<Map<Object,Object>>
      **/
-    JSONArray getCommentData(String question);
+    JSONArray getAnswer(String question);
 }

+ 41 - 5
eco-ai/ai-text-sql-biz/src/main/java/org/eco/vip/ai/text2sql/service/Text2SqlService.java

@@ -10,13 +10,17 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONArray;
 import jakarta.annotation.Resource;
+import org.eco.vip.ai.ollama.api.api.IOllamaApi;
 import org.eco.vip.ai.text2sql.domain.CommentVo;
 import org.eco.vip.ai.text2sql.mapper.Text2SqlMapper;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * @description Text2SqlService
@@ -29,14 +33,17 @@ public class Text2SqlService implements IText2SqlService {
     @Resource
     private Text2SqlMapper text2SqlMapper;
 
+    @Resource
+    private IOllamaApi ollamaApi;
+
     @Override
     public List<Map<String, Object>> executeSql(String sql) {
         return text2SqlMapper.executeSql(sql);
     }
 
     @Override
-    public List<Map<String, Object>> tableNameByNl(String sql) {
-        return text2SqlMapper.executeSql(sql);
+    public String tableNameByNl(String question) {
+        return this.extractTableName(question);
     }
 
     @Override
@@ -45,9 +52,7 @@ public class Text2SqlService implements IText2SqlService {
     }
 
     @Override
-    public JSONArray getCommentData(String question) {
-        List<Map<String, Object>> mapList = text2SqlMapper.executeSql("select * from sys_user");
-        List<CommentVo> tableNames = text2SqlMapper.selectCommentsByMysql("eco-boot", "sys_user");
+    public JSONArray getCommentData(List<Map<String, Object>> mapList, List<CommentVo> tableNames) {
         JSONArray jsonArray = new JSONArray();
         Map<String, Object> commentMap = new HashMap<>();
         for (Map<String, Object> map : mapList) {
@@ -59,4 +64,35 @@ public class Text2SqlService implements IText2SqlService {
         }
         return jsonArray;
     }
+
+    @Override
+    public JSONArray getAnswer(String question) {
+        String tableName = this.tableNameByNl(question);
+        Map<String, String> map = text2SqlMapper.selectTableDdl(tableName);
+        String ddl = map.get("create table");
+        String content = ollamaApi.syncChat(ddl + "\n" + question + ",根据需求生成Mysql的查询SQL,不要需求外的条件,只输出sql语句不需要任何格式样式,就是一串sql");
+        List<Map<String, Object>> mapList = text2SqlMapper.executeSql(content);
+        List<CommentVo> tableNames = text2SqlMapper.selectCommentsByMysql("eco-boot", tableName);
+        return this.getCommentData(mapList, tableNames);
+    }
+
+    private String extractTableName(String query) {
+        // 使用LinkedHashMap保持插入顺序,确保匹配优先级
+        Map<String, String> keywordMapping = new LinkedHashMap<>();
+        keywordMapping.put("部门表|部门信息", "sys_dept");
+        keywordMapping.put("用户|人员|姓名|账号|性别", "sys_user");
+
+        // 预处理:去除标点符号和非文字字符
+        String cleanedQuery = query.replaceAll("[^\\w\\u4e00-\\u9fff]", "");
+
+        // 遍历映射进行正则匹配
+        for (Map.Entry<String, String> entry : keywordMapping.entrySet()) {
+            Pattern pattern = Pattern.compile(entry.getKey());
+            Matcher matcher = pattern.matcher(cleanedQuery);
+            if (matcher.find()) {
+                return entry.getValue();
+            }
+        }
+        return "unknown_table";
+    }
 }

+ 1 - 1
eco-bom/pom.xml

@@ -28,6 +28,7 @@
         <jackson.version>2.18.3</jackson.version>
         <easy-trans.version>3.0.6</easy-trans.version>
         <deepseek4j.version>1.4.5</deepseek4j.version>
+        <milvus.version>2.3.5</milvus.version>
     </properties>
 
     <!-- 全局的依赖配置-->
@@ -124,7 +125,6 @@
                 <artifactId>deepseek-spring-boot-starter</artifactId>
                 <version>${deepseek4j.version}</version>
             </dependency>
-
         </dependencies>
     </dependencyManagement>
 

+ 6 - 1
eco-start/src/main/resources/application.yml

@@ -113,4 +113,9 @@ logging:
 deepseek:
   api-key: local-ollama  # 必填项:你的 API 密钥
   model: qwen2.5:3b
-  base-url: http://127.0.0.1:11434/v1  # 可选,默认为官方 API 地址
+  base-url: http://127.0.0.1:11434/v1  # 可选,默认为官方 API 地址
+# 向量模型链接信息
+embedding:
+  api-key: ${deepseek.api-key}
+  base-url: ${deepseek.base-url}
+  model: bge-m3:latest