You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2024/03/18 12:28:49 UTC

(camel) branch main updated: Camel-AI: Langchain Embeddings component testing with Camel Milvus (#13517)

This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 721b135294d Camel-AI: Langchain Embeddings component testing with Camel Milvus (#13517)
721b135294d is described below

commit 721b135294da296d65fe17b0b20d0a22347ebea5
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Mon Mar 18 13:28:42 2024 +0100

    Camel-AI: Langchain Embeddings component testing with Camel Milvus (#13517)
    
    Signed-off-by: Andrea Cosentino <an...@gmail.com>
---
 .../camel-ai/camel-langchain-embeddings/pom.xml    |  12 ++
 ...LangchainEmbeddingsComponentMilvusTargetIT.java | 191 +++++++++++++++++++++
 .../embeddings/LangchainEmbeddingsTestSupport.java |  23 +++
 3 files changed, 226 insertions(+)

diff --git a/components/camel-ai/camel-langchain-embeddings/pom.xml b/components/camel-ai/camel-langchain-embeddings/pom.xml
index d4a68ff9704..09ae4d316fe 100644
--- a/components/camel-ai/camel-langchain-embeddings/pom.xml
+++ b/components/camel-ai/camel-langchain-embeddings/pom.xml
@@ -57,6 +57,11 @@
       <artifactId>camel-qdrant</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-milvus</artifactId>
+      <scope>test</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.camel</groupId>
@@ -98,6 +103,13 @@
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test-infra-milvus</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
 
   </dependencies>
 </project>
diff --git a/components/camel-ai/camel-langchain-embeddings/src/test/java/org/apache/camel/component/langchain/embeddings/LangchainEmbeddingsComponentMilvusTargetIT.java b/components/camel-ai/camel-langchain-embeddings/src/test/java/org/apache/camel/component/langchain/embeddings/LangchainEmbeddingsComponentMilvusTargetIT.java
new file mode 100644
index 00000000000..728914d789e
--- /dev/null
+++ b/components/camel-ai/camel-langchain-embeddings/src/test/java/org/apache/camel/component/langchain/embeddings/LangchainEmbeddingsComponentMilvusTargetIT.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain.embeddings;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import dev.langchain4j.model.embedding.AllMiniLmL6V2EmbeddingModel;
+import io.milvus.common.clientenum.ConsistencyLevelEnum;
+import io.milvus.grpc.DataType;
+import io.milvus.param.IndexType;
+import io.milvus.param.MetricType;
+import io.milvus.param.collection.CreateCollectionParam;
+import io.milvus.param.collection.FieldType;
+import io.milvus.param.highlevel.dml.SearchSimpleParam;
+import io.milvus.param.highlevel.dml.response.SearchResponse;
+import io.milvus.param.index.CreateIndexParam;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.milvus.Milvus;
+import org.apache.camel.component.milvus.MilvusAction;
+import org.apache.camel.component.milvus.MilvusComponent;
+import org.apache.camel.test.infra.milvus.services.MilvusService;
+import org.apache.camel.test.infra.milvus.services.MilvusServiceFactory;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.assertj.core.util.Lists;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class LangchainEmbeddingsComponentMilvusTargetIT extends CamelTestSupport {
+    public static final String MILVUS_URI = "milvus:embeddings";
+
+    @RegisterExtension
+    static MilvusService MILVUS = MilvusServiceFactory.createSingletonService();
+
+    @Override
+
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+
+        var milvus = context.getComponent(Milvus.SCHEME, MilvusComponent.class);
+        URL url = new URL(MILVUS.getMilvusEndpointUrl());
+        milvus.getConfiguration().setHost(url.getHost());
+        milvus.getConfiguration().setPort(url.getPort());
+
+        context.getRegistry().bind("embedding-model", new AllMiniLmL6V2EmbeddingModel());
+
+        return context;
+    }
+
+    @Test
+    @Order(1)
+    public void createCollectionAndIndex() {
+        FieldType fieldType1 = FieldType.newBuilder()
+                .withName("userID")
+                .withDescription("user identification")
+                .withDataType(DataType.Int64)
+                .withPrimaryKey(true)
+                .withAutoID(true)
+                .build();
+
+        FieldType fieldType2 = FieldType.newBuilder()
+                .withName("vector")
+                .withDescription("face embedding")
+                .withDataType(DataType.FloatVector)
+                .withDimension(384)
+                .build();
+
+        CreateCollectionParam createCollectionReq = CreateCollectionParam.newBuilder()
+                .withCollectionName("embeddings")
+                .withDescription("customer info")
+                .withShardsNum(2)
+                .withEnableDynamicField(false)
+                .addFieldType(fieldType1)
+                .addFieldType(fieldType2)
+                .build();
+
+        Exchange result = fluentTemplate.to(MILVUS_URI)
+                .withHeader(Milvus.Headers.ACTION, MilvusAction.CREATE_COLLECTION)
+                .withBody(
+                        createCollectionReq)
+                .request(Exchange.class);
+
+        assertThat(result).isNotNull();
+        assertThat(result.getException()).isNull();
+
+        CreateIndexParam createVectorIndexParam = CreateIndexParam.newBuilder()
+                .withCollectionName("embeddings")
+                .withFieldName("vector")
+                .withIndexName("vectorIndex")
+                .withIndexType(IndexType.IVF_FLAT)
+                .withMetricType(MetricType.L2)
+                .withExtraParam("{\"nlist\":128}")
+                .withSyncMode(Boolean.TRUE)
+                .build();
+
+        result = fluentTemplate.to(MILVUS_URI)
+                .withHeader(Milvus.Headers.ACTION, MilvusAction.CREATE_INDEX)
+                .withBody(
+                        createVectorIndexParam)
+                .request(Exchange.class);
+
+        assertThat(result).isNotNull();
+        assertThat(result.getException()).isNull();
+    }
+
+    @Test
+    @Order(2)
+    public void insert() {
+
+        Exchange result = fluentTemplate.to("direct:in")
+                .withBody("hi")
+                .request(Exchange.class);
+
+        assertThat(result).isNotNull();
+        assertThat(result.getException()).isNull();
+    }
+
+    @Test
+    @Order(3)
+    public void search() {
+        SearchSimpleParam searchSimpleParam = SearchSimpleParam.newBuilder()
+                .withCollectionName("embeddings")
+                .withVectors(generateFloatVector())
+                .withFilter("userID>=1")
+                .withLimit(100L)
+                .withOffset(0L)
+                .withOutputFields(Lists.newArrayList("userID"))
+                .withConsistencyLevel(ConsistencyLevelEnum.STRONG)
+                .build();
+        Exchange result = fluentTemplate.to(MILVUS_URI)
+                .withHeader(Milvus.Headers.ACTION, MilvusAction.SEARCH)
+                .withBody(searchSimpleParam)
+                .request(Exchange.class);
+
+        assertThat(result).isNotNull();
+        assertThat(result.getException()).isNull();
+
+        assertThat(result.getIn().getBody()).isInstanceOfSatisfying(SearchResponse.class,
+                c -> assertThat(c.rowRecords.size() == 1));
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:in")
+                        .to("langchain-embeddings:test")
+                        .bean(LangchainEmbeddingsTestSupport.AsInsertParam.class)
+                        .setHeader(Milvus.Headers.ACTION).constant(MilvusAction.INSERT)
+                        .bean(LangchainEmbeddingsTestSupport.AsInsertParam.class)
+                        .to(MILVUS_URI);
+            }
+        };
+    }
+
+    private List<Float> generateFloatVector() {
+        Random ran = new Random();
+        List<Float> vector = new ArrayList<>();
+        for (int i = 0; i < 384; ++i) {
+            vector.add(ran.nextFloat());
+        }
+        return vector;
+    }
+}
diff --git a/components/camel-ai/camel-langchain-embeddings/src/test/java/org/apache/camel/component/langchain/embeddings/LangchainEmbeddingsTestSupport.java b/components/camel-ai/camel-langchain-embeddings/src/test/java/org/apache/camel/component/langchain/embeddings/LangchainEmbeddingsTestSupport.java
index 16b22347c8a..326c456ef80 100644
--- a/components/camel-ai/camel-langchain-embeddings/src/test/java/org/apache/camel/component/langchain/embeddings/LangchainEmbeddingsTestSupport.java
+++ b/components/camel-ai/camel-langchain-embeddings/src/test/java/org/apache/camel/component/langchain/embeddings/LangchainEmbeddingsTestSupport.java
@@ -16,8 +16,13 @@
  */
 package org.apache.camel.component.langchain.embeddings;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.protobuf.InvalidProtocolBufferException;
 import dev.langchain4j.data.embedding.Embedding;
 import dev.langchain4j.data.segment.TextSegment;
+import io.milvus.param.dml.InsertParam;
 import io.qdrant.client.ValueFactory;
 import io.qdrant.client.VectorsFactory;
 import io.qdrant.client.grpc.Points;
@@ -55,4 +60,22 @@ public class LangchainEmbeddingsTestSupport {
             return builder.build();
         }
     }
+
+    public static class AsInsertParam {
+        @Handler
+        public InsertParam AsInsertParam(Exchange e) throws InvalidProtocolBufferException {
+            Embedding embedding = e.getMessage().getHeader(LangchainEmbeddings.Headers.VECTOR, Embedding.class);
+            List<InsertParam.Field> fields = new ArrayList<>();
+            ArrayList list = new ArrayList<>();
+            list.add(embedding.vectorAsList());
+            fields.add(new InsertParam.Field("vector", list));
+
+            InsertParam insertParam = InsertParam.newBuilder()
+                    .withCollectionName("embeddings")
+                    .withFields(fields)
+                    .build();
+
+            return insertParam;
+        }
+    }
 }