Gaokun Wang 4 сар өмнө
parent
commit
b0436c7348

+ 5 - 0
eco-ai/ai-knowledge-biz/pom.xml

@@ -36,6 +36,11 @@
             <artifactId>spring-ai-milvus-store</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.eco.vip</groupId>
+            <artifactId>ai-ollama-biz</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 45 - 0
eco-ai/ai-knowledge-biz/src/main/java/org/eco/vip/ai/knowledge/config/MilvusConfig.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2025 GaoKunW
+ *
+ */
+
+package org.eco.vip.ai.knowledge.config;
+
+
+import io.milvus.client.MilvusServiceClient;
+import io.milvus.param.ConnectParam;
+import io.milvus.v2.client.ConnectConfig;
+import io.milvus.v2.client.MilvusClientV2;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * @description MilvusConfig
+ *
+ * @author GaoKunW
+ * @date 2025/3/18 15:10
+ */
+@AutoConfiguration
+public class MilvusConfig {
+    @Value("${milvus.host}")
+    private String host;
+
+    @Value("${milvus.port}")
+    private Integer port;
+
+    @Bean
+    public MilvusClientV2 milvusClientV2() {
+        String uri = "http://" + this.host + ":" + this.port.toString();
+        return new MilvusClientV2(ConnectConfig.builder().uri(uri).build());
+    }
+
+    @Bean
+    public MilvusServiceClient milvusServiceClient() {
+        ConnectParam connectParam = ConnectParam.newBuilder()
+                .withHost(host)
+                .withPort(port)
+                .build();
+        return new MilvusServiceClient(connectParam);
+    }
+}

+ 22 - 4
eco-ai/ai-knowledge-biz/src/main/java/org/eco/vip/ai/knowledge/controller/KnowledgeController.java

@@ -6,13 +6,17 @@
 package org.eco.vip.ai.knowledge.controller;
 
 
+import cn.hutool.core.lang.Assert;
+import com.alibaba.fastjson.JSON;
+import io.milvus.v2.service.vector.response.InsertResp;
 import jakarta.annotation.Resource;
 import org.eco.vip.ai.knowledge.domain.knowledge.Knowledge;
 import org.eco.vip.ai.knowledge.service.IKnowledgeService;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.eco.vip.ai.knowledge.service.IMilvusService;
+import org.springframework.ai.ollama.OllamaEmbeddingModel;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
 
 /**
  * @description KnowledgeController
@@ -27,6 +31,20 @@ public class KnowledgeController {
     @Resource
     private IKnowledgeService knowledgeService;
 
+    @Resource
+    private OllamaEmbeddingModel ollamaEmbeddingModel;
+
+    @Resource
+    private IMilvusService milvusService;
+
+    @GetMapping("/addCustomRagData")
+    public InsertResp addCustomRagData(@RequestParam String text) {
+        Assert.notNull(text, "text不能为空");
+        float[] embed = ollamaEmbeddingModel.embed(text);
+        // 插入数据
+        InsertResp insert = milvusService.insert(embed, text, JSON.toJSONString(new HashMap<>().put("custom", text)), "custom");
+        return insert;
+    }
 
     @PostMapping("/save")
     public Void save(@RequestBody Knowledge bo) {

+ 33 - 0
eco-ai/ai-knowledge-biz/src/main/java/org/eco/vip/ai/knowledge/service/IMilvusService.java

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2025 GaoKunW
+ *
+ */
+
+package org.eco.vip.ai.knowledge.service;
+
+
+import io.milvus.v2.service.vector.response.InsertResp;
+
+/**
+ * @description IMilvusService
+ *
+ * @author GaoKunW
+ * @date 2025/3/18 15:21
+ */
+public interface IMilvusService {
+
+    /**
+     * 检查集合是否存在,不存在则创建集合
+     */
+    void hasCollection();
+
+    /**
+     * 插入数据
+     *
+     * @param vectorParam 向量参数
+     * @param text        文本
+     * @param metadata    元数据
+     * @param fileName    文件名
+     */
+    InsertResp insert(float[] vectorParam, String text, String metadata, String fileName);
+}

+ 163 - 0
eco-ai/ai-knowledge-biz/src/main/java/org/eco/vip/ai/knowledge/service/MilvusService.java

