diff --git a/docker/.env.example b/docker/.env.example index 23789af45847e87f55aa5c8de0d144c232159565..6368a1900b783876aeb206a1e2c55982f7e5eae4 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -232,4 +232,7 @@ GID='1000' # AGENT_GSE_CTX= #------ Serper.dev ----------- https://serper.dev/ -# AGENT_SERPER_DEV_KEY= \ No newline at end of file +# AGENT_SERPER_DEV_KEY= + +#------ Bing Search ----------- https://portal.azure.com/ +# AGENT_BING_SEARCH_API_KEY= \ No newline at end of file diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx index 15d18178f0e2f27713cb3c92f93b521cf097a77c..3d579ed43ae18a8a7e24a6f32b7eb37df68869ab 100644 --- a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/SearchProviderOptions/index.jsx @@ -6,6 +6,7 @@ export function GoogleSearchOptions({ settings }) { <a href="https://programmablesearchengine.google.com/controlpanel/create" target="_blank" + rel="noreferrer" className="text-blue-300 underline" > from Google here. @@ -57,6 +58,7 @@ export function SerperDotDevOptions({ settings }) { <a href="https://serper.dev" target="_blank" + rel="noreferrer" className="text-blue-300 underline" > from Serper.dev. @@ -82,3 +84,66 @@ export function SerperDotDevOptions({ settings }) { </> ); } + +export function BingSearchOptions({ settings }) { + return ( + <> + <p className="text-sm text-white/60 my-2"> + You can get a Bing Web Search API subscription key{" "} + <a + href="https://portal.azure.com/" + target="_blank" + rel="noreferrer" + className="text-blue-300 underline" + > + from the Azure portal. + </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::AgentBingSearchApiKey" + 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="Bing Web Search API Key" + defaultValue={settings?.AgentBingSearchApiKey ? "*".repeat(20) : ""} + required={true} + autoComplete="off" + spellCheck={false} + /> + </div> + </div> + <p className="text-sm text-white/60 my-2"> + To set up a Bing Web Search API subscription: + </p> + <ol className="list-decimal text-sm text-white/60 ml-6"> + <li> + Go to the Azure portal:{" "} + <a + href="https://portal.azure.com/" + target="_blank" + rel="noreferrer" + className="text-blue-300 underline" + > + https://portal.azure.com/ + </a> + </li> + <li>Create a new Azure account or sign in with an existing one.</li> + <li> + Navigate to the "Create a resource" section and search for "Bing + Search v7". + </li> + <li> + Select the "Bing Search v7" resource and create a new subscription. + </li> + <li> + Choose the pricing tier that suits your needs (free tier available). + </li> + <li>Obtain the API key for your Bing Web Search subscription.</li> + </ol> + </> + ); +} diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/icons/bing.png b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/icons/bing.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe1c8365c61e09ea36409220c2a7f739bdb78b0 Binary files /dev/null and b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/icons/bing.png differ diff --git a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx index 0581983fa2fdfc2ecc2da327c5e3a958692cc717..8e8f054ea08c532d7a506a1aefdcf9ce6ad171f5 100644 --- a/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/AgentConfig/WebSearchSelection/index.jsx @@ -2,11 +2,13 @@ import React, { useEffect, useRef, useState } from "react"; 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 { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react"; import SearchProviderItem from "./SearchProviderItem"; import { SerperDotDevOptions, GoogleSearchOptions, + BingSearchOptions, } from "./SearchProviderOptions"; const SEARCH_PROVIDERS = [ @@ -34,6 +36,14 @@ const SEARCH_PROVIDERS = [ description: "Serper.dev web-search. Free account with a 2,500 calls, but then paid.", }, + { + name: "Bing Search", + value: "bing-search", + logo: BingSearchIcon, + options: (settings) => <BingSearchOptions settings={settings} />, + description: + "Web search powered by the Bing Search API. Free for 1000 queries per month.", + }, ]; export default function AgentWebSearchSelection({ diff --git a/server/.env.example b/server/.env.example index e38250beb37ad413eaa5b226b28f8057ee95caec..f51d61771800751b7ec72f100e7de212fd025975 100644 --- a/server/.env.example +++ b/server/.env.example @@ -228,4 +228,7 @@ TTS_PROVIDER="native" # AGENT_GSE_CTX= #------ Serper.dev ----------- https://serper.dev/ -# AGENT_SERPER_DEV_KEY= \ No newline at end of file +# AGENT_SERPER_DEV_KEY= + +#------ Bing Search ----------- https://portal.azure.com/ +# AGENT_BING_SEARCH_API_KEY= diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js index 52393a02faa1a10c4570843191edc5ae05df25ff..ac0523198479895f8d13ec448516dd28509d10fb 100644 --- a/server/models/systemSettings.js +++ b/server/models/systemSettings.js @@ -70,7 +70,11 @@ const SystemSettings = { agent_search_provider: (update) => { try { if (update === "none") return null; - if (!["google-search-engine", "serper-dot-dev"].includes(update)) + if ( + !["google-search-engine", "serper-dot-dev", "bing-search"].includes( + update + ) + ) throw new Error("Invalid SERP provider."); return String(update); } catch (e) { @@ -171,6 +175,7 @@ const SystemSettings = { AgentGoogleSearchEngineId: process.env.AGENT_GSE_CTX || null, AgentGoogleSearchEngineKey: process.env.AGENT_GSE_KEY || null, AgentSerperApiKey: process.env.AGENT_SERPER_DEV_KEY || null, + AgentBingSearchApiKey: process.env.AGENT_BING_SEARCH_API_KEY || null, }; }, diff --git a/server/utils/agents/aibitat/plugins/web-browsing.js b/server/utils/agents/aibitat/plugins/web-browsing.js index 198b3ec55477615976975a87fdc1bc4682f3c609..b30688f174904da5e8f0762e14133274b334c511 100644 --- a/server/utils/agents/aibitat/plugins/web-browsing.js +++ b/server/utils/agents/aibitat/plugins/web-browsing.js @@ -65,6 +65,9 @@ const webBrowsing = { case "serper-dot-dev": engine = "_serperDotDev"; break; + case "bing-search": + engine = "_bingWebSearch"; + break; default: engine = "_googleSearchEngine"; } @@ -172,6 +175,49 @@ const webBrowsing = { return `No information was found online for the search query.`; return JSON.stringify(data); }, + _bingWebSearch: async function (query) { + if (!process.env.AGENT_BING_SEARCH_API_KEY) { + this.super.introspect( + `${this.caller}: I can't use Bing Web Search because the user has not defined the required API key.\nVisit: https://portal.azure.com/ to create the API key.` + ); + return `Search is disabled and no content was found. This functionality is disabled because the user has not set it up yet.`; + } + + const searchURL = new URL( + "https://api.bing.microsoft.com/v7.0/search" + ); + searchURL.searchParams.append("q", query); + + this.super.introspect( + `${this.caller}: Using Bing Web Search to search for "${ + query.length > 100 ? `${query.slice(0, 100)}...` : query + }"` + ); + + const searchResponse = await fetch(searchURL, { + headers: { + "Ocp-Apim-Subscription-Key": + process.env.AGENT_BING_SEARCH_API_KEY, + }, + }) + .then((res) => res.json()) + .then((data) => { + const searchResults = data.webPages?.value || []; + return searchResults.map((result) => ({ + title: result.name, + link: result.url, + snippet: result.snippet, + })); + }) + .catch((e) => { + console.log(e); + return []; + }); + + if (searchResponse.length === 0) + return `No information was found online for the search query.`; + return JSON.stringify(searchResponse); + }, }); }, }; diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js index c95ccd57d01fc9968bb2deaf391ad777178ddc3d..d6900ae57f9177db8adaf20426e631556cdefb5d 100644 --- a/server/utils/helpers/updateENV.js +++ b/server/utils/helpers/updateENV.js @@ -399,6 +399,10 @@ const KEY_MAPPING = { envKey: "AGENT_SERPER_DEV_KEY", checks: [], }, + AgentBingSearchApiKey: { + envKey: "AGENT_BING_SEARCH_API_KEY", + checks: [], + }, // TTS/STT Integration ENVS TextToSpeechProvider: { @@ -762,6 +766,7 @@ async function dumpENV() { "AGENT_GSE_CTX", "AGENT_GSE_KEY", "AGENT_SERPER_DEV_KEY", + "AGENT_BING_SEARCH_API_KEY", ]; // Simple sanitization of each value to prevent ENV injection via newline or quote escaping.