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:11:10 UTC
(camel) 01/01: Camel-AI: Langchain Embeddings component testing with Camel Milvus
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch milvus-supp-langchain
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 930ff7f9e870d1d788886b8357643f390628cadd
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Mon Mar 18 13:10:19 2024 +0100
Camel-AI: Langchain Embeddings component testing with Camel Milvus
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;
+ }
+ }
}