diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml index e62328dcf2525..a250592fbbd46 100644 --- a/bom/camel-bom/pom.xml +++ b/bom/camel-bom/pom.xml @@ -1297,6 +1297,11 @@ camel-langchain4j-chat 4.7.0-SNAPSHOT + + org.apache.camel + camel-langchain4j-core + 4.7.0-SNAPSHOT + org.apache.camel camel-langchain4j-embeddings diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml index 2dfc5615942e0..daf1adf883686 100644 --- a/catalog/camel-allcomponents/pom.xml +++ b/catalog/camel-allcomponents/pom.xml @@ -1107,6 +1107,11 @@ camel-langchain4j-chat ${project.version} + + org.apache.camel + camel-langchain4j-core + ${project.version} + org.apache.camel camel-langchain4j-embeddings diff --git a/components/camel-ai/camel-langchain4j-chat/pom.xml b/components/camel-ai/camel-langchain4j-chat/pom.xml index a5ac9a1ba94d1..604500a8feb20 100644 --- a/components/camel-ai/camel-langchain4j-chat/pom.xml +++ b/components/camel-ai/camel-langchain4j-chat/pom.xml @@ -40,9 +40,8 @@ camel-support - dev.langchain4j - langchain4j - ${langchain4j-version} + org.apache.camel + camel-langchain4j-core diff --git a/components/camel-ai/camel-langchain4j-core/pom.xml b/components/camel-ai/camel-langchain4j-core/pom.xml new file mode 100644 index 0000000000000..734bf4b554b31 --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/pom.xml @@ -0,0 +1,73 @@ + + + + + 4.0.0 + + + camel-ai-parent + org.apache.camel + 4.7.0-SNAPSHOT + + + camel-langchain4j-core + jar + Camel :: LangChain4j :: Core + LangChain4j Core + + + 4.7.0 + + LangChain4j Core + Experimental + + + + + org.apache.camel + camel-support + + + dev.langchain4j + langchain4j-core + ${langchain4j-version} + + + + + + org.apache.camel + camel-test-junit5 + test + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + ${assertj-version} + test + + + diff --git a/components/camel-ai/camel-langchain4j-core/src/generated/java/org/apache/camel/component/langchain4j/core/LangChain4jConverterLoader.java b/components/camel-ai/camel-langchain4j-core/src/generated/java/org/apache/camel/component/langchain4j/core/LangChain4jConverterLoader.java new file mode 100644 index 0000000000000..ee39897cdc5b2 --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/generated/java/org/apache/camel/component/langchain4j/core/LangChain4jConverterLoader.java @@ -0,0 +1,54 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.langchain4j.core; + +import javax.annotation.processing.Generated; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.DeferredContextBinding; +import org.apache.camel.Exchange; +import org.apache.camel.TypeConversionException; +import org.apache.camel.TypeConverterLoaderException; +import org.apache.camel.spi.TypeConverterLoader; +import org.apache.camel.spi.TypeConverterRegistry; +import org.apache.camel.support.SimpleTypeConverter; +import org.apache.camel.support.TypeConverterSupport; +import org.apache.camel.util.DoubleMap; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.TypeConverterLoaderGeneratorMojo") +@SuppressWarnings("unchecked") +@DeferredContextBinding +public final class LangChain4jConverterLoader implements TypeConverterLoader, CamelContextAware { + + private CamelContext camelContext; + + public LangChain4jConverterLoader() { + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException { + registerConverters(registry); + } + + private void registerConverters(TypeConverterRegistry registry) { + addTypeConverter(registry, dev.langchain4j.data.document.Document.class, java.lang.String.class, false, + (type, exchange, value) -> org.apache.camel.component.langchain4j.core.LangChain4jConverter.toDocument((java.lang.String) value, exchange)); + } + + private static void addTypeConverter(TypeConverterRegistry registry, Class toType, Class fromType, boolean allowNull, SimpleTypeConverter.ConversionMethod method) { + registry.addTypeConverter(toType, fromType, new SimpleTypeConverter(allowNull, method)); + } +} diff --git a/components/camel-ai/camel-langchain4j-core/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader b/components/camel-ai/camel-langchain4j-core/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader new file mode 100644 index 0000000000000..37d8e16ece7a9 --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +org.apache.camel.component.langchain4j.core.LangChain4jConverterLoader diff --git a/components/camel-ai/camel-langchain4j-core/src/generated/resources/META-INF/services/org/apache/camel/other.properties b/components/camel-ai/camel-langchain4j-core/src/generated/resources/META-INF/services/org/apache/camel/other.properties new file mode 100644 index 0000000000000..e9d95a2b607ae --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/generated/resources/META-INF/services/org/apache/camel/other.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +name=langchain4j-core +groupId=org.apache.camel +artifactId=camel-langchain4j-core +version=4.7.0-SNAPSHOT +projectName=Camel :: LangChain4j :: Core +projectDescription=LangChain4j Core diff --git a/components/camel-ai/camel-langchain4j-core/src/generated/resources/langchain4j-core.json b/components/camel-ai/camel-langchain4j-core/src/generated/resources/langchain4j-core.json new file mode 100644 index 0000000000000..1846eaa6c0fe2 --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/generated/resources/langchain4j-core.json @@ -0,0 +1,15 @@ +{ + "other": { + "kind": "other", + "name": "langchain4j-core", + "title": "LangChain4j Core", + "description": "LangChain4j Core", + "deprecated": false, + "firstVersion": "4.7.0", + "label": "ai", + "supportLevel": "Experimental", + "groupId": "org.apache.camel", + "artifactId": "camel-langchain4j-core", + "version": "4.7.0-SNAPSHOT" + } +} diff --git a/components/camel-ai/camel-langchain4j-core/src/main/java/org/apache/camel/component/langchain4j/core/LangChain4j.java b/components/camel-ai/camel-langchain4j-core/src/main/java/org/apache/camel/component/langchain4j/core/LangChain4j.java new file mode 100644 index 0000000000000..1409cefc2142d --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/main/java/org/apache/camel/component/langchain4j/core/LangChain4j.java @@ -0,0 +1,25 @@ +/* + * 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.langchain4j.core; + +public final class LangChain4j { + public static final String METADATA_PREFIX = "langchain4j.metadata."; + public static final int METADATA_PREFIX_LEN = METADATA_PREFIX.length(); + + private LangChain4j() { + } +} diff --git a/components/camel-ai/camel-langchain4j-core/src/main/java/org/apache/camel/component/langchain4j/core/LangChain4jConverter.java b/components/camel-ai/camel-langchain4j-core/src/main/java/org/apache/camel/component/langchain4j/core/LangChain4jConverter.java new file mode 100644 index 0000000000000..59ce0de10d347 --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/main/java/org/apache/camel/component/langchain4j/core/LangChain4jConverter.java @@ -0,0 +1,67 @@ +/* + * 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.langchain4j.core; + +import java.util.HashMap; +import java.util.Map; + +import dev.langchain4j.data.document.Document; +import dev.langchain4j.data.document.Metadata; +import org.apache.camel.Converter; +import org.apache.camel.Exchange; + +/** + * Converter methods to convert from / to LangChain4j types. + */ +@Converter(generateLoader = true) +public class LangChain4jConverter { + + @Converter + public static Document toDocument(String value, Exchange exchange) { + return Document.document( + value, + toMetadata(exchange)); + } + + private static Metadata toMetadata(Exchange exchange) { + if (exchange == null) { + return new Metadata(); + } + if (exchange.getMessage() == null) { + return new Metadata(); + } + + Map metadata = null; + Map headers = exchange.getMessage().getHeaders(); + + for (Map.Entry entry : headers.entrySet()) { + if (!entry.getKey().startsWith(LangChain4j.METADATA_PREFIX)) { + continue; + } + + if (metadata == null) { + metadata = new HashMap<>(); + } + + metadata.put( + entry.getKey().substring(LangChain4j.METADATA_PREFIX_LEN), + entry.getValue()); + } + + return metadata != null ? Metadata.from(metadata) : new Metadata(); + } +} diff --git a/components/camel-ai/camel-langchain4j-core/src/test/java/org/apache/camel/component/langchain4j/core/LangChain4jConverterTest.java b/components/camel-ai/camel-langchain4j-core/src/test/java/org/apache/camel/component/langchain4j/core/LangChain4jConverterTest.java new file mode 100644 index 0000000000000..68c071b9f1c32 --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/test/java/org/apache/camel/component/langchain4j/core/LangChain4jConverterTest.java @@ -0,0 +1,51 @@ +/* + * 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.langchain4j.core; + +import dev.langchain4j.data.document.Document; +import org.apache.camel.Exchange; +import org.apache.camel.NoTypeConversionAvailableException; +import org.apache.camel.support.DefaultExchange; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LangChain4jConverterTest extends CamelTestSupport { + + @Test + public void testConverter() throws NoTypeConversionAvailableException { + Document doc = context.getTypeConverter().mandatoryConvertTo(Document.class, "foo"); + assertThat(doc.text()).isEqualTo("foo"); + + Exchange exchange = new DefaultExchange(context); + exchange.getMessage().setHeader(LangChain4j.METADATA_PREFIX + "meta1", 1); + exchange.getMessage().setHeader(LangChain4j.METADATA_PREFIX + "meta2", "baz"); + exchange.getMessage().setHeader("meta3", "ignored"); + + Document docWithMetadata = context.getTypeConverter().mandatoryConvertTo( + Document.class, + exchange, + "bar"); + + assertThat(docWithMetadata.text()).isEqualTo("bar"); + assertThat(docWithMetadata.metadata().toMap()) + .containsEntry("meta1", 1) + .containsEntry("meta2", "baz") + .doesNotContainKey("meta3"); + } +} diff --git a/components/camel-ai/camel-langchain4j-core/src/test/resources/log4j2.properties b/components/camel-ai/camel-langchain4j-core/src/test/resources/log4j2.properties new file mode 100644 index 0000000000000..7fad857f000df --- /dev/null +++ b/components/camel-ai/camel-langchain4j-core/src/test/resources/log4j2.properties @@ -0,0 +1,35 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +appender.file.type = File +appender.file.name = file +appender.file.fileName = target/camel-langchain4j-core-test.log +appender.file.layout.type = PatternLayout +appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n + +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n + +rootLogger.level = INFO +rootLogger.appenderRef.file.ref = file +# To log to stdout +#rootLogger.appenderRef.out.ref = out + +logger.camel-langchain4j-core.name = org.apache.camel.component.langchain4j.core +logger.camel-langchain4j-core.level = DEBUG diff --git a/components/camel-ai/camel-langchain4j-embeddings/pom.xml b/components/camel-ai/camel-langchain4j-embeddings/pom.xml index 88e4a6f1f8484..1c2a71b900723 100644 --- a/components/camel-ai/camel-langchain4j-embeddings/pom.xml +++ b/components/camel-ai/camel-langchain4j-embeddings/pom.xml @@ -48,9 +48,8 @@ camel-support - dev.langchain4j - langchain4j-core - ${langchain4j-version} + org.apache.camel + camel-langchain4j-core diff --git a/components/camel-ai/pom.xml b/components/camel-ai/pom.xml index 57c625d53e348..c58045470952c 100644 --- a/components/camel-ai/pom.xml +++ b/components/camel-ai/pom.xml @@ -36,6 +36,7 @@ camel-chatscript camel-djl + camel-langchain4j-core camel-langchain4j-chat camel-langchain4j-embeddings diff --git a/docs/components/modules/others/examples/json/langchain4j-core.json b/docs/components/modules/others/examples/json/langchain4j-core.json new file mode 120000 index 0000000000000..49f0f1d8d081b --- /dev/null +++ b/docs/components/modules/others/examples/json/langchain4j-core.json @@ -0,0 +1 @@ +../../../../../../components/camel-ai/camel-langchain4j-core/src/generated/resources/langchain4j-core.json \ No newline at end of file diff --git a/parent/pom.xml b/parent/pom.xml index ff989fea5c89a..e4df94274e62a 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -1724,6 +1724,11 @@ camel-langchain4j-chat ${project.version} + + org.apache.camel + camel-langchain4j-core + ${project.version} + org.apache.camel camel-langchain4j-embeddings