This is an automated email from the ASF dual-hosted git repository.
zbendhiba 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 a543ea524ff CAMEL-20935: introduce Camel LangChain4j Web Search
component (#14928)
a543ea524ff is described below
commit a543ea524ff0572d33614761198605599e52cd24
Author: Zineb BENDHIBA <[email protected]>
AuthorDate: Fri Jul 26 09:01:53 2024 +0200
CAMEL-20935: introduce Camel LangChain4j Web Search component (#14928)
---
bom/camel-bom/pom.xml | 5 +
catalog/camel-allcomponents/pom.xml | 5 +
.../camel-ai/camel-langchain4j-web-search/pom.xml | 85 +++++++++
.../LangChain4jWebSearchComponentConfigurer.java | 57 ++++++
...angChain4jWebSearchConfigurationConfigurer.java | 111 ++++++++++++
.../LangChain4jWebSearchEndpointConfigurer.java | 122 +++++++++++++
.../LangChain4jWebSearchEndpointUriFactory.java | 81 +++++++++
.../web/search/langchain4j-web-search.json | 43 +++++
.../services/org/apache/camel/component.properties | 7 +
.../apache/camel/component/langchain4j-web-search | 2 +
.../configurer/langchain4j-web-search-component | 2 +
.../configurer/langchain4j-web-search-endpoint | 2 +
...4j.web.search.LangChain4jWebSearchConfiguration | 2 +
.../urifactory/langchain4j-web-search-endpoint | 2 +
.../docs/langchain4j-web-search-component.adoc | 164 ++++++++++++++++++
.../web/search/LangChain4jWebSearchComponent.java | 55 ++++++
.../search/LangChain4jWebSearchConfiguration.java | 192 +++++++++++++++++++++
.../web/search/LangChain4jWebSearchEndpoint.java | 76 ++++++++
.../web/search/LangChain4jWebSearchEngine.java | 26 +++
.../web/search/LangChain4jWebSearchProducer.java | 112 ++++++++++++
.../web/search/LangChain4jWebSearchResultType.java | 23 +++
.../search/LangChain4jGoogleWebSearchEngineIT.java | 90 ++++++++++
.../search/LangChain4jTavilyWebSearchEngineIT.java | 88 ++++++++++
components/camel-ai/pom.xml | 1 +
.../ROOT/examples/json/langchain4j-web-search.json | 1 +
docs/components/modules/ROOT/nav.adoc | 1 +
.../pages/langchain4j-web-search-component.adoc | 1 +
parent/pom.xml | 5 +
28 files changed, 1361 insertions(+)
diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index 63aad62abed..d4be05ec273 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -1327,6 +1327,11 @@
<artifactId>camel-langchain4j-embeddings</artifactId>
<version>4.8.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-langchain4j-web-search</artifactId>
+ <version>4.8.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-language</artifactId>
diff --git a/catalog/camel-allcomponents/pom.xml
b/catalog/camel-allcomponents/pom.xml
index 9f98de291c1..af7bc3a0e46 100644
--- a/catalog/camel-allcomponents/pom.xml
+++ b/catalog/camel-allcomponents/pom.xml
@@ -1122,6 +1122,11 @@
<artifactId>camel-langchain4j-embeddings</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-langchain4j-web-search</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-language</artifactId>
diff --git a/components/camel-ai/camel-langchain4j-web-search/pom.xml
b/components/camel-ai/camel-langchain4j-web-search/pom.xml
new file mode 100644
index 00000000000..bada1ca140f
--- /dev/null
+++ b/components/camel-ai/camel-langchain4j-web-search/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <artifactId>camel-ai-parent</artifactId>
+ <groupId>org.apache.camel</groupId>
+ <version>4.8.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>camel-langchain4j-web-search</artifactId>
+ <packaging>jar</packaging>
+ <name>Camel :: AI :: LangChain4j :: Web Search</name>
+ <description>LangChain4j Web Search</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-support</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-langchain4j-core</artifactId>
+ </dependency>
+
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-direct</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-junit5</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>${assertj-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>dev.langchain4j</groupId>
+ <artifactId>langchain4j-web-search-engine-tavily</artifactId>
+ <version>${langchain4j-version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>dev.langchain4j</groupId>
+ <artifactId>langchain4j-web-search-engine-google-custom</artifactId>
+ <version>${langchain4j-version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+</project>
+
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchComponentConfigurer.java
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchComponentConfigurer.java
new file mode 100644
index 00000000000..8d4f0ab598d
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchComponentConfigurer.java
@@ -0,0 +1,57 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.langchain4j.web.search;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo")
+@SuppressWarnings("unchecked")
+public class LangChain4jWebSearchComponentConfigurer extends
PropertyConfigurerSupport implements GeneratedPropertyConfigurer,
PropertyConfigurerGetter {
+
+ @Override
+ public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
+ LangChain4jWebSearchComponent target = (LangChain4jWebSearchComponent)
obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "autowiredenabled":
+ case "autowiredEnabled":
target.setAutowiredEnabled(property(camelContext, boolean.class, value));
return true;
+ case "lazystartproducer":
+ case "lazyStartProducer":
target.setLazyStartProducer(property(camelContext, boolean.class, value));
return true;
+ default: return false;
+ }
+ }
+
+ @Override
+ public Class<?> getOptionType(String name, boolean ignoreCase) {
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "autowiredenabled":
+ case "autowiredEnabled": return boolean.class;
+ case "lazystartproducer":
+ case "lazyStartProducer": return boolean.class;
+ default: return null;
+ }
+ }
+
+ @Override
+ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+ LangChain4jWebSearchComponent target = (LangChain4jWebSearchComponent)
obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "autowiredenabled":
+ case "autowiredEnabled": return target.isAutowiredEnabled();
+ case "lazystartproducer":
+ case "lazyStartProducer": return target.isLazyStartProducer();
+ default: return null;
+ }
+ }
+}
+
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchConfigurationConfigurer.java
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchConfigurationConfigurer.java
new file mode 100644
index 00000000000..0a91667f75f
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchConfigurationConfigurer.java
@@ -0,0 +1,111 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.langchain4j.web.search;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import
org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.GenerateConfigurerMojo")
+@SuppressWarnings("unchecked")
+public class LangChain4jWebSearchConfigurationConfigurer extends
org.apache.camel.support.component.PropertyConfigurerSupport implements
GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+ @Override
+ public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
+
org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration
target =
(org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration)
obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams":
target.setAdditionalParams(property(camelContext, java.util.Map.class, value));
return true;
+ case "geolocation":
+ case "geoLocation": target.setGeoLocation(property(camelContext,
java.lang.String.class, value)); return true;
+ case "language": target.setLanguage(property(camelContext,
java.lang.String.class, value)); return true;
+ case "maxresults":
+ case "maxResults": target.setMaxResults(property(camelContext,
java.lang.Integer.class, value)); return true;
+ case "resulttype":
+ case "resultType": target.setResultType(property(camelContext,
org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchResultType.class,
value)); return true;
+ case "safesearch":
+ case "safeSearch": target.setSafeSearch(property(camelContext,
java.lang.Boolean.class, value)); return true;
+ case "startindex":
+ case "startIndex": target.setStartIndex(property(camelContext,
java.lang.Integer.class, value)); return true;
+ case "startpage":
+ case "startPage": target.setStartPage(property(camelContext,
java.lang.Integer.class, value)); return true;
+ case "websearchengine":
+ case "webSearchEngine":
target.setWebSearchEngine(property(camelContext,
dev.langchain4j.web.search.WebSearchEngine.class, value)); return true;
+ case "websearchrequest":
+ case "webSearchRequest":
target.setWebSearchRequest(property(camelContext,
dev.langchain4j.web.search.WebSearchRequest.class, value)); return true;
+ default: return false;
+ }
+ }
+
+ @Override
+ public Class<?> getOptionType(String name, boolean ignoreCase) {
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams": return java.util.Map.class;
+ case "geolocation":
+ case "geoLocation": return java.lang.String.class;
+ case "language": return java.lang.String.class;
+ case "maxresults":
+ case "maxResults": return java.lang.Integer.class;
+ case "resulttype":
+ case "resultType": return
org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchResultType.class;
+ case "safesearch":
+ case "safeSearch": return java.lang.Boolean.class;
+ case "startindex":
+ case "startIndex": return java.lang.Integer.class;
+ case "startpage":
+ case "startPage": return java.lang.Integer.class;
+ case "websearchengine":
+ case "webSearchEngine": return
dev.langchain4j.web.search.WebSearchEngine.class;
+ case "websearchrequest":
+ case "webSearchRequest": return
dev.langchain4j.web.search.WebSearchRequest.class;
+ default: return null;
+ }
+ }
+
+ @Override
+ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+
org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration
target =
(org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration)
obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams": return target.getAdditionalParams();
+ case "geolocation":
+ case "geoLocation": return target.getGeoLocation();
+ case "language": return target.getLanguage();
+ case "maxresults":
+ case "maxResults": return target.getMaxResults();
+ case "resulttype":
+ case "resultType": return target.getResultType();
+ case "safesearch":
+ case "safeSearch": return target.getSafeSearch();
+ case "startindex":
+ case "startIndex": return target.getStartIndex();
+ case "startpage":
+ case "startPage": return target.getStartPage();
+ case "websearchengine":
+ case "webSearchEngine": return target.getWebSearchEngine();
+ case "websearchrequest":
+ case "webSearchRequest": return target.getWebSearchRequest();
+ default: return null;
+ }
+ }
+
+ @Override
+ public Object getCollectionValueType(Object target, String name, boolean
ignoreCase) {
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams": return java.lang.Object.class;
+ default: return null;
+ }
+ }
+}
+
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpointConfigurer.java
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpointConfigurer.java
new file mode 100644
index 00000000000..e280ad92a41
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpointConfigurer.java
@@ -0,0 +1,122 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.langchain4j.web.search;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo")
+@SuppressWarnings("unchecked")
+public class LangChain4jWebSearchEndpointConfigurer extends
PropertyConfigurerSupport implements GeneratedPropertyConfigurer,
PropertyConfigurerGetter {
+
+ @Override
+ public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
+ LangChain4jWebSearchEndpoint target = (LangChain4jWebSearchEndpoint)
obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams":
target.getConfiguration().setAdditionalParams(property(camelContext,
java.util.Map.class, value)); return true;
+ case "geolocation":
+ case "geoLocation":
target.getConfiguration().setGeoLocation(property(camelContext,
java.lang.String.class, value)); return true;
+ case "language":
target.getConfiguration().setLanguage(property(camelContext,
java.lang.String.class, value)); return true;
+ case "lazystartproducer":
+ case "lazyStartProducer":
target.setLazyStartProducer(property(camelContext, boolean.class, value));
return true;
+ case "maxresults":
+ case "maxResults":
target.getConfiguration().setMaxResults(property(camelContext,
java.lang.Integer.class, value)); return true;
+ case "resulttype":
+ case "resultType":
target.getConfiguration().setResultType(property(camelContext,
org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchResultType.class,
value)); return true;
+ case "safesearch":
+ case "safeSearch":
target.getConfiguration().setSafeSearch(property(camelContext,
java.lang.Boolean.class, value)); return true;
+ case "startindex":
+ case "startIndex":
target.getConfiguration().setStartIndex(property(camelContext,
java.lang.Integer.class, value)); return true;
+ case "startpage":
+ case "startPage":
target.getConfiguration().setStartPage(property(camelContext,
java.lang.Integer.class, value)); return true;
+ case "websearchengine":
+ case "webSearchEngine":
target.getConfiguration().setWebSearchEngine(property(camelContext,
dev.langchain4j.web.search.WebSearchEngine.class, value)); return true;
+ case "websearchrequest":
+ case "webSearchRequest":
target.getConfiguration().setWebSearchRequest(property(camelContext,
dev.langchain4j.web.search.WebSearchRequest.class, value)); return true;
+ default: return false;
+ }
+ }
+
+ @Override
+ public String[] getAutowiredNames() {
+ return new String[]{"additionalParams", "webSearchEngine",
"webSearchRequest"};
+ }
+
+ @Override
+ public Class<?> getOptionType(String name, boolean ignoreCase) {
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams": return java.util.Map.class;
+ case "geolocation":
+ case "geoLocation": return java.lang.String.class;
+ case "language": return java.lang.String.class;
+ case "lazystartproducer":
+ case "lazyStartProducer": return boolean.class;
+ case "maxresults":
+ case "maxResults": return java.lang.Integer.class;
+ case "resulttype":
+ case "resultType": return
org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchResultType.class;
+ case "safesearch":
+ case "safeSearch": return java.lang.Boolean.class;
+ case "startindex":
+ case "startIndex": return java.lang.Integer.class;
+ case "startpage":
+ case "startPage": return java.lang.Integer.class;
+ case "websearchengine":
+ case "webSearchEngine": return
dev.langchain4j.web.search.WebSearchEngine.class;
+ case "websearchrequest":
+ case "webSearchRequest": return
dev.langchain4j.web.search.WebSearchRequest.class;
+ default: return null;
+ }
+ }
+
+ @Override
+ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+ LangChain4jWebSearchEndpoint target = (LangChain4jWebSearchEndpoint)
obj;
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams": return
target.getConfiguration().getAdditionalParams();
+ case "geolocation":
+ case "geoLocation": return target.getConfiguration().getGeoLocation();
+ case "language": return target.getConfiguration().getLanguage();
+ case "lazystartproducer":
+ case "lazyStartProducer": return target.isLazyStartProducer();
+ case "maxresults":
+ case "maxResults": return target.getConfiguration().getMaxResults();
+ case "resulttype":
+ case "resultType": return target.getConfiguration().getResultType();
+ case "safesearch":
+ case "safeSearch": return target.getConfiguration().getSafeSearch();
+ case "startindex":
+ case "startIndex": return target.getConfiguration().getStartIndex();
+ case "startpage":
+ case "startPage": return target.getConfiguration().getStartPage();
+ case "websearchengine":
+ case "webSearchEngine": return
target.getConfiguration().getWebSearchEngine();
+ case "websearchrequest":
+ case "webSearchRequest": return
target.getConfiguration().getWebSearchRequest();
+ default: return null;
+ }
+ }
+
+ @Override
+ public Object getCollectionValueType(Object target, String name, boolean
ignoreCase) {
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalparams":
+ case "additionalParams": return java.lang.Object.class;
+ default: return null;
+ }
+ }
+}
+
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpointUriFactory.java
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpointUriFactory.java
new file mode 100644
index 00000000000..a13d6262bad
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpointUriFactory.java
@@ -0,0 +1,81 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.langchain4j.web.search;
+
+import javax.annotation.processing.Generated;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.spi.EndpointUriFactory;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.GenerateEndpointUriFactoryMojo")
+public class LangChain4jWebSearchEndpointUriFactory extends
org.apache.camel.support.component.EndpointUriFactorySupport implements
EndpointUriFactory {
+
+ private static final String BASE = ":searchId";
+
+ private static final Set<String> PROPERTY_NAMES;
+ private static final Set<String> SECRET_PROPERTY_NAMES;
+ private static final Set<String> MULTI_VALUE_PREFIXES;
+ static {
+ Set<String> props = new HashSet<>(12);
+ props.add("additionalParams");
+ props.add("geoLocation");
+ props.add("language");
+ props.add("lazyStartProducer");
+ props.add("maxResults");
+ props.add("resultType");
+ props.add("safeSearch");
+ props.add("searchId");
+ props.add("startIndex");
+ props.add("startPage");
+ props.add("webSearchEngine");
+ props.add("webSearchRequest");
+ PROPERTY_NAMES = Collections.unmodifiableSet(props);
+ SECRET_PROPERTY_NAMES = Collections.emptySet();
+ MULTI_VALUE_PREFIXES = Collections.emptySet();
+ }
+
+ @Override
+ public boolean isEnabled(String scheme) {
+ return "langchain4j-web-search".equals(scheme);
+ }
+
+ @Override
+ public String buildUri(String scheme, Map<String, Object> properties,
boolean encode) throws URISyntaxException {
+ String syntax = scheme + BASE;
+ String uri = syntax;
+
+ Map<String, Object> copy = new HashMap<>(properties);
+
+ uri = buildPathParameter(syntax, uri, "searchId", null, true, copy);
+ uri = buildQueryParameters(uri, copy, encode);
+ return uri;
+ }
+
+ @Override
+ public Set<String> propertyNames() {
+ return PROPERTY_NAMES;
+ }
+
+ @Override
+ public Set<String> secretPropertyNames() {
+ return SECRET_PROPERTY_NAMES;
+ }
+
+ @Override
+ public Set<String> multiValuePrefixes() {
+ return MULTI_VALUE_PREFIXES;
+ }
+
+ @Override
+ public boolean isLenientProperties() {
+ return false;
+ }
+}
+
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/web/search/langchain4j-web-search.json
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/web/search/langchain4j-web-search.json
new file mode 100644
index 00000000000..f882cf829f5
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/web/search/langchain4j-web-search.json
@@ -0,0 +1,43 @@
+{
+ "component": {
+ "kind": "component",
+ "name": "langchain4j-web-search",
+ "title": "LangChain4j Web Search",
+ "description": "LangChain4j Web Search Engine",
+ "deprecated": false,
+ "firstVersion": "4.8.0",
+ "label": "ai",
+ "javaType":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchComponent",
+ "supportLevel": "Preview",
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-langchain4j-web-search",
+ "version": "4.8.0-SNAPSHOT",
+ "scheme": "langchain4j-web-search",
+ "extendsScheme": "",
+ "syntax": "langchain4j-web-search:searchId",
+ "async": false,
+ "api": false,
+ "consumerOnly": false,
+ "producerOnly": true,
+ "lenientProperties": false,
+ "remote": true
+ },
+ "componentProperties": {
+ "lazyStartProducer": { "index": 0, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
+ "autowiredEnabled": { "index": 1, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
+ },
+ "properties": {
+ "searchId": { "index": 0, "kind": "path", "displayName": "Search Id",
"group": "producer", "label": "", "required": true, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "The id" },
+ "additionalParams": { "index": 1, "kind": "parameter", "displayName":
"Additional Params", "group": "producer", "label": "", "required": false,
"type": "object", "javaType": "java.util.Map<java.lang.String,
java.lang.Object>", "deprecated": false, "deprecationNote": "", "autowired":
true, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The additionalPar [...]
+ "geoLocation": { "index": 2, "kind": "parameter", "displayName": "Geo
Location", "group": "producer", "label": "", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The geoLocation is the
desired geolocation for search results. Each search engine [...]
+ "language": { "index": 3, "kind": "parameter", "displayName": "Language",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The language is the
desired language for search results. The expected values may vary dep [...]
+ "maxResults": { "index": 4, "kind": "parameter", "displayName": "Max
Results", "group": "producer", "label": "", "required": true, "type":
"integer", "javaType": "java.lang.Integer", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue":
"1", "configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The maxResults is the
expected number o [...]
+ "resultType": { "index": 5, "kind": "parameter", "displayName": "Result
Type", "group": "producer", "label": "", "required": true, "type": "object",
"javaType":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchResultType",
"enum": [ "LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT", "CONTENT", "SNIPPET" ],
"deprecated": false, "deprecationNote": "", "autowired": false, "secret":
false, "defaultValue": "CONTENT", "configurationClass":
"org.apache.camel.component.langchain4 [...]
+ "safeSearch": { "index": 6, "kind": "parameter", "displayName": "Safe
Search", "group": "producer", "label": "", "required": false, "type":
"boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The safeSearch is the
safe search flag, indicating whether to enable or disable sa [...]
+ "startIndex": { "index": 7, "kind": "parameter", "displayName": "Start
Index", "group": "producer", "label": "", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The startIndex is the
start index for search results, which may vary depending on [...]
+ "startPage": { "index": 8, "kind": "parameter", "displayName": "Start
Page", "group": "producer", "label": "", "required": false, "type": "integer",
"javaType": "java.lang.Integer", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The startPage is the
start page number for search results" },
+ "webSearchEngine": { "index": 9, "kind": "parameter", "displayName": "Web
Search Engine", "group": "producer", "label": "", "required": true, "type":
"object", "javaType": "dev.langchain4j.web.search.WebSearchEngine",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The WebSearchEngine
engine [...]
+ "lazyStartProducer": { "index": 10, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "webSearchRequest": { "index": 11, "kind": "parameter", "displayName":
"Web Search Request", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType":
"dev.langchain4j.web.search.WebSearchRequest", "deprecated": false,
"deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration",
"configurationField": "configuration", "description": "The webSearch [...]
+ }
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/component.properties
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/component.properties
new file mode 100644
index 00000000000..b5b7ff362be
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/component.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+components=langchain4j-web-search
+groupId=org.apache.camel
+artifactId=camel-langchain4j-web-search
+version=4.8.0-SNAPSHOT
+projectName=Camel :: AI :: LangChain4j :: Web Search
+projectDescription=LangChain4j Web Search
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/component/langchain4j-web-search
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/component/langchain4j-web-search
new file mode 100644
index 00000000000..f5d8e91d577
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/component/langchain4j-web-search
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchComponent
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/langchain4j-web-search-component
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/langchain4j-web-search-component
new file mode 100644
index 00000000000..62e7d2413d7
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/langchain4j-web-search-component
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchComponentConfigurer
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/langchain4j-web-search-endpoint
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/langchain4j-web-search-endpoint
new file mode 100644
index 00000000000..6b16d2f8683
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/langchain4j-web-search-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchEndpointConfigurer
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration
new file mode 100644
index 00000000000..58253746407
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfiguration
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchConfigurationConfigurer
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/urifactory/langchain4j-web-search-endpoint
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/urifactory/langchain4j-web-search-endpoint
new file mode 100644
index 00000000000..39e3e075134
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/services/org/apache/camel/urifactory/langchain4j-web-search-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchEndpointUriFactory
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/main/docs/langchain4j-web-search-component.adoc
b/components/camel-ai/camel-langchain4j-web-search/src/main/docs/langchain4j-web-search-component.adoc
new file mode 100644
index 00000000000..ac6483137bc
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/main/docs/langchain4j-web-search-component.adoc
@@ -0,0 +1,164 @@
+= LangChain4j Web Search Component
+:doctitle: LangChain4j Web Search
+:shortname: langchain4j-web-search
+:artifactid: camel-langchain4j-web-search
+:description: LangChain4j Web Search Engine
+:since: 4.8
+:supportlevel: Preview
+:tabs-sync-option:
+:component-header: Only producer is supported
+//Manually maintained attributes
+:group: AI
+:camel-spring-boot-name: langchain4j-web-search
+
+*Since Camel {since}*
+
+*{component-header}*
+
+The LangChain4j Web Search component provides support to perform a web search
using the https://docs.langchain4j.dev/[LangChain4j] Web Search Engines.
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-langchain4j-web-search</artifactId>
+ <version>x.x.x</version>
+ <!-- use the same version as your Camel core version -->
+</dependency>
+----
+
+
+== URI format
+
+[source]
+----
+langchain4j-web-search:searchId[?options]
+----
+
+Where *searchId* can be any string to uniquely identify the endpoint
+
+
+// component-configure options: START
+
+// component-configure options: END
+
+// component options: START
+include::partial$component-configure-options.adoc[]
+include::partial$component-endpoint-options.adoc[]
+// component options: END
+
+// endpoint options: START
+
+// endpoint options: END
+
+// component headers: START
+include::partial$component-endpoint-headers.adoc[]
+// component headers: END
+
+include::spring-boot:partial$starter.adoc[]
+
+
+== Using a specific Web Search Engine
+The Camel LangChain4j web search component provides an abstraction for
interacting with various types of Web Search Engines supported by
https://github.com/langchain4j/langchain4j[LangChain4j].
+
+To integrate with a specific Web Search Engine, users should follow these
steps:
+
+=== Example of integrating with Tavily
+Add the dependency for LangChain4j Tavily Web Search Engine support :
+
+[source,xml]
+----
+<dependency>
+ <groupId>dev.langchain4j</groupId>
+ <artifactId>langchain4j-web-search-engine-tavily</artifactId>
+ <version>x.x.x</version>
+</dependency>
+----
+
+Init the Tavily Web Search Engine, and add it to the Camel Registry:
+Initialize the Tavily Web Search Engine, and bind it to the Camel Registry:
+
+[source, java]
+----
+@BindToRegistry("web-search-engine")
+WebSearchEngine tavilyWebSearchEngine = TavilyWebSearchEngine.builder()
+ .apiKey(tavilyApiKey)
+ .includeRawContent(true)
+ .build();
+----
+
+The web search engine will be autowired automatically if its bound name is
`web-search-engine`. Otherwise, it should be added as a configured parameter to
the Camel route.
+
+Example of route:
+
+[source, java]
+----
+ from("direct:web-search")
+
.to("langchain4j-web-search:test?webSearchEngine=#web-search-engine-test")
+----
+
+[NOTE]
+====
+To switch to another Web Search Engine and its corresponding dependency,
simply replace the `langchain4j-web-search-engine-tavily` dependency with the
appropriate dependency for the desired web search engine. Update the
initialization parameters accordingly in the code snippet provided above.
+====
+
+== Customizing Web Search Results
+By default, the `maxResults` property is set to 1. You can adjust this value
to retrieve a list of results.
+
+=== Retrieving single result or list of strings
+When `maxResults` is set to 1, you can by default retrieve by default the
content as a single string.
+Example:
+
+[source, java]
+----
+String response = template.requestBody("langchain4j-web-search:test", "Who won
the European Cup in 2024?", String.class);
+----
+
+When `maxResults` is greater than 1, you can retrieve a list of strings.
+Example:
+
+[source, java]
+----
+List<String> responses =
template.requestBody("langchain4j-web-search:test?maxResults=3", "Who won the
European Cup in 2024?", List.class);
+----
+
+=== Retrieve different types of Results
+You can get different type of Results.
+
+When `resultType` = SNIPPET, you will get a single or list (depending of
`maxResults` value) of Strings containing the snippets.
+
+When `resultType` = LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT, you will get a
single or list (depending of `maxResults` value) of Objects of type
`WebSearchOrganicResult` containing all the response created under the hood by
Langchain4j Web Search.
+
+== Advanced usage of WebSearchRequest
+
+When defining a WebSearchRequest, the Camel LangChain4j web search component
will default to this request, instead of creating one from the body and config
parameters.
+
+[NOTE]
+====
+When using a WebSearchRequest, the body and the parameters of the search will
be ignored. Use this parameter with caution.
+====
+
+A WebSearchRequest should be bound to the registry.
+
+Example of binding the request to the registry.
+
+[source, java]
+----
+@BindToRegistry("web-search-request")
+WebSearchRequest request = WebSearchRequest.builder()
+ .searchTerms("Who won the European Cup in 2024?")
+ .maxResults(2)
+ .build();
+----
+
+The request will be autowired automatically if its bound name is
`web-search-request`. Otherwise, it should be added as a configured parameter
to the Camel route.
+
+Example of route:
+[source, java]
+----
+ from("direct:web-search")
+ .to("langchain4j-web-search:test?webSearchRequest=#searchRequestTest");
+----
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchComponent.java
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchComponent.java
new file mode 100644
index 00000000000..b1dab154dac
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchComponent.java
@@ -0,0 +1,55 @@
+/*
+ * 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.web.search;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.support.DefaultComponent;
+
+@Component(LangChain4jWebSearchEngine.SCHEME)
+public class LangChain4jWebSearchComponent extends DefaultComponent {
+
+ @Metadata
+ private LangChain4jWebSearchConfiguration configuration;
+
+ public LangChain4jWebSearchComponent() {
+ this(null);
+ }
+
+ public LangChain4jWebSearchComponent(CamelContext context) {
+ super(context);
+ this.configuration = new LangChain4jWebSearchConfiguration();
+ }
+
+ public LangChain4jWebSearchConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ @Override
+ protected Endpoint createEndpoint(String uri, String remaining,
Map<String, Object> parameters) throws Exception {
+ LangChain4jWebSearchConfiguration configuration =
this.configuration.copy();
+
+ LangChain4jWebSearchEndpoint endpoint = new
LangChain4jWebSearchEndpoint(uri, this, remaining, configuration);
+ setProperties(endpoint, parameters);
+
+ return endpoint;
+ }
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchConfiguration.java
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchConfiguration.java
new file mode 100644
index 00000000000..46a18746c11
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchConfiguration.java
@@ -0,0 +1,192 @@
+/*
+ * 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.web.search;
+
+import java.util.Map;
+
+import dev.langchain4j.web.search.WebSearchEngine;
+import dev.langchain4j.web.search.WebSearchRequest;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.Configurer;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+
+@Configurer
+@UriParams
+public class LangChain4jWebSearchConfiguration implements Cloneable {
+
+ @Metadata(required = true, autowired = true)
+ @UriParam
+ private WebSearchEngine webSearchEngine;
+
+ @Metadata(required = true, defaultValue = "CONTENT")
+ @UriParam
+ private LangChain4jWebSearchResultType resultType =
LangChain4jWebSearchResultType.CONTENT;
+
+ @Metadata(required = true, defaultValue = "1")
+ @UriParam
+ private Integer maxResults = 1;
+ @UriParam
+ private String language;
+ @UriParam
+ private String geoLocation;
+ @UriParam
+ private Integer startPage;
+ @UriParam
+ private Integer startIndex;
+ @UriParam
+ private Boolean safeSearch;
+ @UriParam
+ @Metadata(autowired = true)
+ private Map<String, Object> additionalParams;
+
+ @UriParam(label = "advanced")
+ @Metadata(autowired = true)
+ private WebSearchRequest webSearchRequest;
+
+ public WebSearchEngine getWebSearchEngine() {
+ return webSearchEngine;
+ }
+
+ /**
+ * The {@link WebSearchEngine} engine to use. This is mandatory. Use one
of the implementations from Langchain4j web
+ * search engines.
+ */
+ public void setWebSearchEngine(WebSearchEngine webSearchEngine) {
+ this.webSearchEngine = webSearchEngine;
+ }
+
+ public LangChain4jWebSearchResultType getResultType() {
+ return resultType;
+ }
+
+ /**
+ * The {@link #resultType} is the result type of the request. Valid values
are
+ * LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT, CONTENT, or SNIPPET. CONTENT is
the default value; it will return a list
+ * of String . You can also specify to return either the Langchain4j Web
Search Organic Result object (using
+ * `LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT`) or snippet (using `SNIPPET`)
for each result. If {@link #maxResults} is
+ * equal to 1, the response will be a single object instead of a list.
+ */
+ public void setResultType(LangChain4jWebSearchResultType resultType) {
+ this.resultType = resultType;
+ }
+
+ /**
+ * The {@link #maxResults} is the expected number of results to be found
if the search request were made. Each
+ * search engine may have a different limit for the maximum number of
results that can be returned.
+ *
+ * @return
+ */
+ public Integer getMaxResults() {
+ return maxResults;
+ }
+
+ public void setMaxResults(Integer maxResults) {
+ this.maxResults = maxResults;
+ }
+
+ /**
+ * The {@link #language} is the desired language for search results. The
expected values may vary depending on the
+ * search engine.
+ *
+ * @return
+ */
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public String getGeoLocation() {
+ return geoLocation;
+ }
+
+ /**
+ * The {@link #geoLocation} is the desired geolocation for search results.
Each search engine may have a different
+ * set of supported geolocations.
+ */
+ public void setGeoLocation(String geoLocation) {
+ this.geoLocation = geoLocation;
+ }
+
+ public Integer getStartPage() {
+ return startPage;
+ }
+
+ /**
+ * The {@link #startPage} is the start page number for search results
+ */
+ public void setStartPage(Integer startPage) {
+ this.startPage = startPage;
+ }
+
+ public Integer getStartIndex() {
+ return startIndex;
+ }
+
+ /**
+ * The {@link #startIndex} is the start index for search results, which
may vary depending on the search engine.
+ */
+ public void setStartIndex(Integer startIndex) {
+ this.startIndex = startIndex;
+ }
+
+ public Boolean getSafeSearch() {
+ return safeSearch;
+ }
+
+ /**
+ * The {@link #safeSearch} is the safe search flag, indicating whether to
enable or disable safe search.
+ */
+ public void setSafeSearch(Boolean safeSearch) {
+ this.safeSearch = safeSearch;
+ }
+
+ public Map<String, Object> getAdditionalParams() {
+ return additionalParams;
+ }
+
+ /**
+ * The {@link #additionalParams} is the additional parameters for the
search request are a map of key-value pairs
+ * that represent additional parameters for the search request.
+ */
+ public void setAdditionalParams(Map<String, Object> additionalParams) {
+ this.additionalParams = additionalParams;
+ }
+
+ public WebSearchRequest getWebSearchRequest() {
+ return webSearchRequest;
+ }
+
+ /**
+ * The {@link #webSearchRequest} is the custom WebSearchRequest - advanced
+ */
+ public void setWebSearchRequest(WebSearchRequest webSearchRequest) {
+ this.webSearchRequest = webSearchRequest;
+ }
+
+ public LangChain4jWebSearchConfiguration copy() {
+ try {
+ return (LangChain4jWebSearchConfiguration) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpoint.java
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpoint.java
new file mode 100644
index 00000000000..ea3e75441a6
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEndpoint.java
@@ -0,0 +1,76 @@
+/*
+ * 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.web.search;
+
+import org.apache.camel.Category;
+import org.apache.camel.Component;
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.support.DefaultEndpoint;
+
+/**
+ * LangChain4j Web Search Engine
+ */
+@UriEndpoint(firstVersion = "4.8.0", scheme =
LangChain4jWebSearchEngine.SCHEME, title = "LangChain4j Web Search",
+ syntax = "langchain4j-web-search:searchId", producerOnly = true,
category = {
+ Category.AI
+ }, headersClass = LangChain4jWebSearchEngine.Headers.class)
+public class LangChain4jWebSearchEndpoint extends DefaultEndpoint {
+
+ @Metadata(required = true)
+ @UriPath(description = "The id")
+ private final String searchId;
+
+ @UriParam
+ private LangChain4jWebSearchConfiguration configuration;
+
+ public LangChain4jWebSearchEndpoint(
+ String endpointUri,
+ Component component,
+ String searchId,
+ LangChain4jWebSearchConfiguration
configuration) {
+
+ super(endpointUri, component);
+
+ this.searchId = searchId;
+ this.configuration = configuration;
+ }
+
+ public String getSearchId() {
+ return searchId;
+ }
+
+ public LangChain4jWebSearchConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ @Override
+ public Producer createProducer() throws Exception {
+ return new LangChain4jWebSearchProducer(this);
+ }
+
+ @Override
+ public Consumer createConsumer(Processor processor) throws Exception {
+ throw new UnsupportedOperationException("Consumer is not implemented
for this component");
+ }
+
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEngine.java
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEngine.java
new file mode 100644
index 00000000000..a731fd8d74a
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchEngine.java
@@ -0,0 +1,26 @@
+/*
+ * 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.web.search;
+
+public class LangChain4jWebSearchEngine {
+ public static final String SCHEME = "langchain4j-web-search";
+
+ public static class Headers {
+
+ }
+
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchProducer.java
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchProducer.java
new file mode 100644
index 00000000000..10d9242b3dd
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchProducer.java
@@ -0,0 +1,112 @@
+/*
+ * 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.web.search;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import dev.langchain4j.web.search.WebSearchEngine;
+import dev.langchain4j.web.search.WebSearchOrganicResult;
+import dev.langchain4j.web.search.WebSearchRequest;
+import dev.langchain4j.web.search.WebSearchResults;
+import org.apache.camel.Exchange;
+import org.apache.camel.support.DefaultProducer;
+import org.apache.camel.util.ObjectHelper;
+
+public class LangChain4jWebSearchProducer extends DefaultProducer {
+
+ private WebSearchEngine webSearchEngine;
+
+ public LangChain4jWebSearchProducer(LangChain4jWebSearchEndpoint endpoint)
{
+ super(endpoint);
+ }
+
+ @Override
+ public LangChain4jWebSearchEndpoint getEndpoint() {
+ return (LangChain4jWebSearchEndpoint) super.getEndpoint();
+ }
+
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ // check if there's a custom WebSearchRequest -- advanced
+ WebSearchRequest webSearchRequest =
getEndpoint().getConfiguration().getWebSearchRequest();
+
+ // build a Web Search Request
+ if (webSearchRequest == null) {
+ final String searchTerms =
exchange.getMessage().getMandatoryBody(String.class);
+ webSearchRequest = WebSearchRequest.builder()
+ .searchTerms(searchTerms)
+
.maxResults(getEndpoint().getConfiguration().getMaxResults())
+ .language(getEndpoint().getConfiguration().getLanguage())
+
.geoLocation(getEndpoint().getConfiguration().getGeoLocation())
+ .startPage(getEndpoint().getConfiguration().getStartPage())
+
.startIndex(getEndpoint().getConfiguration().getStartIndex())
+
.additionalParams(getEndpoint().getConfiguration().getAdditionalParams())
+ .build();
+ }
+
+ // perform the request
+ WebSearchResults webSearchResults =
webSearchEngine.search(webSearchRequest);
+
+ // exrtact the list
+ List<WebSearchOrganicResult> resultList = webSearchResults.results();
+
+ // compute the response
+ computeResponse(resultList, exchange, webSearchRequest.maxResults());
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+ this.webSearchEngine =
getEndpoint().getConfiguration().getWebSearchEngine();
+ ObjectHelper.notNull(webSearchEngine, "webSearchEngine");
+ }
+
+ /**
+ * Computes the response of the web search based on the configuration and
input results.
+ *
+ * @param webSearchOrganicResults the list of WebSearchOrganicResult
objects to process
+ * @param exchange the Apache Camel Exchange object
+ * @param maxResults maxResults
+ */
+ private void computeResponse(List<WebSearchOrganicResult>
webSearchOrganicResults, Exchange exchange, Integer maxResults) {
+ // Check if the input list is null or empty and handle it gracefully
+ if (webSearchOrganicResults == null ||
webSearchOrganicResults.isEmpty()) {
+ exchange.getIn().setBody(null);
+ return;
+ }
+
+ // return a single object as a response
+ if (maxResults == 1) {
+ switch (getEndpoint().getConfiguration().getResultType()) {
+ case LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT ->
exchange.getIn().setBody(webSearchOrganicResults.get(0));
+ case CONTENT ->
exchange.getIn().setBody(webSearchOrganicResults.get(0).content());
+ case SNIPPET ->
exchange.getIn().setBody(webSearchOrganicResults.get(0).snippet());
+ }
+ } else { // return a List of Objects as a response
+ switch (getEndpoint().getConfiguration().getResultType()) {
+ case LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT ->
exchange.getIn().setBody(webSearchOrganicResults);
+ case CONTENT -> exchange.getIn()
+
.setBody(webSearchOrganicResults.stream().map(WebSearchOrganicResult::content)
+ .collect(Collectors.toList()));
+ case SNIPPET -> exchange.getIn()
+
.setBody(webSearchOrganicResults.stream().map(WebSearchOrganicResult::snippet)
+ .collect(Collectors.toList()));
+ }
+ }
+ }
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchResultType.java
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchResultType.java
new file mode 100644
index 00000000000..4b4b9d2f595
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/main/java/org/apache/camel/component/langchain4j/web/search/LangChain4jWebSearchResultType.java
@@ -0,0 +1,23 @@
+/*
+ * 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.web.search;
+
+public enum LangChain4jWebSearchResultType {
+ LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT,
+ CONTENT,
+ SNIPPET
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/test/java/org/apache/camel/component/langchain4j/web/search/LangChain4jGoogleWebSearchEngineIT.java
b/components/camel-ai/camel-langchain4j-web-search/src/test/java/org/apache/camel/component/langchain4j/web/search/LangChain4jGoogleWebSearchEngineIT.java
new file mode 100644
index 00000000000..594ce4ffd8c
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/test/java/org/apache/camel/component/langchain4j/web/search/LangChain4jGoogleWebSearchEngineIT.java
@@ -0,0 +1,90 @@
+/*
+ * 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.web.search;
+
+import java.util.List;
+
+import dev.langchain4j.web.search.WebSearchEngine;
+import dev.langchain4j.web.search.WebSearchRequest;
+import
dev.langchain4j.web.search.google.customsearch.GoogleCustomWebSearchEngine;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.Exchange;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// Instruction to generate one
https://developers.google.com/custom-search/v1/overview
+@EnabledIfEnvironmentVariable(named = "GOOGLE_API_KEY", matches = ".*")
+// Instructions to create a Google search engine
https://developers.google.com/custom-search/docs/tutorial/creatingcse
+@EnabledIfEnvironmentVariable(named = "GOOGLE_SEARCH_ENGINE_ID", matches =
".*")
+public class LangChain4jGoogleWebSearchEngineIT extends CamelTestSupport {
+ public static final String WEB_SEARCH_URI =
"langchain4j-web-search:googleTest";
+
+ @BindToRegistry("web-search-engine")
+ WebSearchEngine googleSearchEngine = GoogleCustomWebSearchEngine.builder()
+ .apiKey(System.getenv("GOOGLE_API_KEY"))
+ .csi(System.getenv("GOOGLE_SEARCH_ENGINE_ID"))
+ .logRequests(true)
+ .logResponses(true)
+ .build();
+
+ @BindToRegistry("web-search-request")
+ WebSearchRequest request = WebSearchRequest.builder()
+ .searchTerms("Who won the European Cup in 2024?")
+ .maxResults(2)
+ .build();
+
+ @Test
+ void testSimpleSearch() {
+ String uri = String.format("%s?resultType=%s", WEB_SEARCH_URI,
LangChain4jWebSearchResultType.SNIPPET);
+ Exchange result = fluentTemplate.to(uri)
+ .withBody("Who won the European Cup in 2024?")
+ .request(Exchange.class);
+
+ assertNotNull(result, "An Exchange is expected.");
+
+ String organicResult = result.getIn().getBody(String.class);
+ assertNotNull(organicResult, "For this web search a snippet value is
expected as a String.");
+ }
+
+ @Test
+ void testSearchWithParams() {
+ String uri =
String.format("%s?maxResults=2&language=fr&resultType=%s", WEB_SEARCH_URI,
+ LangChain4jWebSearchResultType.SNIPPET);
+
+ Exchange result = fluentTemplate.to(uri)
+ .withBody("Qui a gagné la coupe d'Europe en 2024?")
+ .request(Exchange.class);
+
+ assertNotNull(result, "An Exchange is expected.");
+
+ List<String> listResult = result.getIn().getBody(List.class);
+ assertNotNull(listResult, "The list results from the Google Search
Engine shouldn't be null.");
+ assertNotEquals(0, listResult.get(0),
+ "The list results from the Google Search Engine shouldn't be
empty. It's the value of the snippet as a Strng");
+ }
+
+ @Test
+ void advancedRequestTest() {
+ List<String> response = template.requestBody(WEB_SEARCH_URI, null,
List.class);
+ assertNotNull(response, "An Exchange is expected.");
+ assertNotEquals(0, response.get(0), "The list results from the Google
Search Engine shouldn't be empty.");
+ }
+}
diff --git
a/components/camel-ai/camel-langchain4j-web-search/src/test/java/org/apache/camel/component/langchain4j/web/search/LangChain4jTavilyWebSearchEngineIT.java
b/components/camel-ai/camel-langchain4j-web-search/src/test/java/org/apache/camel/component/langchain4j/web/search/LangChain4jTavilyWebSearchEngineIT.java
new file mode 100644
index 00000000000..1dc93f532a8
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-web-search/src/test/java/org/apache/camel/component/langchain4j/web/search/LangChain4jTavilyWebSearchEngineIT.java
@@ -0,0 +1,88 @@
+/*
+ * 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.web.search;
+
+import java.util.List;
+
+import dev.langchain4j.web.search.WebSearchEngine;
+import dev.langchain4j.web.search.WebSearchOrganicResult;
+import dev.langchain4j.web.search.WebSearchRequest;
+import dev.langchain4j.web.search.tavily.TavilyWebSearchEngine;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.Exchange;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// Get an API key at https://app.tavily.com/
+@EnabledIfEnvironmentVariable(named = "TAVILY_API_KEY", matches = ".*")
+public class LangChain4jTavilyWebSearchEngineIT extends CamelTestSupport {
+ public static final String WEB_SEARCH_URI =
"langchain4j-web-search:tavilyTest";
+
+ @BindToRegistry("web-search-engine")
+ WebSearchEngine tavilyWebSearchEngine = TavilyWebSearchEngine.builder()
+ .apiKey(System.getenv("TAVILY_API_KEY"))
+ .includeRawContent(true)
+ .build();
+
+ @BindToRegistry("web-search-request")
+ WebSearchRequest request = WebSearchRequest.builder()
+ .searchTerms("Who won the European Cup in 2024?")
+ .maxResults(2)
+ .build();
+
+ @Test
+ void testSimpleSearch() {
+ Exchange result = fluentTemplate.to(WEB_SEARCH_URI)
+ .withBody("Who won the European Cup in 2024?")
+ .request(Exchange.class);
+
+ assertNotNull(result, "An Exchange is expected.");
+
+ String organicResult = result.getIn().getBody(String.class);
+ assertNotNull(organicResult, "For this web search a content value is
expected as a String.");
+ }
+
+ @Test
+ void testSearchWithParams() {
+ String uri = String.format("%s?maxResults=2&resultType=%s",
WEB_SEARCH_URI,
+
LangChain4jWebSearchResultType.LANGCHAIN4J_WEB_SEARCH_ORGANIC_RESULT);
+
+ Exchange result = fluentTemplate.to(uri)
+ .withBody("Who won the European Cup in 2024?")
+ .request(Exchange.class);
+
+ assertNotNull(result, "An Exchange is expected.");
+
+ List<WebSearchOrganicResult> listResult =
result.getIn().getBody(List.class);
+ assertNotNull(listResult, "The list results from the Tavily Search
Engine shouldn't be null.");
+ assertNotEquals(0, listResult.get(0), "The list results from the
Tavily Search Engine shouldn't be empty.");
+ assertNotNull(listResult.get(0).content(), "The first result from the
Tavily Search Engine should contain content.");
+
+ }
+
+ @Test
+ void advancedRequestTest() {
+ List<String> response = template.requestBody(WEB_SEARCH_URI, null,
List.class);
+ assertNotNull(response, "An Exchange is expected.");
+ assertNotEquals(0, response.get(0), "The list results from the Tavily
Search Engine shouldn't be empty.");
+ }
+
+}
diff --git a/components/camel-ai/pom.xml b/components/camel-ai/pom.xml
index ada306d3cfe..30b7d33fa74 100644
--- a/components/camel-ai/pom.xml
+++ b/components/camel-ai/pom.xml
@@ -39,6 +39,7 @@
<module>camel-langchain4j-core</module>
<module>camel-langchain4j-chat</module>
<module>camel-langchain4j-embeddings</module>
+ <module>camel-langchain4j-web-search</module>
<module>camel-milvus</module>
<module>camel-pinecone</module>
<module>camel-qdrant</module>
diff --git
a/docs/components/modules/ROOT/examples/json/langchain4j-web-search.json
b/docs/components/modules/ROOT/examples/json/langchain4j-web-search.json
new file mode 120000
index 00000000000..ce0432d6b37
--- /dev/null
+++ b/docs/components/modules/ROOT/examples/json/langchain4j-web-search.json
@@ -0,0 +1 @@
+../../../../../../components/camel-ai/camel-langchain4j-web-search/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/web/search/langchain4j-web-search.json
\ No newline at end of file
diff --git a/docs/components/modules/ROOT/nav.adoc
b/docs/components/modules/ROOT/nav.adoc
index b6ca855b85d..17470b8cf78 100644
--- a/docs/components/modules/ROOT/nav.adoc
+++ b/docs/components/modules/ROOT/nav.adoc
@@ -9,6 +9,7 @@
*** xref:djl-component.adoc[Deep Java Library]
*** xref:langchain4j-chat-component.adoc[langChain4j Chat]
*** xref:langchain4j-embeddings-component.adoc[LangChain4j Embeddings]
+*** xref:langchain4j-web-search-component.adoc[LangChain4j Web Search]
*** xref:milvus-component.adoc[Milvus]
*** xref:pinecone-component.adoc[Pinecone]
*** xref:qdrant-component.adoc[Qdrant]
diff --git
a/docs/components/modules/ROOT/pages/langchain4j-web-search-component.adoc
b/docs/components/modules/ROOT/pages/langchain4j-web-search-component.adoc
new file mode 120000
index 00000000000..c8328e90e3d
--- /dev/null
+++ b/docs/components/modules/ROOT/pages/langchain4j-web-search-component.adoc
@@ -0,0 +1 @@
+../../../../../components/camel-ai/camel-langchain4j-web-search/src/main/docs/langchain4j-web-search-component.adoc
\ No newline at end of file
diff --git a/parent/pom.xml b/parent/pom.xml
index 7949383e746..5f0dad26113 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -1743,6 +1743,11 @@
<artifactId>camel-langchain4j-embeddings</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-langchain4j-web-search</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-language</artifactId>