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:
Harrison Chase 2023-04-20 07:57:07 -07:00 committed by GitHub
parent 34fb56b633
commit b7f2061736
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 249 additions and 0 deletions

View 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
}

View File

@ -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",
] ]

View File

@ -0,0 +1 @@
"""Google Places API Toolkit."""

View 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")

View File

@ -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",

View 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