Skip to content

Commit

Permalink
[FEATURE] Adds SearchApi as WebSearchEngine and Tool (langchain4j#1216)
Browse files Browse the repository at this point in the history
  • Loading branch information
LangChain4j committed Aug 22, 2024
1 parent 99ed696 commit 2e47b12
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 17 deletions.
6 changes: 3 additions & 3 deletions docs/docs/integrations/web-search/searchapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ Add the following dependencies to your project's `pom.xml`:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-web-search-engine-searchapi</artifactId>
<version>{your-version}</version> <!-- Specify langchain4j version here -->
<version>0.34.0</version>
</dependency>
```

or project's `build.gradle`:

```groovy
implementation 'dev.langchain4j:langchain4j-web-search-engine-searchapi:{your-version}'
implementation 'dev.langchain4j:langchain4j-web-search-engine-searchapi:0.34.0'
```

### Example code:
Expand All @@ -40,7 +40,7 @@ import dev.langchain4j.web.search.searchapi.SearchApiWebSearchEngine;
public class SearchApiTool {

interface Assistant {
@dev.langchain4j.service.SystemMessage({
@SystemMessage({
"You are a web search support agent.",
"If there is any event that has not happened yet",
"You MUST create a web search request with user query and",
Expand Down
18 changes: 18 additions & 0 deletions langchain4j-core/src/main/java/dev/langchain4j/internal/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;

import static java.net.HttpURLConnection.HTTP_OK;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;

/**
* Utility methods.
Expand Down Expand Up @@ -273,4 +275,20 @@ public static <T> List<T> copyIfNotNull(List<T> list) {

return unmodifiableList(list);
}


/**
* Returns an (unmodifiable) copy of the provided map.
* Returns <code>null</code> if the provided map is <code>null</code>.
*
* @param map The map to copy.
* @return The copy of the provided map.
*/
public static <K,V> Map<K,V> copyIfNotNull(Map<K,V> map) {
if (map == null) {
return null;
}

return unmodifiableMap(map);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.UUID;
import java.util.*;
import java.util.stream.Stream;

import static dev.langchain4j.internal.Utils.quoted;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static java.util.Collections.*;
import static org.assertj.core.api.Assertions.*;

@SuppressWarnings({"ObviousNullCheck", "ConstantValue"})
class UtilsTest {
Expand Down Expand Up @@ -215,13 +211,20 @@ public void test_readBytes() throws IOException {
}

@Test
void test_copyIfNotNull() {
assertThat(Utils.copyIfNotNull(null)).isNull();
void test_copyIfNotNull_List() {
assertThat(Utils.copyIfNotNull((List<?>) null)).isNull();
assertThat(Utils.copyIfNotNull(emptyList())).isEmpty();
assertThat(Utils.copyIfNotNull(singletonList("one"))).containsExactly("one");
assertThat(Utils.copyIfNotNull(asList("one", "two"))).containsExactly("one", "two");
}

@Test
void test_copyIfNotNull_Map() {
assertThat(Utils.copyIfNotNull((Map<?, ?>)null)).isNull();
assertThat(Utils.copyIfNotNull(emptyMap())).isEmpty();
assertThat(Utils.copyIfNotNull(singletonMap("key", "value"))).containsExactly(entry("key", "value"));
}

@Test
void test_ensureTrailingForwardSlash() {
assertThat(Utils.ensureTrailingForwardSlash("https://example.com")).isEqualTo("https://example.com/");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

interface SearchApi {

@GET("/api/v1/search")
@GET("api/v1/search")
Call<SearchApiWebSearchResponse> search(@QueryMap Map<String, Object> params,
@Header("Authorization") String bearerToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Map;
import java.util.stream.Collectors;

import static dev.langchain4j.internal.Utils.copyIfNotNull;
import static dev.langchain4j.internal.Utils.getOrDefault;
import static dev.langchain4j.internal.ValidationUtils.ensureNotBlank;
import static java.time.Duration.ofSeconds;
Expand All @@ -25,7 +26,7 @@
*/
public class SearchApiWebSearchEngine implements WebSearchEngine {

private static final String BASE_URL = "https://www.searchapi.io";
private static final String DEFAULT_BASE_URL = "https://www.searchapi.io";
private static final String DEFAULT_ENGINE = "google";

private final String apiKey;
Expand Down Expand Up @@ -54,10 +55,10 @@ public SearchApiWebSearchEngine(String apiKey,
Map<String, Object> optionalParameters) {
this.apiKey = ensureNotBlank(apiKey, "apiKey");
this.engine = getOrDefault(engine, DEFAULT_ENGINE);
this.optionalParameters = getOrDefault(optionalParameters, new HashMap<>());
this.optionalParameters = getOrDefault(copyIfNotNull(optionalParameters), new HashMap<>());
this.client = SearchApiClient.builder()
.timeout(getOrDefault(timeout, ofSeconds(30)))
.baseUrl(getOrDefault(baseUrl, BASE_URL))
.baseUrl(getOrDefault(baseUrl, DEFAULT_BASE_URL))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.Builder;
import lombok.Getter;

import java.util.HashMap;
import java.util.Map;

@Getter
Expand All @@ -25,7 +26,7 @@ class SearchApiWebSearchRequest {
this.engine = engine;
this.apiKey = apiKey;
this.query = query;
this.finalOptionalParameters = optionalParameters;
this.finalOptionalParameters = new HashMap<>(optionalParameters);
if (additionalRequestParameters != null) {
finalOptionalParameters.putAll(additionalRequestParameters);
}
Expand Down

0 comments on commit 2e47b12

Please sign in to comment.