diff --git a/.changeset/clever-pens-mix.md b/.changeset/clever-pens-mix.md new file mode 100644 index 0000000000000000000000000000000000000000..193d782734b9ccbf0be8e2a6bfb06fcc0ee1cc35 --- /dev/null +++ b/.changeset/clever-pens-mix.md @@ -0,0 +1,5 @@ +--- +"create-llama": patch +--- + +Add DuckDuckGo search tool diff --git a/helpers/tools.ts b/helpers/tools.ts index 67d8f486f36e45f37f69dbb8f34668b3e1283b9d..ffa92640b3e2f800095b934196f6b57c554a0df5 100644 --- a/helpers/tools.ts +++ b/helpers/tools.ts @@ -54,6 +54,29 @@ export const supportedTools: Tool[] = [ }, ], }, + { + // For python app, we will use a local DuckDuckGo search tool (instead of DuckDuckGo search tool in LlamaHub) + // to get the same results as the TS app. + display: "DuckDuckGo Search", + name: "duckduckgo", + dependencies: [ + { + name: "duckduckgo-search", + version: "6.1.7", + }, + ], + supportedFrameworks: ["fastapi", "nextjs", "express"], + type: ToolType.LOCAL, + envVars: [ + { + name: TOOL_SYSTEM_PROMPT_ENV_VAR, + description: "System prompt for DuckDuckGo search tool.", + value: `You are a DuckDuckGo search agent. +You can use the duckduckgo search tool to get information from the web to answer user questions. +For better results, you can specify the region parameter to get results from a specific region but it's optional.`, + }, + ], + }, { display: "Wikipedia", name: "wikipedia.WikipediaToolSpec", diff --git a/templates/components/engines/python/agent/tools/duckduckgo.py b/templates/components/engines/python/agent/tools/duckduckgo.py new file mode 100644 index 0000000000000000000000000000000000000000..43e799b4643587479831c80489901f2beca1fad8 --- /dev/null +++ b/templates/components/engines/python/agent/tools/duckduckgo.py @@ -0,0 +1,36 @@ +from llama_index.core.tools.function_tool import FunctionTool + + +def duckduckgo_search( + query: str, + region: str = "wt-wt", + max_results: int = 10, +): + """ + Use this function to search for any query in DuckDuckGo. + Args: + query (str): The query to search in DuckDuckGo. + region Optional(str): The region to be used for the search in [country-language] convention, ex us-en, uk-en, ru-ru, etc... + max_results Optional(int): The maximum number of results to be returned. Default is 10. + """ + try: + from duckduckgo_search import DDGS + except ImportError: + raise ImportError( + "duckduckgo_search package is required to use this function." + "Please install it by running: `poetry add duckduckgo_search` or `pip install duckduckgo_search`" + ) + + params = { + "keywords": query, + "region": region, + "max_results": max_results, + } + results = [] + with DDGS() as ddg: + results = list(ddg.text(**params)) + return results + + +def get_tools(): + return [FunctionTool.from_defaults(duckduckgo_search)] diff --git a/templates/components/engines/typescript/agent/tools/duckduckgo.ts b/templates/components/engines/typescript/agent/tools/duckduckgo.ts new file mode 100644 index 0000000000000000000000000000000000000000..19423e35314af2e3f237b24b5346b21576ee3bc1 --- /dev/null +++ b/templates/components/engines/typescript/agent/tools/duckduckgo.ts @@ -0,0 +1,61 @@ +import { JSONSchemaType } from "ajv"; +import { search } from "duck-duck-scrape"; +import { BaseTool, ToolMetadata } from "llamaindex"; + +export type DuckDuckGoParameter = { + query: string; + region?: string; +}; + +export type DuckDuckGoToolParams = { + metadata?: ToolMetadata<JSONSchemaType<DuckDuckGoParameter>>; +}; + +const DEFAULT_META_DATA: ToolMetadata<JSONSchemaType<DuckDuckGoParameter>> = { + name: "duckduckgo", + description: "Use this function to search for any query in DuckDuckGo.", + parameters: { + type: "object", + properties: { + query: { + type: "string", + description: "The query to search in DuckDuckGo.", + }, + region: { + type: "string", + description: + "Optional, The region to be used for the search in [country-language] convention, ex us-en, uk-en, ru-ru, etc...", + nullable: true, + }, + }, + required: ["query"], + }, +}; + +type DuckDuckGoSearchResult = { + title: string; + description: string; + url: string; +}; + +export class DuckDuckGoSearchTool implements BaseTool<DuckDuckGoParameter> { + metadata: ToolMetadata<JSONSchemaType<DuckDuckGoParameter>>; + + constructor(params: DuckDuckGoToolParams) { + this.metadata = params.metadata ?? DEFAULT_META_DATA; + } + + async call(input: DuckDuckGoParameter) { + const { query, region } = input; + const options = region ? { region } : {}; + const searchResults = await search(query, options); + + return searchResults.results.map((result) => { + return { + title: result.title, + description: result.description, + url: result.url, + } as DuckDuckGoSearchResult; + }); + } +} diff --git a/templates/components/engines/typescript/agent/tools/index.ts b/templates/components/engines/typescript/agent/tools/index.ts index 7f823eca2bbaa77c1c96904f0aaf2dc2005578f0..0d6345c69900f66a000555148315a032c732fcbc 100644 --- a/templates/components/engines/typescript/agent/tools/index.ts +++ b/templates/components/engines/typescript/agent/tools/index.ts @@ -1,5 +1,6 @@ import { BaseToolWithCall } from "llamaindex"; import { ToolsFactory } from "llamaindex/tools/ToolsFactory"; +import { DuckDuckGoSearchTool, DuckDuckGoToolParams } from "./duckduckgo"; import { InterpreterTool, InterpreterToolParams } from "./interpreter"; import { OpenAPIActionTool } from "./openapi-action"; import { WeatherTool, WeatherToolParams } from "./weather"; @@ -35,6 +36,9 @@ const toolFactory: Record<string, ToolCreator> = { ); return await openAPIActionTool.toToolFunctions(); }, + duckduckgo: async (config: unknown) => { + return [new DuckDuckGoSearchTool(config as DuckDuckGoToolParams)]; + }, }; async function createLocalTools( diff --git a/templates/types/streaming/express/package.json b/templates/types/streaming/express/package.json index 312f708b81a847b49cf72827cc8177d741268d8b..a170e2fd043fd10ab3e2ac5a9a7595796dcd59ba 100644 --- a/templates/types/streaming/express/package.json +++ b/templates/types/streaming/express/package.json @@ -13,6 +13,7 @@ "ai": "^3.0.21", "cors": "^2.8.5", "dotenv": "^16.3.1", + "duck-duck-scrape": "^2.2.5", "express": "^4.18.2", "llamaindex": "0.3.16", "pdf2json": "3.0.5", diff --git a/templates/types/streaming/nextjs/package.json b/templates/types/streaming/nextjs/package.json index 69515e6a7274178cbbf6c6f42466ccc55de4e0d7..61a9ec58b48808d676d190dbedc1bba014f0b08f 100644 --- a/templates/types/streaming/nextjs/package.json +++ b/templates/types/streaming/nextjs/package.json @@ -18,6 +18,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "dotenv": "^16.3.1", + "duck-duck-scrape": "^2.2.5", "llamaindex": "0.3.16", "lucide-react": "^0.294.0", "next": "^14.0.3",