Skip to content

Commit

Permalink
feat: Add DuckDuckGo Search tool (#11386)
Browse files Browse the repository at this point in the history
  • Loading branch information
leehuwuj authored Feb 27, 2024
1 parent 2e63d5e commit b2f0a59
Show file tree
Hide file tree
Showing 14 changed files with 442 additions and 0 deletions.
153 changes: 153 additions & 0 deletions llama-index-tools-duckduckgo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
llama_index/_static
.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
bin/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
etc/
include/
lib/
lib64/
parts/
sdist/
share/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
.ruff_cache

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints
notebooks/

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
pyvenv.cfg

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# Jetbrains
.idea
modules/
*.swp

# VsCode
.vscode

# pipenv
Pipfile
Pipfile.lock

# pyright
pyrightconfig.json
7 changes: 7 additions & 0 deletions llama-index-tools-duckduckgo/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
poetry_requirements(
name="poetry",
)

python_requirements(
name="reqs",
)
1 change: 1 addition & 0 deletions llama-index-tools-duckduckgo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# CHANGELOG
17 changes: 17 additions & 0 deletions llama-index-tools-duckduckgo/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
GIT_ROOT ?= $(shell git rev-parse --show-toplevel)

help: ## Show all Makefile targets.
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}'

format: ## Run code autoformatters (black).
pre-commit install
git ls-files | xargs pre-commit run black --files

lint: ## Run linters: pre-commit (black, ruff, codespell) and mypy
pre-commit install && git ls-files | xargs pre-commit run --show-diff-on-failure --files

test: ## Run tests via pytest.
pytest tests

watch-docs: ## Build and watch documentation.
sphinx-autobuild docs/ docs/_build/html --open-browser --watch $(GIT_ROOT)/llama_index/
27 changes: 27 additions & 0 deletions llama-index-tools-duckduckgo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# DuckDuckGo Search Tool

This tool enables agents to search and retrieve results from the DuckDuckGo search engine. It utilizes the duckduckgo_search package, which either fetches instant query answers from DuckDuckGo or conducts a full search and parses the results.

## Usage

This tool has a more extensive example usage documented in a Jupyter notebook [here](./examples/duckduckgo_search.ipynb)

Here's an example usage of the DuckDuckGoSearchToolSpec.

```python
from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec
from llama_index.agent import OpenAIAgent

tool_spec = DuckDuckGoSearchToolSpec()

agent = OpenAIAgent.from_tools(DuckDuckGoSearchToolSpec.to_tool_list())

agent.chat("What's going on with the superconductor lk-99")
agent.chat("what are the latest developments in machine learning")
```

## Available tool functions:

- `duckduckgo_instant_search`: Make a query to DuckDuckGo api to receive an instant answer.

