mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-05-22 21:50:16 +09:00
81 lines
2.1 KiB
TypeScript
81 lines
2.1 KiB
TypeScript
import { decode } from "html-entities";
|
|
import { convert as htmlToText } from "html-to-text";
|
|
import { Tool } from "langchain/tools";
|
|
import * as cheerio from "cheerio";
|
|
import { getRandomUserAgent } from "./ua_tools";
|
|
|
|
interface SearchResults {
|
|
/** The web results of the search. */
|
|
results: SearchResult[];
|
|
}
|
|
|
|
interface SearchResult {
|
|
/** The URL of the result. */
|
|
url: string;
|
|
/** The title of the result. */
|
|
title: string;
|
|
/**
|
|
* The sanitized description of the result.
|
|
* Bold tags will still be present in this string.
|
|
*/
|
|
description: string;
|
|
}
|
|
|
|
async function search(
|
|
input: string,
|
|
maxResults: number,
|
|
): Promise<SearchResults> {
|
|
const results: SearchResults = {
|
|
results: [],
|
|
};
|
|
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(
|
|
input,
|
|
)}`,
|
|
{
|
|
headers: headers,
|
|
},
|
|
);
|
|
const respCheerio = cheerio.load(await resp.text());
|
|
respCheerio("div.g").each((i, elem) => {
|
|
const item = cheerio.load(elem);
|
|
const linkElement = item("a");
|
|
const url = (linkElement.attr("href") ?? "").trim();
|
|
if (url !== "" && url !== "#") {
|
|
const title = decode(item("h3").text());
|
|
const description = item(`div[data-sncf~="1"]`).text().trim();
|
|
results.results.push({
|
|
url,
|
|
title,
|
|
description,
|
|
});
|
|
}
|
|
});
|
|
return results;
|
|
}
|
|
|
|
export class GoogleSearch extends Tool {
|
|
name = "google_search";
|
|
maxResults = 6;
|
|
|
|
/** @ignore */
|
|
async _call(input: string) {
|
|
const searchResults = await search(input, this.maxResults);
|
|
|
|
if (searchResults.results.length === 0) {
|
|
return "No good search result found";
|
|
}
|
|
|
|
const results = searchResults.results
|
|
.slice(0, this.maxResults)
|
|
.map(({ title, description, url }) => htmlToText(description))
|
|
.join("\n\n");
|
|
return results;
|
|
}
|
|
|
|
description =
|
|
"a search engine. useful for when you need to answer questions about current events. input should be a search query.";
|
|
}
|