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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 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: [], -- GitLab