- `duckduckgo_full_search`: Make a query to DuckDuckGo search to receive a full search results.
115 changes: 115 additions & 0 deletions llama-index-tools-duckduckgo/examples/duckduckgo_search.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "9a0ed198-6f5e-45dc-8a32-9273640dd563",
"metadata": {},
"outputs": [],
"source": [
"# Setup OpenAI Agent\n",
"import openai\n",
"\n",
"openai.api_key = \"sk-xxx\"\n",
"from llama_index.agent.openai import OpenAIAgent"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "96f222e8",
"metadata": {},
"outputs": [],
"source": [
"from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "447e016d",
"metadata": {},
"outputs": [],
"source": [
"agent = OpenAIAgent.from_tools(\n",
" DuckDuckGoSearchToolSpec().to_tool_list(),\n",
" verbose=True,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "943e749c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: Who is Goethe?\n",
"=== Calling Function ===\n",
"Calling function: duckduckgo_instant_search with args: {\"query\":\"Goethe\"}\n",
"Got output: [{'icon': None, 'text': 'Johann Wolfgang Goethe was a German polymath and writer, who is widely regarded as the greatest and most influential writer in the German language. His work has had a profound and wide-ranging influence on Western literary, political, and philosophical thought from the late 18th century to the present day. Goethe was a German poet, playwright, novelist, scientist, statesman, theatre director, and critic. His works include plays, poetry, literature, and aesthetic criticism, as well as treatises on botany, anatomy, and color. Goethe took up residence in Weimar in November 1775 following the success of his first novel, The Sorrows of Young Werther. He was ennobled by the Duke of Saxe-Weimar, Karl August, in 1782. Goethe was an early participant in the Sturm und Drang literary movement.', 'topic': None, 'url': 'https://en.wikipedia.org/wiki/Johann_Wolfgang_von_Goethe'}, {'icon': 'https://duckduckgo.com/i/edd6fba6.jpg', 'text': 'Johann Wolfgang von Goethe A German poet, playwright, novelist, scientist, statesman, theatre director, and critic.', 'topic': None, 'url': 'https://duckduckgo.com/Johann_Wolfgang_von_Goethe'}, {'icon': 'https://duckduckgo.com/i/c819f955.png', 'text': 'Goethe University Frankfurt A university located in Frankfurt am Main, Germany.', 'topic': None, 'url': 'https://duckduckgo.com/Goethe_University_Frankfurt'}, {'icon': 'https://duckduckgo.com/i/www.goethe.de.ico', 'text': 'Goethe-Institut A non-profit German cultural association operational worldwide with 159 institutes, promoting the...', 'topic': None, 'url': 'https://duckduckgo.com/Goethe-Institut'}, {'icon': None, 'text': \"Goethe (grape) Goethe is one of the collection of grape varieties known as Rogers' Hybrids, created by E.S.\", 'topic': None, 'url': 'https://duckduckgo.com/Goethe_(grape)'}, {'icon': 'https://duckduckgo.com/i/6eff7e53.jpg', 'text': 'Goethe (train) An express train that, for most of its existence, linked Paris-Est in Paris, France, with...', 'topic': None, 'url': 'https://duckduckgo.com/Goethe_(train)'}, {'icon': 'https://duckduckgo.com/i/71aac73b.gif', 'text': '3047 Goethe A bright background asteroid from the central regions of the asteroid belt, approximately in...', 'topic': None, 'url': 'https://duckduckgo.com/3047_Goethe'}, {'icon': 'https://duckduckgo.com/i/c71989d7.jpg', 'text': 'Goethe! A 2010 German historical drama film directed by Philipp Stölzl and starring Alexander Fehling...', 'topic': None, 'url': 'https://duckduckgo.com/Young_Goethe_in_Love'}, {'icon': None, 'text': 'Mount Goethe A summit in Fresno County, California, in the United States.', 'topic': None, 'url': 'https://duckduckgo.com/Mount_Goethe'}, {'icon': None, 'text': 'Goethe Awards An American series of comic book fan awards, first presented in 1971 for comics published in 1970.', 'topic': 'See also', 'url': 'https://duckduckgo.com/Goethe_Awards'}, {'icon': 'https://duckduckgo.com/i/b41b9fb4.jpg', 'text': 'Goethe Prize An award for achievement \"worthy of honour in memory of Johann Wolfgang von Goethe\" made by the...', 'topic': 'See also', 'url': 'https://duckduckgo.com/Goethe_Prize'}, {'icon': None, 'text': 'Goethe Medal A yearly prize given by the Goethe-Institut honoring non-Germans \"who have performed outstanding...', 'topic': 'See also', 'url': 'https://duckduckgo.com/Goethe_Medal'}, {'icon': None, 'text': 'Goethe Basin An impact basin at 81.4° N, 54.3° W on Mercury approximately 317 kilometers in diameter.', 'topic': 'See also', 'url': 'https://duckduckgo.com/Goethe_Basin'}, {'icon': None, 'text': \"Goethe (surname) See related meanings for the phrase 'Goethe (surname)'.\", 'topic': 'See also', 'url': 'https://duckduckgo.com/d/Goethe_(surname)'}, {'icon': None, 'text': \"Gote See related meanings for the word 'Gote'.\", 'topic': 'See also', 'url': 'https://duckduckgo.com/d/Gote'}]\n",
"========================\n",
"\n",
"Johann Wolfgang Goethe was a German polymath and writer, widely regarded as the greatest and most influential writer in the German language. He was a poet, playwright, novelist, scientist, statesman, theatre director, and critic. Goethe's work has had a profound influence on Western literary, political, and philosophical thought. He took up residence in Weimar in 1775 and was ennobled by the Duke of Saxe-Weimar in 1782. For more information, you can visit the [Wikipedia page](https://en.wikipedia.org/wiki/Johann_Wolfgang_von_Goethe).\n"
]
}
],
"source": [
"agent.chat_history.clear()\n",
"print(agent.chat(\"Who is Goethe?\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4d46804f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added user message to memory: Give me a quote of Goethe (Deutsch)?\n",
"=== Calling Function ===\n",
"Calling function: duckduckgo_full_search with args: {\"query\":\"Goethe Zitat\",\"region\":\"de\",\"max_results\":1}\n",
"Got output: [{'title': 'Johann Wolfgang von Goethe Quotations - ThoughtCo', 'href': 'https://www.thoughtco.com/goethe-zitate-german-english-quotations-4069390', 'body': 'Sie rauben euch beides, Zeit und Stimmung.\" English Translation: Of all the thieving riff-raff, fools are the worst. They steal both your time and your good mood. \"Das Leben gehört den Lebenden an, und wer lebt, muss auf Wechsel gefasst sein.\"'}]\n",
"========================\n",
"\n",
"Here is a quote by Johann Wolfgang von Goethe in German:\n",
"\n",
"\"Sie rauben euch beides, Zeit und Stimmung.\"\n",
"English Translation: \"Of all the thieving riff-raff, fools are the worst. They steal both your time and your good mood.\"\n",
"\n",
"If you would like more quotes or information about Goethe, you can visit the [source](https://www.thoughtco.com/goethe-zitate-german-english-quotations-4069390).\n"
]
}
],
"source": [
"print(agent.chat(\"Give me a quote of Goethe (Deutsch)?\"))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python_sources()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from llama_index.tools.duckduckgo.base import DuckDuckGoSearchToolSpec

__all__ = ["DuckDuckGoSearchToolSpec"]
44 changes: 44 additions & 0 deletions llama-index-tools-duckduckgo/llama_index/tools/duckduckgo/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import importlib.util
from typing import List, Dict, Optional
from llama_index.core.tools.tool_spec.base import BaseToolSpec


class DuckDuckGoSearchToolSpec(BaseToolSpec):
"""DuckDuckGoSearch tool spec."""

spec_functions = ["duckduckgo_instant_search", "duckduckgo_full_search"]

def __init__(self) -> None:
if not importlib.util.find_spec("duckduckgo_search"):
raise ImportError(
"DuckDuckGoSearchToolSpec requires the duckduckgo_search package to be installed."
)
super().__init__()

def duckduckgo_instant_search(self, query: str) -> List[Dict]:
"""
Make a query to DuckDuckGo api to receive an instant answer.
Args:
query (str): The query to be passed to DuckDuckGo.
"""
from duckduckgo_search import DDGS

with DDGS() as ddg:
return list(ddg.answers(query))

def duckduckgo_full_search(
self, query: str, region: Optional[str] = None, max_results: Optional[int] = 10
) -> List[Dict]:
"""
Make a query to DuckDuckGo search to receive a full search results.
Args:
query (str): The query to be passed to 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.
"""
from duckduckgo_search import DDGS

with DDGS() as ddg:
return list(ddg.text(query, region=region, max_results=max_results))
Loading

0 comments on commit b2f0a59

Please sign in to comment.