@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2025 GaoKunW
+ *
+ */
+
+package org.eco.vip.ai.knowledge.service;
+
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.nimbusds.jose.shaded.gson.Gson;
+import io.milvus.v2.client.MilvusClientV2;
+import io.milvus.v2.common.DataType;
+import io.milvus.v2.common.IndexParam;
+import io.milvus.v2.service.collection.request.AddFieldReq;
+import io.milvus.v2.service.collection.request.CreateCollectionReq;
+import io.milvus.v2.service.collection.request.HasCollectionReq;
+import io.milvus.v2.service.index.request.CreateIndexReq;
+import io.milvus.v2.service.vector.request.InsertReq;
+import io.milvus.v2.service.vector.response.InsertResp;
+import jakarta.annotation.Resource;
+import lombok.RequiredArgsConstructor;
+import org.eco.vip.ai.knowledge.constant.MilvusConstant;
+import org.springframework.ai.ollama.OllamaEmbeddingModel;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * @author GaoKunW
+ * @description MilvusService
+ * @date 2025/3/18 15:23
+ */
+@Service
+@RequiredArgsConstructor
+public class MilvusService implements IMilvusService {
+
+    @Resource
+    private MilvusClientV2 milvusClientV2;
+
+    @Resource
+    private OllamaEmbeddingModel ollamaEmbeddingModel;
+
+    //    private final
+    @Override
+    public void hasCollection() {
+        Boolean b = milvusClientV2.hasCollection(HasCollectionReq.builder().collectionName(MilvusConstant.COLLECTION_NAME).build());
+        if (!b) {
+            this.createCollection();
+        }
+    }
+
+    @Override
+    public InsertResp insert(float[] vectorParam, String text, String metadata, String fileName) {
+        // 校验集合是否存在
+        this.hasCollection();
+        JSONObject jsonObject = new JSONObject();
+        // 数组转换成JsonElement
+        // 使用 Stream API 转换
+        List<Float> floatList = IntStream.range(0, vectorParam.length)
+                .mapToObj(i -> vectorParam[i])
+                .toList();
+        jsonObject.put(MilvusConstant.Field.FEATURE, floatList);
+        jsonObject.put(MilvusConstant.Field.TEXT, text);
+        jsonObject.put(MilvusConstant.Field.METADATA, metadata);
+        jsonObject.put(MilvusConstant.Field.FILE_NAME, fileName);
+        InsertReq insertReq = InsertReq.builder()
+                // 集合名称
+                .collectionName(MilvusConstant.COLLECTION_NAME)
+                .data(Collections.singletonList(jsonObject))
+                .build();
+
+        return milvusClientV2.insert(insertReq);
+    }
+
+    /**
+     * 创建集合
+     */
+    public void createCollection() {
+        // 创建字段
+        CreateCollectionReq.CollectionSchema schema = milvusClientV2.createSchema();
+        // 创建主键字段
+        schema.addField(AddFieldReq.builder()
+                // 字段名
+                .fieldName(MilvusConstant.Field.ID)
+                // 字段描述
+                .description("主键ID")
+                // 字段类型
+                .dataType(DataType.Int64)
+                // 是否为主键
+                .isPrimaryKey(true)
+                // 设置主键自增
+                .autoID(true)
+                .build());
+        schema.addField(AddFieldReq.builder()
+                // 字段名
+                .fieldName(MilvusConstant.Field.FILE_NAME)
+                // 字段描述
+                .description("文件名")
+                // 字段类型
+                .dataType(DataType.VarChar)
+                .build());
+        // 创建特征向量字段
+        schema.addField(AddFieldReq.builder()
+                // 字段名
+                .fieldName(MilvusConstant.Field.FEATURE)
+                // 字段描述
+                .description("特征向量")
+                // 字段类型
+                .dataType(DataType.FloatVector)
+                // 设置向量维度
+                .dimension(MilvusConstant.FEATURE_DIM)
+                .build());
+        schema.addField(AddFieldReq.builder()
+                // 字段名
+                .fieldName(MilvusConstant.Field.TEXT)
+                // 字段描述
+                .description("文本")
+                // 字段类型
+                .dataType(DataType.VarChar)
+                .build());
+        schema.addField(AddFieldReq.builder()
+                // 字段名
+                .fieldName(MilvusConstant.Field.METADATA)
+                // 字段描述
+                .description("元数据")
+                // 字段类型
+                .dataType(DataType.VarChar)
+                .build());
+        // 创建集合
+        CreateCollectionReq collectionReq = CreateCollectionReq.builder()
+                // 集合名称
+                .collectionName(MilvusConstant.COLLECTION_NAME)
+                // 集合描述
+                .description("自定义知识库")
+                // 集合字段
+                .collectionSchema(schema)
+                // 分片数量
+                .numShards(MilvusConstant.SHARDS_NUM)
+                .build();
+        milvusClientV2.createCollection(collectionReq);
+
+        // 创建索引
+        IndexParam indexParam = IndexParam.builder()
+                // 索引字段名
+                .fieldName(MilvusConstant.Field.FEATURE)
+                // 索引类型
+                .indexType(IndexParam.IndexType.IVF_FLAT)
+                // 索引距离度量
+                .metricType(IndexParam.MetricType.COSINE)
+                .build();
+        CreateIndexReq createIndexReq = CreateIndexReq.builder()
+                .collectionName(MilvusConstant.COLLECTION_NAME)
+                .indexParams(Collections.singletonList(indexParam))
+                .build();
+
+        milvusClientV2.createIndex(createIndexReq);
+    }
+}

