From 7693240e21a861aa8c4ca4bee9da9d3de4c3fc39 Mon Sep 17 00:00:00 2001 From: Serply <59339358+googio@users.noreply.github.com> Date: Mon, 10 Jun 2024 18:17:41 -0400 Subject: [PATCH] 1646-added serply (#1647) * added serply search api * undo remove of new line --------- Co-authored-by: teampen <136991215+teampen@users.noreply.github.com> --- docker/.env.example | 5 +- docker/HOW_TO_USE_DOCKER.md | 2 +- .../SearchProviderOptions/index.jsx | 35 +++++++++ .../WebSearchSelection/icons/serply.png | Bin 0 -> 4553 bytes .../AgentConfig/WebSearchSelection/index.jsx | 10 +++ server/.env.example | 3 + server/models/systemSettings.js | 3 +- .../agents/aibitat/plugins/web-browsing.js | 69 ++++++++++++++++++ server/utils/helpers/updateENV.js | 5 ++ 9 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/icons/serply.png diff --git a/docker/.env.example b/docker/.env.example index 174a9d692..a38b4c5a2 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -241,4 +241,7 @@ GID='1000' # AGENT_SERPER_DEV_KEY= #------ Bing Search ----------- https://portal.azure.com/ -# AGENT_BING_SEARCH_API_KEY= \ No newline at end of file +# AGENT_BING_SEARCH_API_KEY= + +#------ Serply.io ----------- https://serply.io/ +# AGENT_SERPLY_API_KEY= diff --git a/docker/HOW_TO_USE_DOCKER.md b/docker/HOW_TO_USE_DOCKER.md index fed16a274..f570dce90 100644 --- a/docker/HOW_TO_USE_DOCKER.md +++ b/docker/HOW_TO_USE_DOCKER.md @@ -89,7 +89,6 @@ mintplexlabs/anythingllm; <tr> <td> Docker Compose</td> <td> - version: '3.8' services: anythingllm: @@ -116,6 +115,7 @@ mintplexlabs/anythingllm; - TTS_PROVIDER=native - PASSWORDMINCHAR=8 - AGENT_SERPER_DEV_KEY="SERPER DEV API KEY" + - AGENT_SERPLY_API_KEY="Serply.io API KEY" volumes: - anythingllm_storage:/app/server/storage restart: always diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx index 3d579ed43..58ceb8447 100644 --- a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx @@ -147,3 +147,38 @@ export function BingSearchOptions({ settings }) { </> ); } + +export function SerplySearchOptions({ settings }) { + return ( + <> + <p className="text-sm text-white/60 my-2"> + You can get a free API key{" "} + <a + href="https://serply.io" + target="_blank" + rel="noreferrer" + className="text-blue-300 underline" + > + from Serply.io. + </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-4"> + API Key + </label> + <input + type="password" + name="env::AgentSerplyApiKey" + className="border-none bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" + placeholder="Serply API Key" + defaultValue={settings?.AgentSerplyApiKey ? "*".repeat(20) : ""} + required={true} + autoComplete="off" + spellCheck={false} + /> + </div> + </div> + </> + ); +} diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/icons/serply.png b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/icons/serply.png new file mode 100644 index 0000000000000000000000000000000000000000..8ac0ef7c00d094dfa8f85ad48fd02eb2fc209742 GIT binary patch literal 4553 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 Yt;erp({yhCO<u@!o*QV^sM|;W2bv!b9{>OV literal 0 HcmV?d00001 diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx index 8e8f054ea..0bbc053ab 100644 --- a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx @@ -3,12 +3,14 @@ import AnythingLLMIcon from "@/media/logo/anything-llm-icon.png"; import GoogleSearchIcon from "./icons/google.png"; import SerperDotDevIcon from "./icons/serper.png"; import BingSearchIcon from "./icons/bing.png"; +import SerplySearchIcon from "./icons/serply.png" import { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react"; import SearchProviderItem from "./SearchProviderItem"; import { SerperDotDevOptions, GoogleSearchOptions, BingSearchOptions, + SerplySearchOptions } from "./SearchProviderOptions"; const SEARCH_PROVIDERS = [ @@ -44,6 +46,14 @@ const SEARCH_PROVIDERS = [ description: "Web search powered by the Bing Search API. Free for 1000 queries per month.", }, + { + name: "Serply.io", + value: "serply-engine", + logo: SerplySearchIcon, + options: (settings) => <SerplySearchOptions settings={settings} />, + description: + "Serply.io web-search. Free account with a 100 calls/month forever.", + }, ]; export default function AgentWebSearchSelection({ diff --git a/server/.env.example b/server/.env.example index 6148d594f..a88a8a039 100644 --- a/server/.env.example +++ b/server/.env.example @@ -238,3 +238,6 @@ TTS_PROVIDER="native" #------ Bing Search ----------- https://portal.azure.com/ # AGENT_BING_SEARCH_API_KEY= + +#------ Serply.io ----------- https://serply.io/ +# AGENT_SERPLY_API_KEY= diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js index ac0523198..3cb0456f4 100644 --- a/server/models/systemSettings.js +++ b/server/models/systemSettings.js @@ -71,7 +71,7 @@ const SystemSettings = { try { if (update === "none") return null; if ( - !["google-search-engine", "serper-dot-dev", "bing-search"].includes( + !["google-search-engine", "serper-dot-dev", "bing-search", "serply-engine"].includes( update ) ) @@ -176,6 +176,7 @@ const SystemSettings = { AgentGoogleSearchEngineKey: process.env.AGENT_GSE_KEY || null, 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 b30688f17..00b004cbc 100644 --- a/server/utils/agents/aibitat/plugins/web-browsing.js +++ b/server/utils/agents/aibitat/plugins/web-browsing.js @@ -68,6 +68,9 @@ const webBrowsing = { case "bing-search": engine = "_bingWebSearch"; break; + case "serply-engine": + engine = "_serplyEngine"; + break; default: engine = "_googleSearchEngine"; } @@ -218,6 +221,72 @@ const webBrowsing = { return `No information was found online for the search query.`; return JSON.stringify(searchResponse); }, + _serplyEngine: async function (query, language = "en", hl = "us", limit = 100, device_type = "desktop", proxy_location = "US") { + // query (str): The query to search for + // hl (str): Host Language code to display results in (reference https://developers.google.com/custom-search/docs/xml_results?hl=en#wsInterfaceLanguages) + // limit (int): The maximum number of results to return [10-100, defaults to 100] + // device_type: get results based on desktop/mobile (defaults to desktop) + + if (!process.env.AGENT_SERPLY_API_KEY) { + this.super.introspect( + `${this.caller}: I can't use Serply.io searching because the user has not defined the required API key.\nVisit: https://serply.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 Serply to search for "${ + query.length > 100 ? `${query.slice(0, 100)}...` : query + }"` + ); + + const params = new URLSearchParams({ + q: query, + language: language, + hl, + gl: proxy_location.toUpperCase() + }) + const url = `https://api.serply.io/v1/search/${params.toString()}` + const { response, error } = await fetch( + url, + { + method: "GET", + headers: { + "X-API-KEY": process.env.AGENT_SERPLY_API_KEY, + "Content-Type": "application/json", + "User-Agent": "anything-llm", + "X-Proxy-Location": proxy_location, + "X-User-Agent": device_type + } + } + ) + .then((res) => res.json()) + .then((data) => { + if (data?.message === "Unauthorized"){ + return { response: null, error: "Unauthorized. Please double check your AGENT_SERPLY_API_KEY" }; + } + 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 = []; + response.results?.forEach((searchResult) => { + const { title, link, description } = searchResult; + data.push({ + title, + link, + snippet: description, + }); + }); + + if (data.length === 0) + return `No information was found online for the search query.`; + return JSON.stringify(data); + }, }); }, }; diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js index 1a0e710a9..3f2baf7e3 100644 --- a/server/utils/helpers/updateENV.js +++ b/server/utils/helpers/updateENV.js @@ -403,6 +403,10 @@ const KEY_MAPPING = { envKey: "AGENT_BING_SEARCH_API_KEY", checks: [], }, + AgentSerplyApiKey: { + envKey: "AGENT_SERPLY_API_KEY", + checks: [], + }, // TTS/STT Integration ENVS TextToSpeechProvider: { @@ -769,6 +773,7 @@ async function dumpENV() { "AGENT_GSE_KEY", "AGENT_SERPER_DEV_KEY", "AGENT_BING_SEARCH_API_KEY", + "AGENT_SERPLY_API_KEY" ]; // Simple sanitization of each value to prevent ENV injection via newline or quote escaping. -- GitLab