From b8b55b5899a9bd5f095d8ad18e4b7ddaf5651221 Mon Sep 17 00:00:00 2001 From: Timothy Carambat <rambat1010@gmail.com> Date: Thu, 5 Sep 2024 10:36:46 -0700 Subject: [PATCH] Feature/add searchapi web browsing (#2224) * Add SearchApi to web browsing * UI modifications for SearchAPI --------- Co-authored-by: Sebastjan Prachovskij <sebastjan.prachovskij@gmail.com> --- .vscode/settings.json | 1 + docker/.env.example | 4 + docker/HOW_TO_USE_DOCKER.md | 4 +- .../SearchProviderOptions/index.jsx | 77 ++++++++++++++++++ .../WebSearchSelection/icons/searchapi.png | Bin 0 -> 4477 bytes .../Admin/Agents/WebSearchSelection/index.jsx | 10 +++ server/.env.example | 4 + server/models/systemSettings.js | 3 + .../agents/aibitat/plugins/web-browsing.js | 69 ++++++++++++++++ server/utils/helpers/updateENV.js | 8 ++ 10 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pages/Admin/Agents/WebSearchSelection/icons/searchapi.png diff --git a/.vscode/settings.json b/.vscode/settings.json index 549fd1574..4769a939c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -41,6 +41,7 @@ "Qdrant", "royalblue", "searxng", + "SearchApi", "Serper", "Serply", "streamable", diff --git a/docker/.env.example b/docker/.env.example index 56be87cb4..1521a307a 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -252,6 +252,10 @@ GID='1000' # AGENT_GSE_KEY= # AGENT_GSE_CTX= +#------ SearchApi.io ----------- https://www.searchapi.io/ +# AGENT_SEARCHAPI_API_KEY= +# AGENT_SEARCHAPI_ENGINE=google + #------ Serper.dev ----------- https://serper.dev/ # AGENT_SERPER_DEV_KEY= diff --git a/docker/HOW_TO_USE_DOCKER.md b/docker/HOW_TO_USE_DOCKER.md index 1e95bd8a0..2eeaee060 100644 --- a/docker/HOW_TO_USE_DOCKER.md +++ b/docker/HOW_TO_USE_DOCKER.md @@ -117,8 +117,8 @@ services: - WHISPER_PROVIDER=local - TTS_PROVIDER=native - PASSWORDMINCHAR=8 - - AGENT_SERPER_DEV_KEY="SERPER DEV API KEY" - - AGENT_SERPLY_API_KEY="Serply.io API KEY" + # Add any other keys here for services or settings + # you can find in the docker/.env.example file volumes: - anythingllm_storage:/app/server/storage restart: always diff --git a/frontend/src/pages/Admin/Agents/WebSearchSelection/SearchProviderOptions/index.jsx b/frontend/src/pages/Admin/Agents/WebSearchSelection/SearchProviderOptions/index.jsx index f7ad09c03..1e5349857 100644 --- a/frontend/src/pages/Admin/Agents/WebSearchSelection/SearchProviderOptions/index.jsx +++ b/frontend/src/pages/Admin/Agents/WebSearchSelection/SearchProviderOptions/index.jsx @@ -50,6 +50,83 @@ export function GoogleSearchOptions({ settings }) { ); } +const SearchApiEngines = [ + { name: "Google Search", value: "google" }, + { name: "Google Maps", value: "google_maps" }, + { name: "Google Shopping", value: "google_shopping" }, + { name: "Google News", value: "google_news" }, + { name: "Google Jobs", value: "google_jobs" }, + { name: "Google Scholar", value: "google_scholar" }, + { name: "Google Finance", value: "google_finance" }, + { name: "Google Patents", value: "google_patents" }, + { name: "YouTube", value: "youtube" }, + { name: "Bing", value: "bing" }, + { name: "Bing News", value: "bing_news" }, + { name: "Amazon Product Search", value: "amazon_search" }, + { name: "Baidu", value: "baidu" }, +]; +export function SearchApiOptions({ settings }) { + return ( + <> + <p className="text-sm text-white/60 my-2"> + You can get a free API key{" "} + <a + href="https://www.searchapi.io/" + target="_blank" + rel="noreferrer" + className="text-blue-300 underline" + > + from SearchApi. + </a> + </p> + <div className="flex gap-x-4"> + <div className="flex flex-col w-60"> + <label className="text-white text-sm font-semibold block mb-3"> + API Key + </label> + <input + type="password" + name="env::AgentSearchApiKey" + className="border-none bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5" + placeholder="SearchApi API Key" + defaultValue={settings?.AgentSearchApiKey ? "*".repeat(20) : ""} + required={true} + autoComplete="off" + spellCheck={false} + /> + </div> + <div className="flex flex-col w-60"> + <label className="text-white text-sm font-semibold block mb-3"> + Engine + </label> + <select + name="env::AgentSearchApiEngine" + required={true} + className="border-none bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5" + defaultValue={settings?.AgentSearchApiEngine || "google"} + > + {SearchApiEngines.map(({ name, value }) => ( + <option key={name} value={value}> + {name} + </option> + ))} + </select> + {/* <input + type="text" + name="env::AgentSearchApiEngine" + className="border-none bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5" + placeholder="SearchApi engine (Google, Bing...)" + defaultValue={settings?.AgentSearchApiEngine || "google"} + required={true} + autoComplete="off" + spellCheck={false} + /> */} + </div> + </div> + </> + ); +} + export function SerperDotDevOptions({ settings }) { return ( <> diff --git a/frontend/src/pages/Admin/Agents/WebSearchSelection/icons/searchapi.png b/frontend/src/pages/Admin/Agents/WebSearchSelection/icons/searchapi.png new file mode 100644 index 0000000000000000000000000000000000000000..65bae79bf4363ac4a534143177b244a8b0161b26 GIT binary patch literal 4477 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 Ry!#YBqnikLsowo3{{(zoV95Xg literal 0 HcmV?d00001 diff --git a/frontend/src/pages/Admin/Agents/WebSearchSelection/index.jsx b/frontend/src/pages/Admin/Agents/WebSearchSelection/index.jsx index c1f14cc6a..fd201fb90 100644 --- a/frontend/src/pages/Admin/Agents/WebSearchSelection/index.jsx +++ b/frontend/src/pages/Admin/Agents/WebSearchSelection/index.jsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef, useState } from "react"; import AnythingLLMIcon from "@/media/logo/anything-llm-icon.png"; import GoogleSearchIcon from "./icons/google.png"; +import SearchApiIcon from "./icons/searchapi.png"; import SerperDotDevIcon from "./icons/serper.png"; import BingSearchIcon from "./icons/bing.png"; import SerplySearchIcon from "./icons/serply.png"; @@ -14,6 +15,7 @@ import { import SearchProviderItem from "./SearchProviderItem"; import WebSearchImage from "@/media/agents/scrape-websites.png"; import { + SearchApiOptions, SerperDotDevOptions, GoogleSearchOptions, BingSearchOptions, @@ -38,6 +40,14 @@ const SEARCH_PROVIDERS = [ description: "Web search powered by a custom Google Search Engine. Free for 100 queries per day.", }, + { + name: "SearchApi", + value: "searchapi", + logo: SearchApiIcon, + options: (settings) => <SearchApiOptions settings={settings} />, + description: + "SearchApi delivers structured data from multiple search engines. Free for 100 queries, but then paid. ", + }, { name: "Serper.dev", value: "serper-dot-dev", diff --git a/server/.env.example b/server/.env.example index 22bd557ee..f942d6832 100644 --- a/server/.env.example +++ b/server/.env.example @@ -241,6 +241,10 @@ TTS_PROVIDER="native" # AGENT_GSE_KEY= # AGENT_GSE_CTX= +#------ SearchApi.io ----------- https://www.searchapi.io/ +# AGENT_SEARCHAPI_API_KEY= +# AGENT_SEARCHAPI_ENGINE=google + #------ Serper.dev ----------- https://serper.dev/ # AGENT_SERPER_DEV_KEY= diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js index b85f3cb8c..e9ae3f3e9 100644 --- a/server/models/systemSettings.js +++ b/server/models/systemSettings.js @@ -81,6 +81,7 @@ const SystemSettings = { if ( ![ "google-search-engine", + "searchapi", "serper-dot-dev", "bing-search", "serply-engine", @@ -218,6 +219,8 @@ const SystemSettings = { // -------------------------------------------------------- AgentGoogleSearchEngineId: process.env.AGENT_GSE_CTX || null, AgentGoogleSearchEngineKey: !!process.env.AGENT_GSE_KEY || null, + AgentSearchApiKey: !!process.env.AGENT_SEARCHAPI_API_KEY || null, + AgentSearchApiEngine: process.env.AGENT_SEARCHAPI_ENGINE || "google", AgentSerperApiKey: !!process.env.AGENT_SERPER_DEV_KEY || null, AgentBingSearchApiKey: !!process.env.AGENT_BING_SEARCH_API_KEY || null, AgentSerplyApiKey: !!process.env.AGENT_SERPLY_API_KEY || null, diff --git a/server/utils/agents/aibitat/plugins/web-browsing.js b/server/utils/agents/aibitat/plugins/web-browsing.js index f4269fe13..76849056e 100644 --- a/server/utils/agents/aibitat/plugins/web-browsing.js +++ b/server/utils/agents/aibitat/plugins/web-browsing.js @@ -62,6 +62,9 @@ const webBrowsing = { case "google-search-engine": engine = "_googleSearchEngine"; break; + case "searchapi": + engine = "_searchApi"; + break; case "serper-dot-dev": engine = "_serperDotDev"; break; @@ -130,6 +133,72 @@ const webBrowsing = { return JSON.stringify(data); }, + /** + * Use SearchApi + * SearchApi supports multiple search engines like Google Search, Bing Search, Baidu Search, Google News, YouTube, and many more. + * https://www.searchapi.io/ + */ + _searchApi: async function (query) { + if (!process.env.AGENT_SEARCHAPI_API_KEY) { + this.super.introspect( + `${this.caller}: I can't use SearchApi searching because the user has not defined the required API key.\nVisit: https://www.searchapi.io/ to create the API key for free.` + ); + return `Search is disabled and no content was found. This functionality is disabled because the user has not set it up yet.`; + } + + this.super.introspect( + `${this.caller}: Using SearchApi to search for "${ + query.length > 100 ? `${query.slice(0, 100)}...` : query + }"` + ); + + const engine = process.env.AGENT_SEARCHAPI_ENGINE; + const params = new URLSearchParams({ + engine: engine, + q: query, + }); + + const url = `https://www.searchapi.io/api/v1/search?${params.toString()}`; + const { response, error } = await fetch(url, { + method: "GET", + headers: { + Authorization: `Bearer ${process.env.AGENT_SEARCHAPI_API_KEY}`, + "Content-Type": "application/json", + "X-SearchApi-Source": "AnythingLLM", + }, + }) + .then((res) => res.json()) + .then((data) => { + return { response: data, error: null }; + }) + .catch((e) => { + return { response: null, error: e.message }; + }); + if (error) + return `There was an error searching for content. ${error}`; + + const data = []; + if (response.hasOwnProperty("knowledge_graph")) + data.push(response.knowledge_graph?.description); + if (response.hasOwnProperty("answer_box")) + data.push(response.answer_box?.answer); + response.organic_results?.forEach((searchResult) => { + const { title, link, snippet } = searchResult; + data.push({ + title, + link, + snippet, + }); + }); + + if (data.length === 0) + return `No information was found online for the search query.`; + this.super.introspect( + `${this.caller}: I found ${data.length} results - looking over them now.` + ); + return JSON.stringify(data); + }, + /** * Use Serper.dev * Free to set up, easy to use, 2,500 calls for free one-time diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js index c579da188..af5a460db 100644 --- a/server/utils/helpers/updateENV.js +++ b/server/utils/helpers/updateENV.js @@ -435,6 +435,14 @@ const KEY_MAPPING = { envKey: "AGENT_GSE_KEY", checks: [], }, + AgentSearchApiKey: { + envKey: "AGENT_SEARCHAPI_API_KEY", + checks: [], + }, + AgentSearchApiEngine: { + envKey: "AGENT_SEARCHAPI_ENGINE", + checks: [], + }, AgentSerperApiKey: { envKey: "AGENT_SERPER_DEV_KEY", checks: [],