feat: 支持duckduckgo搜索插件

This commit is contained in:
Hk-Gosuto
2023-07-29 19:02:57 +08:00
parent be35b50940
commit 1d5e8a9cbf
5 changed files with 141 additions and 61 deletions

View File

@@ -0,0 +1,32 @@
import { SafeSearchType, search } from "duck-duck-scrape";
import { convert as htmlToText } from "html-to-text";
import { Tool } from "langchain/tools";
export class DuckDuckGo extends Tool {
name = "duckduckgo_search";
maxResults = 4;
/** @ignore */
async _call(input: string) {
const searchResults = await search(input, {
safeSearch: SafeSearchType.OFF,
});
if (searchResults.noResults) {
return "No good search result found";
}
const results = searchResults.results
.slice(0, this.maxResults)
.map(
({ title, description, url }) =>
`title:${title}\ncontent:${htmlToText(description)}\nurl:${url}`,
)
.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.";
}

View File

@@ -9,12 +9,14 @@ import {
DynamicTool,
RequestsGetTool,
RequestsPostTool,
Tool,
} from "langchain/tools";
import { SerpAPI } from "langchain/tools";
import { Calculator } from "langchain/tools/calculator";
import { AIMessage, HumanMessage, SystemMessage } from "langchain/schema";
import { BufferMemory, ChatMessageHistory } from "langchain/memory";
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { SerpAPI } from "langchain/tools";
import { Calculator } from "langchain/tools/calculator";
import { DuckDuckGo } from "@/app/api/tools/duckduckgo";
const serverConfig = getServerSideConfig();
@@ -120,16 +122,21 @@ async function handle(req: NextRequest) {
},
});
let searchTool: Tool = new DuckDuckGo();
if (process.env.SERPAPI_API_KEY) {
let serpAPITool = new SerpAPI(process.env.SERPAPI_API_KEY);
searchTool = new DynamicTool({
name: "google_search",
description: serpAPITool.description,
func: async (input: string) => serpAPITool.call(input),
});
}
const tools = [
searchTool,
new RequestsGetTool(),
new RequestsPostTool(),
new SerpAPI(process.env.SERPAPI_API_KEY),
new Calculator(),
// new DynamicTool({
// name: ddg.name,
// description: ddg.description,
// func: async (input: string) => ddg.call(input),
// }),
];
const pastMessages = new Array();
@@ -192,4 +199,4 @@ async function handle(req: NextRequest) {
export const GET = handle;
export const POST = handle;
export const runtime = "edge";
export const runtime = "nodejs";

View File

@@ -1,50 +0,0 @@
import { prettyObject } from "@/app/utils/format";
import { NextRequest, NextResponse } from "next/server";
import { auth } from "../../auth";
import { search, SafeSearchType } from "duck-duck-scrape";
async function handle(req: NextRequest) {
if (req.method === "OPTIONS") {
return NextResponse.json({ body: "OK" }, { status: 200 });
}
let query = req.nextUrl.searchParams.get("query") ?? "";
let maxResults = req.nextUrl.searchParams.get(
"max_results",
) as unknown as number;
if (!maxResults) maxResults = 3;
console.log("[Tools Route] query ", query);
const authResult = auth(req);
if (authResult.error) {
return NextResponse.json(authResult, {
status: 401,
});
}
try {
const searchResults = await search(query, {
safeSearch: SafeSearchType.OFF,
});
const result = searchResults.results
.slice(0, maxResults)
.map(({ title, description, url }) => ({
title,
content: description,
url,
}));
const res = new NextResponse(JSON.stringify(result));
res.headers.set("Content-Type", "application/json");
res.headers.set("Cache-Control", "no-cache");
return res;
} catch (e) {
console.error("[Tools] ", e);
return NextResponse.json(prettyObject(e));
}
}
export const GET = handle;
export const POST = handle;
export const runtime = "nodejs";