@langchain/community
Version:
Third-party integrations for LangChain.js
1 lines • 21 kB
Source Map (JSON)
{"version":3,"file":"serpapi.cjs","names":["Tool"],"sources":["../../src/tools/serpapi.ts"],"sourcesContent":["import { getEnvironmentVariable } from \"@langchain/core/utils/env\";\nimport { Tool } from \"@langchain/core/tools\";\n\n/**\n * This does not use the `serpapi` package because it appears to cause issues\n * when used in `jest` tests. Part of the issue seems to be that the `serpapi`\n * package imports a wasm module to use instead of native `fetch`, which we\n * don't want anyway.\n *\n * NOTE: you must provide location, gl and hl or your region and language will\n * may not match your location, and will not be deterministic.\n */\n\n// Copied over from `serpapi` package\ninterface BaseParameters {\n /**\n * Parameter defines the device to use to get the results. It can be set to\n * `desktop` (default) to use a regular browser, `tablet` to use a tablet browser\n * (currently using iPads), or `mobile` to use a mobile browser (currently\n * using iPhones).\n */\n device?: \"desktop\" | \"tablet\" | \"mobile\";\n /**\n * Parameter will force SerpApi to fetch the Google results even if a cached\n * version is already present. A cache is served only if the query and all\n * parameters are exactly the same. Cache expires after 1h. Cached searches\n * are free, and are not counted towards your searches per month. It can be set\n * to `false` (default) to allow results from the cache, or `true` to disallow\n * results from the cache. `no_cache` and `async` parameters should not be used together.\n */\n no_cache?: boolean;\n /**\n * Specify the client-side timeout of the request. In milliseconds.\n */\n timeout?: number;\n}\n\nexport interface SerpAPIParameters extends BaseParameters {\n /**\n * Search Query\n * Parameter defines the query you want to search. You can use anything that you\n * would use in a regular Google search. e.g. `inurl:`, `site:`, `intitle:`. We\n * also support advanced search query parameters such as as_dt and as_eq. See the\n * [full list](https://serpapi.com/advanced-google-query-parameters) of supported\n * advanced search query parameters.\n */\n q: string;\n /**\n * Location\n * Parameter defines from where you want the search to originate. If several\n * locations match the location requested, we'll pick the most popular one. Head to\n * [/locations.json API](https://serpapi.com/locations-api) if you need more\n * precise control. location and uule parameters can't be used together. Avoid\n * utilizing location when setting the location outside the U.S. when using Google\n * Shopping and/or Google Product API.\n */\n location?: string;\n /**\n * Encoded Location\n * Parameter is the Google encoded location you want to use for the search. uule\n * and location parameters can't be used together.\n */\n uule?: string;\n /**\n * Google Place ID\n * Parameter defines the id (`CID`) of the Google My Business listing you want to\n * scrape. Also known as Google Place ID.\n */\n ludocid?: string;\n /**\n * Additional Google Place ID\n * Parameter that you might have to use to force the knowledge graph map view to\n * show up. You can find the lsig ID by using our [Local Pack\n * API](https://serpapi.com/local-pack) or [Local Places Results\n * API](https://serpapi.com/local-results).\n * lsig ID is also available via a redirect Google uses within [Google My\n * Business](https://www.google.com/business/).\n */\n lsig?: string;\n /**\n * Google Knowledge Graph ID\n * Parameter defines the id (`KGMID`) of the Google Knowledge Graph listing you\n * want to scrape. Also known as Google Knowledge Graph ID. Searches with kgmid\n * parameter will return results for the originally encrypted search parameters.\n * For some searches, kgmid may override all other parameters except start, and num\n * parameters.\n */\n kgmid?: string;\n /**\n * Google Cached Search Parameters ID\n * Parameter defines the cached search parameters of the Google Search you want to\n * scrape. Searches with si parameter will return results for the originally\n * encrypted search parameters. For some searches, si may override all other\n * parameters except start, and num parameters. si can be used to scrape Google\n * Knowledge Graph Tabs.\n */\n si?: string;\n /**\n * Domain\n * Parameter defines the Google domain to use. It defaults to `google.com`. Head to\n * the [Google domains page](https://serpapi.com/google-domains) for a full list of\n * supported Google domains.\n */\n google_domain?: string;\n /**\n * Country\n * Parameter defines the country to use for the Google search. It's a two-letter\n * country code. (e.g., `us` for the United States, `uk` for United Kingdom, or\n * `fr` for France). Head to the [Google countries\n * page](https://serpapi.com/google-countries) for a full list of supported Google\n * countries.\n */\n gl?: string;\n /**\n * Language\n * Parameter defines the language to use for the Google search. It's a two-letter\n * language code. (e.g., `en` for English, `es` for Spanish, or `fr` for French).\n * Head to the [Google languages page](https://serpapi.com/google-languages) for a\n * full list of supported Google languages.\n */\n hl?: string;\n /**\n * Set Multiple Languages\n * Parameter defines one or multiple languages to limit the search to. It uses\n * `lang_{two-letter language code}` to specify languages and `|` as a delimiter.\n * (e.g., `lang_fr|lang_de` will only search French and German pages). Head to the\n * [Google lr languages page](https://serpapi.com/google-lr-languages) for a full\n * list of supported languages.\n */\n lr?: string;\n /**\n * as_dt\n * Parameter controls whether to include or exclude results from the site named in\n * the as_sitesearch parameter.\n */\n as_dt?: string;\n /**\n * as_epq\n * Parameter identifies a phrase that all documents in the search results must\n * contain. You can also use the [phrase\n * search](https://developers.google.com/custom-search/docs/xml_results#PhraseSearchqt)\n * query term to search for a phrase.\n */\n as_epq?: string;\n /**\n * as_eq\n * Parameter identifies a word or phrase that should not appear in any documents in\n * the search results. You can also use the [exclude\n * query](https://developers.google.com/custom-search/docs/xml_results#Excludeqt)\n * term to ensure that a particular word or phrase will not appear in the documents\n * in a set of search results.\n */\n as_eq?: string;\n /**\n * as_lq\n * Parameter specifies that all search results should contain a link to a\n * particular URL. You can also use the\n * [link:](https://developers.google.com/custom-search/docs/xml_results#BackLinksqt)\n * query term for this type of query.\n */\n as_lq?: string;\n /**\n * as_nlo\n * Parameter specifies the starting value for a search range. Use as_nlo and as_nhi\n * to append an inclusive search range.\n */\n as_nlo?: string;\n /**\n * as_nhi\n * Parameter specifies the ending value for a search range. Use as_nlo and as_nhi\n * to append an inclusive search range.\n */\n as_nhi?: string;\n /**\n * as_oq\n * Parameter provides additional search terms to check for in a document, where\n * each document in the search results must contain at least one of the additional\n * search terms. You can also use the [Boolean\n * OR](https://developers.google.com/custom-search/docs/xml_results#BooleanOrqt)\n * query term for this type of query.\n */\n as_oq?: string;\n /**\n * as_q\n * Parameter provides search terms to check for in a document. This parameter is\n * also commonly used to allow users to specify additional terms to search for\n * within a set of search results.\n */\n as_q?: string;\n /**\n * as_qdr\n * Parameter requests search results from a specified time period (quick date\n * range). The following values are supported:\n * `d[number]`: requests results from the specified number of past days. Example\n * for the past 10 days: `as_qdr=d10`\n * `w[number]`: requests results from the specified number of past weeks.\n * `m[number]`: requests results from the specified number of past months.\n * `y[number]`: requests results from the specified number of past years. Example\n * for the past year: `as_qdr=y`\n */\n as_qdr?: string;\n /**\n * as_rq\n * Parameter specifies that all search results should be pages that are related to\n * the specified URL. The parameter value should be a URL. You can also use the\n * [related:](https://developers.google.com/custom-search/docs/xml_results#RelatedLinksqt)\n * query term for this type of query.\n */\n as_rq?: string;\n /**\n * as_sitesearch\n * Parameter allows you to specify that all search results should be pages from a\n * given site. By setting the as_dt parameter, you can also use it to exclude pages\n * from a given site from your search resutls.\n */\n as_sitesearch?: string;\n /**\n * Advanced Search Parameters\n * (to be searched) parameter defines advanced search parameters that aren't\n * possible in the regular query field. (e.g., advanced search for patents, dates,\n * news, videos, images, apps, or text contents).\n */\n tbs?: string;\n /**\n * Adult Content Filtering\n * Parameter defines the level of filtering for adult content. It can be set to\n * `active`, or `off` (default).\n */\n safe?: string;\n /**\n * Exclude Auto-corrected Results\n * Parameter defines the exclusion of results from an auto-corrected query that is\n * spelled wrong. It can be set to `1` to exclude these results, or `0` to include\n * them (default).\n */\n nfpr?: string;\n /**\n * Results Filtering\n * Parameter defines if the filters for 'Similar Results' and 'Omitted Results' are\n * on or off. It can be set to `1` (default) to enable these filters, or `0` to\n * disable these filters.\n */\n filter?: string;\n /**\n * Search Type\n * (to be matched) parameter defines the type of search you want to do.\n * It can be set to:\n * `(no tbm parameter)`: regular Google Search,\n * `isch`: [Google Images API](https://serpapi.com/images-results),\n * `lcl` - [Google Local API](https://serpapi.com/local-results)\n * `vid`: [Google Videos API](https://serpapi.com/videos-results),\n * `nws`: [Google News API](https://serpapi.com/news-results),\n * `shop`: [Google Shopping API](https://serpapi.com/shopping-results),\n * or any other Google service.\n */\n tbm?: string;\n /**\n * Result Offset\n * Parameter defines the result offset. It skips the given number of results. It's\n * used for pagination. (e.g., `0` (default) is the first page of results, `10` is\n * the 2nd page of results, `20` is the 3rd page of results, etc.).\n * Google Local Results only accepts multiples of `20`(e.g. `20` for the second\n * page results, `40` for the third page results, etc.) as the start value.\n */\n start?: number;\n /**\n * Number of Results\n * Parameter defines the maximum number of results to return. (e.g., `10` (default)\n * returns 10 results, `40` returns 40 results, and `100` returns 100 results).\n */\n num?: string;\n /**\n * Page Number (images)\n * Parameter defines the page number for [Google\n * Images](https://serpapi.com/images-results). There are 100 images per page. This\n * parameter is equivalent to start (offset) = ijn * 100. This parameter works only\n * for [Google Images](https://serpapi.com/images-results) (set tbm to `isch`).\n */\n ijn?: string;\n}\n\ntype UrlParameters = Record<\n string,\n string | number | boolean | undefined | null\n>;\n\n/**\n * Wrapper around SerpAPI.\n *\n * To use, you should have the `serpapi` package installed and the SERPAPI_API_KEY environment variable set.\n */\nexport class SerpAPI extends Tool {\n static lc_name() {\n return \"SerpAPI\";\n }\n\n toJSON() {\n return this.toJSONNotImplemented();\n }\n\n protected key: string;\n\n protected params: Partial<SerpAPIParameters>;\n\n protected baseUrl: string;\n\n constructor(\n apiKey: string | undefined = getEnvironmentVariable(\"SERPAPI_API_KEY\"),\n params: Partial<SerpAPIParameters> = {},\n baseUrl = \"https://serpapi.com\"\n ) {\n super(...arguments);\n\n if (!apiKey) {\n throw new Error(\n \"SerpAPI API key not set. You can set it as SERPAPI_API_KEY in your .env file, or pass it to SerpAPI.\"\n );\n }\n\n this.key = apiKey;\n this.params = params;\n this.baseUrl = baseUrl;\n }\n\n name = \"search\";\n\n /**\n * Builds a URL for the SerpAPI request.\n * @param path The path for the request.\n * @param parameters The parameters for the request.\n * @param baseUrl The base URL for the request.\n * @returns A string representing the built URL.\n */\n protected buildUrl<P extends UrlParameters>(\n path: string,\n parameters: P,\n baseUrl: string\n ): string {\n const nonUndefinedParams: [string, string][] = Object.entries(parameters)\n .filter(([_, value]) => value !== undefined)\n .map(([key, value]) => [key, `${value}`]);\n const searchParams = new URLSearchParams(nonUndefinedParams);\n return `${baseUrl}/${path}?${searchParams}`;\n }\n\n /** @ignore */\n async _call(input: string) {\n const { timeout, ...params } = this.params;\n const resp = await fetch(\n this.buildUrl(\n \"search\",\n {\n ...params,\n api_key: this.key,\n q: input,\n },\n this.baseUrl\n ),\n {\n signal: timeout ? AbortSignal.timeout(timeout) : undefined,\n }\n );\n\n const res = await resp.json();\n\n if (res.error) {\n throw new Error(`Got error from serpAPI: ${res.error}`);\n }\n\n const answer_box = res.answer_box_list\n ? res.answer_box_list[0]\n : res.answer_box;\n if (answer_box) {\n if (answer_box.result) {\n return answer_box.result;\n } else if (answer_box.answer) {\n return answer_box.answer;\n } else if (answer_box.snippet) {\n return answer_box.snippet;\n } else if (answer_box.snippet_highlighted_words) {\n return answer_box.snippet_highlighted_words.toString();\n } else {\n const answer: { [key: string]: string } = {};\n Object.keys(answer_box)\n .filter(\n (k) =>\n !Array.isArray(answer_box[k]) &&\n typeof answer_box[k] !== \"object\" &&\n !(\n typeof answer_box[k] === \"string\" &&\n answer_box[k].startsWith(\"http\")\n )\n )\n .forEach((k) => {\n answer[k] = answer_box[k];\n });\n return JSON.stringify(answer);\n }\n }\n\n if (res.events_results) {\n return JSON.stringify(res.events_results);\n }\n\n if (res.sports_results) {\n return JSON.stringify(res.sports_results);\n }\n\n if (res.top_stories) {\n return JSON.stringify(res.top_stories);\n }\n\n if (res.news_results) {\n return JSON.stringify(res.news_results);\n }\n\n if (res.jobs_results?.jobs) {\n return JSON.stringify(res.jobs_results.jobs);\n }\n\n if (res.questions_and_answers) {\n return JSON.stringify(res.questions_and_answers);\n }\n\n if (res.popular_destinations?.destinations) {\n return JSON.stringify(res.popular_destinations.destinations);\n }\n\n if (res.top_sights?.sights) {\n const sights: Array<{ [key: string]: string }> = res.top_sights.sights\n .map((s: { [key: string]: string }) => ({\n title: s.title,\n description: s.description,\n price: s.price,\n }))\n .slice(0, 8);\n return JSON.stringify(sights);\n }\n\n if (res.shopping_results && res.shopping_results[0]?.title) {\n return JSON.stringify(res.shopping_results.slice(0, 3));\n }\n\n if (res.images_results && res.images_results[0]?.thumbnail) {\n return res.images_results\n .map((ir: { thumbnail: string }) => ir.thumbnail)\n .slice(0, 10)\n .toString();\n }\n\n const snippets = [];\n if (res.knowledge_graph) {\n if (res.knowledge_graph.description) {\n snippets.push(res.knowledge_graph.description);\n }\n\n const title = res.knowledge_graph.title || \"\";\n Object.keys(res.knowledge_graph)\n .filter(\n (k) =>\n typeof res.knowledge_graph[k] === \"string\" &&\n k !== \"title\" &&\n k !== \"description\" &&\n !k.endsWith(\"_stick\") &&\n !k.endsWith(\"_link\") &&\n !k.startsWith(\"http\")\n )\n .forEach((k) =>\n snippets.push(`${title} ${k}: ${res.knowledge_graph[k]}`)\n );\n }\n\n const first_organic_result = res.organic_results?.[0];\n if (first_organic_result) {\n if (first_organic_result.snippet) {\n snippets.push(first_organic_result.snippet);\n } else if (first_organic_result.snippet_highlighted_words) {\n snippets.push(first_organic_result.snippet_highlighted_words);\n } else if (first_organic_result.rich_snippet) {\n snippets.push(first_organic_result.rich_snippet);\n } else if (first_organic_result.rich_snippet_table) {\n snippets.push(first_organic_result.rich_snippet_table);\n } else if (first_organic_result.link) {\n snippets.push(first_organic_result.link);\n }\n }\n\n if (res.buying_guide) {\n snippets.push(res.buying_guide);\n }\n\n if (res.local_results?.places) {\n snippets.push(res.local_results.places);\n }\n\n if (snippets.length > 0) {\n return JSON.stringify(snippets);\n } else {\n return \"No good search result found\";\n }\n }\n\n description =\n \"a search engine. useful for when you need to answer questions about current events. input should be a search query.\";\n}\n"],"mappings":"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"}