+ 0 - 1
eco-ai/ai-knowledge-biz/src/main/java/org/eco/vip/ai/knowledge/vectorstore/MilvusVectorStores.java

@@ -33,7 +33,6 @@ public class MilvusVectorStores implements VectorStores {
     private void createSchema(String kid) {
         CreateCollectionReq.CollectionSchema schema = milvusServiceClient.createSchema();
 
-
         schema.addField(AddFieldReq.builder()
                 .fieldName("row_id")
                 .description("主键ID")

+ 1 - 0
eco-ai/ai-knowledge-biz/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -0,0 +1 @@
+org.eco.vip.ai.knowledge.config.MilvusConfig

+ 5 - 36
eco-ai/ai-ollama-biz/src/main/java/org/eco/vip/ai/ollama/service/OllamaService.java

@@ -12,7 +12,11 @@ import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.eco.vip.text2sql.api.IText2sqlApi;
 import org.eco.vip.text2sql.domain.ContentVo;
+import org.springframework.ai.autoconfigure.ollama.OllamaChatProperties;
+import org.springframework.ai.chat.prompt.Prompt;
 import org.springframework.ai.ollama.OllamaChatModel;
+import org.springframework.ai.ollama.api.OllamaModel;
+import org.springframework.ai.ollama.api.OllamaOptions;
 import org.springframework.stereotype.Service;
 import reactor.core.publisher.Flux;
 
@@ -35,44 +39,9 @@ public class OllamaService implements IOllamaService {
     @Resource
     private OllamaChatModel ollamaChatModel;
 
-    public String convertJsonArrayToMd(JSONArray array) {
-        if (array.isEmpty()) {
-            return "";
-        }
-
-        // 2. 提取表头(假设所有对象的键相同)
-        JSONObject firstObj = array.getJSONObject(0);
-        String[] headers = firstObj.keySet().toArray(new String[0]);
-
-        // 3. 构建Markdown表格
-        StringBuilder md = new StringBuilder();
-
-        // 3.1 表头行
-        md.append("|").append(String.join("|", headers)).append("|\n");
-
-        // 3.2 分隔线行(左对齐)
-        md.append("|").append(String.join("|", Arrays.stream(headers)
-                .map(h -> "---")
-                .toArray(String[]::new))).append("|\n");
-
-        // 3.3 数据行
-        for (int i = 0; i < array.size(); i++) {
-            JSONObject obj = array.getJSONObject(i);
-            String[] row = Arrays.stream(headers)
-                    // 空值默认显示为 "-"
-                    .map(key -> obj.getStr(key, "-")
-                            .replace("|", "\\|")
-                            .replace("\n", "<br>")
-                    )
-                    .toArray(String[]::new);
-            md.append("|").append(String.join("|", row)).append("|\n");
-        }
-
-        return md.toString();
-    }
-
     @Override
     public Flux<String> chatStream(String prompt) {
+//        ollamaChatModel.setObservationConvention(ChatObservationConvention.LLAMA2);
         return ollamaChatModel.stream(prompt);
     }
 

+ 6 - 0
eco-bom/pom.xml

@@ -80,6 +80,12 @@
                 <artifactId>eco-ai</artifactId>
                 <version>${revision}</version>
             </dependency>
+            <!-- com-core -->
+            <dependency>
+                <groupId>org.eco.vip</groupId>
+                <artifactId>ai-ollama-biz</artifactId>
+                <version>${revision}</version>
+            </dependency>
 
             <!-- lombok -->
             <dependency>

+ 0 - 6
eco-start/pom.xml

@@ -31,12 +31,6 @@
             <groupId>org.eco.vip</groupId>
             <artifactId>ai-knowledge-biz</artifactId>
             <version>${revision}</version>
-            <exclusions>
-                <exclusion>
-                    <artifactId>spring-ai-milvus-store</artifactId>
-                    <groupId>org.springframework.ai</groupId>
-                </exclusion>
-            </exclusions>
         </dependency>
     </dependencies>
 

+ 9 - 0
eco-start/src/main/resources/application.yml

@@ -41,6 +41,10 @@ spring:
         options:
           # 选用模型
           model: qwen2.5:1.5b
+      # 嵌入模型配置
+      embedding:
+        options:
+          model: bge-m3:latest
 
 # 开发环境配置
 server:
@@ -128,6 +132,11 @@ embedding:
   base-url: ${deepseek.base-url}
   model: bge-m3:latest
 
+# Milvus配置
+milvus:
+  host: 127.0.0.1
+  port: 19530
+
 --- #ai-表名映射
 table:
   mappings: