Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add brave search util #5538

Merged
merged 5 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions docs/modules/agents/tools/examples/brave_search.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "eda326e4",
"metadata": {},
"source": [
"# Brave Search\n",
"\n",
"This notebook goes over how to use the Brave Search tool."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "a4c896e5",
"metadata": {},
"outputs": [],
"source": [
"from langchain.tools import BraveSearch"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6784d37c",
"metadata": {},
"outputs": [],
"source": [
"api_key = \"...\""
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5b14008a",
"metadata": {},
"outputs": [],
"source": [
"tool = BraveSearch.from_api_key(api_key=api_key, search_kwargs={\"count\": 3})"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f11937b2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'[{\"title\": \"Barack Obama - Wikipedia\", \"link\": \"https://en.wikipedia.org/wiki/Barack_Obama\", \"snippet\": \"Outside of politics, <strong>Obama</strong> has published three bestselling books: Dreams from My Father (1995), The Audacity of Hope (2006) and A Promised Land (2020). Rankings by scholars and historians, in which he has been featured since 2010, place him in the <strong>middle</strong> to upper tier of American presidents.\"}, {\"title\": \"Obama\\'s Middle Name -- My Last Name -- is \\'Hussein.\\' So?\", \"link\": \"https://www.cair.com/cair_in_the_news/obamas-middle-name-my-last-name-is-hussein-so/\", \"snippet\": \"Many Americans understand that common names don\\\\u2019t only come in the form of a \\\\u201cSmith\\\\u201d or a \\\\u201cJohnson.\\\\u201d Perhaps, they have a neighbor, mechanic or teacher named Hussein. Or maybe they\\\\u2019ve seen fashion designer Hussein Chalayan in the pages of Vogue or recall <strong>King Hussein</strong>, our ally in the Middle East.\"}, {\"title\": \"What\\'s up with Obama\\'s middle name? - Quora\", \"link\": \"https://www.quora.com/Whats-up-with-Obamas-middle-name\", \"snippet\": \"Answer (1 of 15): A better question would be, \\\\u201cWhat\\\\u2019s up with Obama\\\\u2019s first name?\\\\u201d President <strong>Barack Hussein Obama</strong>\\\\u2019s father\\\\u2019s name was <strong>Barack Hussein Obama</strong>. He was named after his father. Hussein, Obama\\\\u2019s middle name, is a very common Arabic name, meaning &quot;good,&quot; &quot;handsome,&quot; or &quot;beautiful.&quot;\"}]'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tool.run(\"obama middle name\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "da9c63d5",
"metadata": {},
"outputs": [],
"source": []
}
],
"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",
"version": "3.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
2 changes: 1 addition & 1 deletion docs/modules/agents/tools/examples/google_search.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
"version": "3.9.1"
},
"vscode": {
"interpreter": {
Expand Down
2 changes: 2 additions & 0 deletions langchain/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
)
from langchain.tools.base import BaseTool, StructuredTool, Tool, tool
from langchain.tools.bing_search.tool import BingSearchResults, BingSearchRun
from langchain.tools.brave_search.tool import BraveSearch
from langchain.tools.ddg_search.tool import DuckDuckGoSearchResults, DuckDuckGoSearchRun
from langchain.tools.file_management.copy import CopyFileTool
from langchain.tools.file_management.delete import DeleteFileTool
Expand Down Expand Up @@ -118,4 +119,5 @@
"ZapierNLARunAction",
"tool",
"YouTubeSearchTool",
"BraveSearch",
]
Empty file.
43 changes: 43 additions & 0 deletions langchain/tools/brave_search/tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from __future__ import annotations

from typing import Any, Optional

from langchain.callbacks.manager import (
AsyncCallbackManagerForToolRun,
CallbackManagerForToolRun,
)
from langchain.tools.base import BaseTool
from langchain.utilities.brave_search import BraveSearchWrapper


class BraveSearch(BaseTool):
name = "brave-search"
description = (
"a search engine. "
"useful for when you need to answer questions about current events."
" input should be a search query."
)
search_wrapper: BraveSearchWrapper

@classmethod
def from_api_key(
cls, api_key: str, search_kwargs: Optional[dict] = None, **kwargs: Any
) -> BraveSearch:
wrapper = BraveSearchWrapper(api_key=api_key, search_kwargs=search_kwargs or {})
return cls(search_wrapper=wrapper, **kwargs)

def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""Use the tool."""
return self.search_wrapper.run(query)

async def _arun(
self,
query: str,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("BraveSearch does not support async")
40 changes: 40 additions & 0 deletions langchain/utilities/brave_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import json

import requests
from pydantic import BaseModel, Field


class BraveSearchWrapper(BaseModel):
api_key: str
search_kwargs: dict = Field(default_factory=dict)

def run(self, query: str) -> str:
headers = {
"X-Subscription-Token": self.api_key,
"Accept": "application/json",
}
base_url = "https://api.search.brave.com/res/v1/web/search"
req = requests.PreparedRequest()
params = {**self.search_kwargs, **{"q": query}}
req.prepare_url(base_url, params)
if req.url is None:
raise ValueError("prepared url is None, this should not happen")

response = requests.get(req.url, headers=headers)

if not response.ok:
raise Exception(f"HTTP error {response.status_code}")

parsed_response = response.json()
web_search_results = parsed_response.get("web", {}).get("results", [])
final_results = []
if isinstance(web_search_results, list):
for item in web_search_results:
final_results.append(
{
"title": item.get("title"),
"link": item.get("url"),
"snippet": item.get("description"),
}
)
return json.dumps(final_results)
1 change: 1 addition & 0 deletions tests/unit_tests/tools/test_public_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"ZapierNLARunAction",
"tool",
"YouTubeSearchTool",
"BraveSearch",
]


Expand Down