forked from Archives/langchain
Harrison/google places (#3207)
Co-authored-by: Cao Hoang <65607230+cnhhoang850@users.noreply.github.com> Co-authored-by: vowelparrot <130414180+vowelparrot@users.noreply.github.com>
This commit is contained in:
parent
34fb56b633
commit
b7f2061736
105
docs/modules/agents/tools/examples/google_places.ipynb
Normal file
105
docs/modules/agents/tools/examples/google_places.ipynb
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "487607cd",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Google Places\n",
|
||||||
|
"\n",
|
||||||
|
"This notebook goes through how to use Google Places API"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 10,
|
||||||
|
"id": "8690845f",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"#!pip install googlemaps"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 12,
|
||||||
|
"id": "fae31ef4",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import os\n",
|
||||||
|
"os.environ[\"GPLACES_API_KEY\"] = \"\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 13,
|
||||||
|
"id": "abb502b3",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from langchain.tools import GooglePlacesTool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 14,
|
||||||
|
"id": "a83a02ac",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"places = GooglePlacesTool()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 16,
|
||||||
|
"id": "2b65a285",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"\"1. Delfina Restaurant\\nAddress: 3621 18th St, San Francisco, CA 94110, USA\\nPhone: (415) 552-4055\\nWebsite: https://www.delfinasf.com/\\n\\n\\n2. Piccolo Forno\\nAddress: 725 Columbus Ave, San Francisco, CA 94133, USA\\nPhone: (415) 757-0087\\nWebsite: https://piccolo-forno-sf.com/\\n\\n\\n3. L'Osteria del Forno\\nAddress: 519 Columbus Ave, San Francisco, CA 94133, USA\\nPhone: (415) 982-1124\\nWebsite: Unknown\\n\\n\\n4. Il Fornaio\\nAddress: 1265 Battery St, San Francisco, CA 94111, USA\\nPhone: (415) 986-0100\\nWebsite: https://www.ilfornaio.com/\\n\\n\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 16,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"places.run(\"al fornos\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "66d3da8a",
|
||||||
|
"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,6 +2,7 @@
|
|||||||
|
|
||||||
from langchain.tools.base import BaseTool
|
from langchain.tools.base import BaseTool
|
||||||
from langchain.tools.ddg_search.tool import DuckDuckGoSearchTool
|
from langchain.tools.ddg_search.tool import DuckDuckGoSearchTool
|
||||||
|
from langchain.tools.google_places.tool import GooglePlacesTool
|
||||||
from langchain.tools.ifttt import IFTTTWebhook
|
from langchain.tools.ifttt import IFTTTWebhook
|
||||||
from langchain.tools.openapi.utils.api_models import APIOperation
|
from langchain.tools.openapi.utils.api_models import APIOperation
|
||||||
from langchain.tools.openapi.utils.openapi_utils import OpenAPISpec
|
from langchain.tools.openapi.utils.openapi_utils import OpenAPISpec
|
||||||
@ -13,5 +14,6 @@ __all__ = [
|
|||||||
"AIPluginTool",
|
"AIPluginTool",
|
||||||
"OpenAPISpec",
|
"OpenAPISpec",
|
||||||
"APIOperation",
|
"APIOperation",
|
||||||
|
"GooglePlacesTool",
|
||||||
"DuckDuckGoSearchTool",
|
"DuckDuckGoSearchTool",
|
||||||
]
|
]
|
||||||
|
1
langchain/tools/google_places/__init__.py
Normal file
1
langchain/tools/google_places/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""Google Places API Toolkit."""
|
27
langchain/tools/google_places/tool.py
Normal file
27
langchain/tools/google_places/tool.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"""Tool for the Google search API."""
|
||||||
|
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
|
from langchain.tools.base import BaseTool
|
||||||
|
from langchain.utilities.google_places_api import GooglePlacesAPIWrapper
|
||||||
|
|
||||||
|
|
||||||
|
class GooglePlacesTool(BaseTool):
|
||||||
|
"""Tool that adds the capability to query the Google places API."""
|
||||||
|
|
||||||
|
name = "Google Places"
|
||||||
|
description = (
|
||||||
|
"A wrapper around Google Places. "
|
||||||
|
"Useful for when you need to validate or "
|
||||||
|
"discover addressed from ambiguous text. "
|
||||||
|
"Input should be a search query."
|
||||||
|
)
|
||||||
|
api_wrapper: GooglePlacesAPIWrapper = Field(default_factory=GooglePlacesAPIWrapper)
|
||||||
|
|
||||||
|
def _run(self, query: str) -> str:
|
||||||
|
"""Use the tool."""
|
||||||
|
return self.api_wrapper.run(query)
|
||||||
|
|
||||||
|
async def _arun(self, query: str) -> str:
|
||||||
|
"""Use the tool asynchronously."""
|
||||||
|
raise NotImplementedError("GooglePlacesRun does not support async")
|
@ -4,6 +4,7 @@ from langchain.utilities.apify import ApifyWrapper
|
|||||||
from langchain.utilities.arxiv import ArxivAPIWrapper
|
from langchain.utilities.arxiv import ArxivAPIWrapper
|
||||||
from langchain.utilities.bash import BashProcess
|
from langchain.utilities.bash import BashProcess
|
||||||
from langchain.utilities.bing_search import BingSearchAPIWrapper
|
from langchain.utilities.bing_search import BingSearchAPIWrapper
|
||||||
|
from langchain.utilities.google_places_api import GooglePlacesAPIWrapper
|
||||||
from langchain.utilities.google_search import GoogleSearchAPIWrapper
|
from langchain.utilities.google_search import GoogleSearchAPIWrapper
|
||||||
from langchain.utilities.google_serper import GoogleSerperAPIWrapper
|
from langchain.utilities.google_serper import GoogleSerperAPIWrapper
|
||||||
from langchain.utilities.openweathermap import OpenWeatherMapAPIWrapper
|
from langchain.utilities.openweathermap import OpenWeatherMapAPIWrapper
|
||||||
@ -20,6 +21,7 @@ __all__ = [
|
|||||||
"TextRequestsWrapper",
|
"TextRequestsWrapper",
|
||||||
"GoogleSearchAPIWrapper",
|
"GoogleSearchAPIWrapper",
|
||||||
"GoogleSerperAPIWrapper",
|
"GoogleSerperAPIWrapper",
|
||||||
|
"GooglePlacesAPIWrapper",
|
||||||
"WolframAlphaAPIWrapper",
|
"WolframAlphaAPIWrapper",
|
||||||
"SerpAPIWrapper",
|
"SerpAPIWrapper",
|
||||||
"SearxSearchWrapper",
|
"SearxSearchWrapper",
|
||||||
|
112
langchain/utilities/google_places_api.py
Normal file
112
langchain/utilities/google_places_api.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
"""Chain that calls Google Places API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Extra, root_validator
|
||||||
|
|
||||||
|
from langchain.utils import get_from_dict_or_env
|
||||||
|
|
||||||
|
|
||||||
|
class GooglePlacesAPIWrapper(BaseModel):
|
||||||
|
"""Wrapper around Google Places API.
|
||||||
|
|
||||||
|
To use, you should have the ``googlemaps`` python package installed,
|
||||||
|
**an API key for the google maps platform**,
|
||||||
|
and the enviroment variable ''GPLACES_API_KEY''
|
||||||
|
set with your API key , or pass 'gplaces_api_key'
|
||||||
|
as a named parameter to the constructor.
|
||||||
|
|
||||||
|
By default, this will return the all the results on the input query.
|
||||||
|
You can use the top_k_results argument to limit the number of results.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
||||||
|
from langchain import GooglePlacesAPIWrapper
|
||||||
|
gplaceapi = GooglePlacesAPIWrapper()
|
||||||
|
"""
|
||||||
|
|
||||||
|
gplaces_api_key: Optional[str] = None
|
||||||
|
google_map_client: Any #: :meta private:
|
||||||
|
top_k_results: Optional[int] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
"""Configuration for this pydantic object."""
|
||||||
|
|
||||||
|
extra = Extra.forbid
|
||||||
|
arbitrary_types_allowed = True
|
||||||
|
|
||||||
|
@root_validator()
|
||||||
|
def validate_environment(cls, values: Dict) -> Dict:
|
||||||
|
"""Validate that api key is in your environment variable."""
|
||||||
|
gplaces_api_key = get_from_dict_or_env(
|
||||||
|
values, "gplaces_api_key", "GPLACES_API_KEY"
|
||||||
|
)
|
||||||
|
values["gplaces_api_key"] = gplaces_api_key
|
||||||
|
try:
|
||||||
|
import googlemaps
|
||||||
|
|
||||||
|
values["google_map_client"] = googlemaps.Client(gplaces_api_key)
|
||||||
|
except ImportError:
|
||||||
|
raise ValueError(
|
||||||
|
"Could not import googlemaps python packge. "
|
||||||
|
"Please install it with `pip install googlemaps`."
|
||||||
|
)
|
||||||
|
return values
|
||||||
|
|
||||||
|
def run(self, query: str) -> str:
|
||||||
|
"""Run Places search and get k number of places that exists that match."""
|
||||||
|
search_results = self.google_map_client.places(query)["results"]
|
||||||
|
num_to_return = len(search_results)
|
||||||
|
|
||||||
|
places = []
|
||||||
|
|
||||||
|
if num_to_return == 0:
|
||||||
|
return "Google Places did not find any places that match the description"
|
||||||
|
|
||||||
|
num_to_return = (
|
||||||
|
num_to_return
|
||||||
|
if self.top_k_results is None
|
||||||
|
else min(num_to_return, self.top_k_results)
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in range(num_to_return):
|
||||||
|
result = search_results[i]
|
||||||
|
details = self.fetch_place_details(result["place_id"])
|
||||||
|
|
||||||
|
if details is not None:
|
||||||
|
places.append(details)
|
||||||
|
|
||||||
|
return "\n".join([f"{i+1}. {item}" for i, item in enumerate(places)])
|
||||||
|
|
||||||
|
def fetch_place_details(self, place_id: str) -> Optional[str]:
|
||||||
|
try:
|
||||||
|
place_details = self.google_map_client.place(place_id)
|
||||||
|
formatted_details = self.format_place_details(place_details)
|
||||||
|
return formatted_details
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"An Error occurred while fetching place details: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def format_place_details(self, place_details: Dict[str, Any]) -> Optional[str]:
|
||||||
|
try:
|
||||||
|
name = place_details.get("result", {}).get("name", "Unkown")
|
||||||
|
address = place_details.get("result", {}).get(
|
||||||
|
"formatted_address", "Unknown"
|
||||||
|
)
|
||||||
|
phone_number = place_details.get("result", {}).get(
|
||||||
|
"formatted_phone_number", "Unknown"
|
||||||
|
)
|
||||||
|
website = place_details.get("result", {}).get("website", "Unknown")
|
||||||
|
|
||||||
|
formatted_details = (
|
||||||
|
f"{name}\nAddress: {address}\n"
|
||||||
|
f"Phone: {phone_number}\nWebsite: {website}\n\n"
|
||||||
|
)
|
||||||
|
return formatted_details
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"An error occurred while formatting place details: {e}")
|
||||||
|
return None
|
Loading…
Reference in New Issue
Block a user