diff --git a/README.md b/README.md index 797078c5b..233bd9822 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ - [GoogleCustomSearch](https://api.js.langchain.com/classes/langchain_tools.GoogleCustomSearch.html) - 环境变量: + - `GOOGLE_PLUGIN_API_PROXY_PREFIX` 与 `DDG_API_PROXY_PREFIX` 变量使用方法一致 - ~~`GOOGLE_API_KEY`~~ `GOOGLE_SEARCH_API_KEY` - `GOOGLE_CSE_ID` - 申请参考:[说明](https://stackoverflow.com/questions/37083058/programmatically-searching-google-in-python-using-custom-search) @@ -78,7 +79,9 @@ - ChooseSearchEngine(作者:[hang666](https://github.com/hang666)) - - 环境变量:`CHOOSE_SEARCH_ENGINE` + - 环境变量: + - `CHOOSE_SEARCH_ENGINE` + - `GOOGLE_PLUGIN_API_PROXY_PREFIX` 与 `DDG_API_PROXY_PREFIX` 变量使用方法一致,只会对 google 进行代理 可选项如下: diff --git a/app/api/langchain-tools/google_custom_search.ts b/app/api/langchain-tools/google_custom_search.ts new file mode 100644 index 000000000..e9aa7fc1a --- /dev/null +++ b/app/api/langchain-tools/google_custom_search.ts @@ -0,0 +1,85 @@ +import { getEnvironmentVariable } from "@langchain/core/utils/env"; +import { Tool } from "@langchain/core/tools"; + +const API_PROXY_PREFIX = process.env.GOOGLE_PLUGIN_API_PROXY_PREFIX ?? ""; + +/** + * Interface for parameters required by GoogleCustomSearch class. + */ +export interface GoogleCustomSearchParams { + apiKey?: string; + googleCSEId?: string; +} + +/** + * Class that uses the Google Search API to perform custom searches. + * Requires environment variables `GOOGLE_API_KEY` and `GOOGLE_CSE_ID` to + * be set. + */ +export class GoogleCustomSearch extends Tool { + static lc_name() { + return "GoogleCustomSearch"; + } + + get lc_secrets(): { [key: string]: string } | undefined { + return { + apiKey: "GOOGLE_API_KEY", + }; + } + + name = "google-custom-search"; + + protected apiKey: string; + + protected googleCSEId: string; + + description = + "a custom search engine. useful for when you need to answer questions about current events. input should be a search query. outputs a JSON array of results."; + + constructor( + fields: GoogleCustomSearchParams = { + apiKey: getEnvironmentVariable("GOOGLE_API_KEY"), + googleCSEId: getEnvironmentVariable("GOOGLE_CSE_ID"), + }, + ) { + super(...arguments); + if (!fields.apiKey) { + throw new Error( + `Google API key not set. You can set it as "GOOGLE_API_KEY" in your environment variables.`, + ); + } + if (!fields.googleCSEId) { + throw new Error( + `Google custom search engine id not set. You can set it as "GOOGLE_CSE_ID" in your environment variables.`, + ); + } + this.apiKey = fields.apiKey; + this.googleCSEId = fields.googleCSEId; + } + + async _call(input: string) { + const res = await fetch( + `${API_PROXY_PREFIX}https://www.googleapis.com/customsearch/v1?key=${this.apiKey}&cx=${ + this.googleCSEId + }&q=${encodeURIComponent(input)}`, + ); + + if (!res.ok) { + throw new Error( + `Got ${res.status} error from Google custom search: ${res.statusText}`, + ); + } + + const json = await res.json(); + + const results = + json?.items?.map( + (item: { title?: string; link?: string; snippet?: string }) => ({ + title: item.title, + link: item.link, + snippet: item.snippet, + }), + ) ?? []; + return JSON.stringify(results); + } +} diff --git a/app/api/langchain-tools/google_search.ts b/app/api/langchain-tools/google_search.ts index 8eed5131e..9d118b1d5 100644 --- a/app/api/langchain-tools/google_search.ts +++ b/app/api/langchain-tools/google_search.ts @@ -4,6 +4,8 @@ import { Tool } from "@langchain/core/tools"; import * as cheerio from "cheerio"; import { getRandomUserAgent } from "./ua_tools"; +const API_PROXY_PREFIX = process.env.GOOGLE_PLUGIN_API_PROXY_PREFIX ?? ""; + interface SearchResults { /** The web results of the search. */ results: SearchResult[]; @@ -31,7 +33,7 @@ async function search( const headers = new Headers(); headers.append("User-Agent", getRandomUserAgent()); const resp = await fetch( - `https://www.google.com/search?nfpr=1&num=${maxResults}&pws=0&q=${encodeURIComponent( + `${API_PROXY_PREFIX}https://www.google.com/search?nfpr=1&num=${maxResults}&pws=0&q=${encodeURIComponent( input, )}`, { diff --git a/app/api/langchain-tools/langchian-tool-index.ts b/app/api/langchain-tools/langchian-tool-index.ts index 5f19f703b..1028c985e 100644 --- a/app/api/langchain-tools/langchian-tool-index.ts +++ b/app/api/langchain-tools/langchian-tool-index.ts @@ -8,10 +8,6 @@ export { Serper, type SerperParameters, } from "@langchain/community/tools/serper"; -export { - GoogleCustomSearch, - type GoogleCustomSearchParams, -} from "@langchain/community/tools/google_custom_search"; export { AIPluginTool } from "@langchain/community/tools/aiplugin"; export { WikipediaQueryRun, diff --git a/app/api/langchain/tool/agent/agentapi.ts b/app/api/langchain/tool/agent/agentapi.ts index 67e4ee4c0..4459f21d7 100644 --- a/app/api/langchain/tool/agent/agentapi.ts +++ b/app/api/langchain/tool/agent/agentapi.ts @@ -28,6 +28,7 @@ import { import { convertToOpenAITool } from "@langchain/core/utils/function_calling"; import { BaiduSearch } from "@/app/api/langchain-tools/baidu_search"; import { GoogleSearch } from "@/app/api/langchain-tools/google_search"; +import { GoogleCustomSearch } from "@/app/api/langchain-tools/google_custom_search"; import { formatToOpenAIToolMessages } from "langchain/agents/format_scratchpad/openai_tools"; import { OpenAIToolsAgentOutputParser, @@ -49,7 +50,6 @@ import { AIMessage, } from "@langchain/core/messages"; import { MultimodalContent } from "@/app/client/api"; -import { GoogleCustomSearch } from "@/app/api/langchain-tools/langchian-tool-index"; import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama"; export interface RequestMessage {