|
|
""" |
|
|
Google Maps Platform API Tool for EvoAgentX |
|
|
|
|
|
This module provides comprehensive Google Maps Platform integration including: |
|
|
- Geocoding API: Convert addresses to coordinates and vice versa |
|
|
- Places API: Search for places and get detailed information |
|
|
- Routes API: Calculate directions and distance matrices |
|
|
- Time Zone API: Get time zone information for locations |
|
|
|
|
|
Compatible with EvoAgentX tool architecture and follows the latest Google Maps Platform APIs. |
|
|
""" |
|
|
|
|
|
import requests |
|
|
import json |
|
|
import os |
|
|
from typing import Dict, Any, List |
|
|
|
|
|
from .tool import Tool, Toolkit |
|
|
from ..core.module import BaseModule |
|
|
from ..core.logging import logger |
|
|
|
|
|
|
|
|
class GoogleMapsBase(BaseModule): |
|
|
""" |
|
|
Base class for Google Maps Platform API interactions. |
|
|
Handles API key management, request formatting, and common utilities. |
|
|
""" |
|
|
|
|
|
def __init__(self, api_key: str = None, timeout: int = 10, **kwargs): |
|
|
""" |
|
|
Initialize the Google Maps base. |
|
|
|
|
|
Args: |
|
|
api_key (str, optional): Google Maps Platform API key. If not provided, will try to get from GOOGLE_MAPS_API_KEY environment variable. |
|
|
timeout (int): Request timeout in seconds |
|
|
**kwargs: Additional keyword arguments for parent class |
|
|
""" |
|
|
super().__init__(**kwargs) |
|
|
|
|
|
|
|
|
self.api_key = api_key or os.getenv("GOOGLE_MAPS_API_KEY") |
|
|
|
|
|
if not self.api_key: |
|
|
logger.warning( |
|
|
"No Google Maps API key provided. Please set GOOGLE_MAPS_API_KEY environment variable " |
|
|
"or pass api_key parameter. Get your API key from: https://console.cloud.google.com/apis/" |
|
|
) |
|
|
|
|
|
self.timeout = timeout |
|
|
self.base_url = "https://maps.googleapis.com/maps/api" |
|
|
|
|
|
def _make_request(self, endpoint: str, params: Dict[str, Any]) -> Dict[str, Any]: |
|
|
""" |
|
|
Make a request to Google Maps Platform API. |
|
|
|
|
|
Args: |
|
|
endpoint (str): API endpoint |
|
|
params (dict): Request parameters |
|
|
|
|
|
Returns: |
|
|
dict: API response |
|
|
""" |
|
|
|
|
|
if not self.api_key: |
|
|
return { |
|
|
"success": False, |
|
|
"error": "Google Maps API key not found. Please set GOOGLE_MAPS_API_KEY environment variable or pass api_key parameter." |
|
|
} |
|
|
|
|
|
try: |
|
|
|
|
|
params['key'] = self.api_key |
|
|
|
|
|
|
|
|
url = f"{self.base_url}/{endpoint}" |
|
|
|
|
|
|
|
|
response = requests.get(url, params=params, timeout=self.timeout) |
|
|
response.raise_for_status() |
|
|
|
|
|
|
|
|
data = response.json() |
|
|
|
|
|
|
|
|
status = data.get('status', 'UNKNOWN_ERROR') |
|
|
if status == 'OK': |
|
|
return { |
|
|
"success": True, |
|
|
"status": status, |
|
|
"data": data |
|
|
} |
|
|
elif status == 'ZERO_RESULTS': |
|
|
return { |
|
|
"success": True, |
|
|
"status": status, |
|
|
"data": data, |
|
|
"message": "No results found" |
|
|
} |
|
|
else: |
|
|
error_message = data.get('error_message', f"API returned status: {status}") |
|
|
logger.error(f"Google Maps API error: {error_message}") |
|
|
return { |
|
|
"success": False, |
|
|
"status": status, |
|
|
"error": error_message |
|
|
} |
|
|
|
|
|
except requests.exceptions.RequestException as e: |
|
|
logger.error(f"Request error: {str(e)}") |
|
|
return { |
|
|
"success": False, |
|
|
"error": f"Request failed: {str(e)}" |
|
|
} |
|
|
except json.JSONDecodeError as e: |
|
|
logger.error(f"JSON decode error: {str(e)}") |
|
|
return { |
|
|
"success": False, |
|
|
"error": f"Invalid JSON response: {str(e)}" |
|
|
} |
|
|
except Exception as e: |
|
|
logger.error(f"Unexpected error: {str(e)}") |
|
|
return { |
|
|
"success": False, |
|
|
"error": f"Unexpected error: {str(e)}" |
|
|
} |
|
|
|
|
|
def _format_coordinates(self, lat: float, lng: float) -> str: |
|
|
"""Format coordinates for API requests.""" |
|
|
return f"{lat},{lng}" |
|
|
|
|
|
|
|
|
class GeocodeAddressTool(Tool): |
|
|
"""Convert addresses to geographic coordinates (latitude/longitude).""" |
|
|
|
|
|
name: str = "geocode_address" |
|
|
description: str = "Convert a street address into geographic coordinates (latitude and longitude). Useful for finding exact locations of places." |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"address": { |
|
|
"type": "string", |
|
|
"description": "The street address to geocode (e.g., '1600 Amphitheatre Parkway, Mountain View, CA')" |
|
|
}, |
|
|
"components": { |
|
|
"type": "string", |
|
|
"description": "Optional component filters (e.g., 'country:US|locality:Mountain View')" |
|
|
}, |
|
|
"region": { |
|
|
"type": "string", |
|
|
"description": "Optional region code for biasing results (e.g., 'us', 'uk')" |
|
|
} |
|
|
} |
|
|
required: List[str] = ["address"] |
|
|
|
|
|
def __init__(self, google_maps_base: GoogleMapsBase): |
|
|
super().__init__() |
|
|
self.google_maps_base = google_maps_base |
|
|
|
|
|
def __call__(self, address: str, components: str = None, region: str = None) -> Dict[str, Any]: |
|
|
""" |
|
|
Geocode an address to coordinates. |
|
|
|
|
|
Args: |
|
|
address: Street address to geocode |
|
|
components: Optional component filters |
|
|
region: Optional region bias |
|
|
|
|
|
Returns: |
|
|
Dictionary with geocoding results |
|
|
""" |
|
|
params = {"address": address} |
|
|
|
|
|
if components: |
|
|
params["components"] = components |
|
|
if region: |
|
|
params["region"] = region |
|
|
|
|
|
result = self.google_maps_base._make_request("geocode/json", params) |
|
|
|
|
|
if result["success"] and result["data"].get("results"): |
|
|
|
|
|
geocode_result = result["data"]["results"][0] |
|
|
location = geocode_result["geometry"]["location"] |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"address": address, |
|
|
"formatted_address": geocode_result.get("formatted_address"), |
|
|
"latitude": location["lat"], |
|
|
"longitude": location["lng"], |
|
|
"place_id": geocode_result.get("place_id"), |
|
|
"location_type": geocode_result["geometry"].get("location_type"), |
|
|
"address_components": geocode_result.get("address_components", []) |
|
|
} |
|
|
else: |
|
|
return { |
|
|
"success": False, |
|
|
"address": address, |
|
|
"error": result.get("error", "No results found") |
|
|
} |
|
|
|
|
|
|
|
|
class ReverseGeocodeTool(Tool): |
|
|
"""Convert geographic coordinates to a human-readable address.""" |
|
|
|
|
|
name: str = "reverse_geocode" |
|
|
description: str = "Convert geographic coordinates (latitude and longitude) into a human-readable address." |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"latitude": { |
|
|
"type": "number", |
|
|
"description": "Latitude coordinate" |
|
|
}, |
|
|
"longitude": { |
|
|
"type": "number", |
|
|
"description": "Longitude coordinate" |
|
|
}, |
|
|
"result_type": { |
|
|
"type": "string", |
|
|
"description": "Optional filter for result types (e.g., 'street_address|route')" |
|
|
} |
|
|
} |
|
|
required: List[str] = ["latitude", "longitude"] |
|
|
|
|
|
def __init__(self, google_maps_base: GoogleMapsBase): |
|
|
super().__init__() |
|
|
self.google_maps_base = google_maps_base |
|
|
|
|
|
def __call__(self, latitude: float, longitude: float, result_type: str = None) -> Dict[str, Any]: |
|
|
""" |
|
|
Reverse geocode coordinates to address. |
|
|
|
|
|
Args: |
|
|
latitude: Latitude coordinate |
|
|
longitude: Longitude coordinate |
|
|
result_type: Optional result type filter |
|
|
|
|
|
Returns: |
|
|
Dictionary with reverse geocoding results |
|
|
""" |
|
|
latlng = self.google_maps_base._format_coordinates(latitude, longitude) |
|
|
params = {"latlng": latlng} |
|
|
|
|
|
if result_type: |
|
|
params["result_type"] = result_type |
|
|
|
|
|
result = self.google_maps_base._make_request("geocode/json", params) |
|
|
|
|
|
if result["success"] and result["data"].get("results"): |
|
|
addresses = [] |
|
|
for geocode_result in result["data"]["results"]: |
|
|
addresses.append({ |
|
|
"formatted_address": geocode_result.get("formatted_address"), |
|
|
"place_id": geocode_result.get("place_id"), |
|
|
"types": geocode_result.get("types", []), |
|
|
"address_components": geocode_result.get("address_components", []) |
|
|
}) |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"latitude": latitude, |
|
|
"longitude": longitude, |
|
|
"addresses": addresses |
|
|
} |
|
|
else: |
|
|
return { |
|
|
"success": False, |
|
|
"latitude": latitude, |
|
|
"longitude": longitude, |
|
|
"error": result.get("error", "No results found") |
|
|
} |
|
|
|
|
|
|
|
|
class PlacesSearchTool(Tool): |
|
|
"""Search for places using text queries or nearby location.""" |
|
|
|
|
|
name: str = "places_search" |
|
|
description: str = "Search for places (restaurants, shops, landmarks) using text queries. Can search near a specific location." |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"query": { |
|
|
"type": "string", |
|
|
"description": "Text search query (e.g., 'pizza restaurants near Times Square')" |
|
|
}, |
|
|
"location": { |
|
|
"type": "string", |
|
|
"description": "Optional location bias as 'latitude,longitude' (e.g., '40.7589,-73.9851')" |
|
|
}, |
|
|
"radius": { |
|
|
"type": "number", |
|
|
"description": "Optional search radius in meters (max 50000)" |
|
|
}, |
|
|
"type": { |
|
|
"type": "string", |
|
|
"description": "Optional place type filter (e.g., 'restaurant', 'gas_station')" |
|
|
} |
|
|
} |
|
|
required: List[str] = ["query"] |
|
|
|
|
|
def __init__(self, google_maps_base: GoogleMapsBase): |
|
|
super().__init__() |
|
|
self.google_maps_base = google_maps_base |
|
|
|
|
|
def __call__(self, query: str, location: str = None, radius: float = None, type: str = None) -> Dict[str, Any]: |
|
|
""" |
|
|
Search for places using text query. |
|
|
|
|
|
Args: |
|
|
query: Text search query |
|
|
location: Optional location bias as 'lat,lng' |
|
|
radius: Optional search radius in meters |
|
|
type: Optional place type filter |
|
|
|
|
|
Returns: |
|
|
Dictionary with search results |
|
|
""" |
|
|
params = {"query": query} |
|
|
|
|
|
if location: |
|
|
params["location"] = location |
|
|
if radius: |
|
|
params["radius"] = min(radius, 50000) |
|
|
if type: |
|
|
params["type"] = type |
|
|
|
|
|
result = self.google_maps_base._make_request("place/textsearch/json", params) |
|
|
|
|
|
if result["success"]: |
|
|
places = [] |
|
|
for place in result["data"].get("results", []): |
|
|
places.append({ |
|
|
"name": place.get("name"), |
|
|
"place_id": place.get("place_id"), |
|
|
"formatted_address": place.get("formatted_address"), |
|
|
"rating": place.get("rating"), |
|
|
"user_ratings_total": place.get("user_ratings_total"), |
|
|
"price_level": place.get("price_level"), |
|
|
"types": place.get("types", []), |
|
|
"geometry": place.get("geometry", {}), |
|
|
"business_status": place.get("business_status") |
|
|
}) |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"query": query, |
|
|
"places_found": len(places), |
|
|
"places": places |
|
|
} |
|
|
else: |
|
|
return { |
|
|
"success": False, |
|
|
"query": query, |
|
|
"error": result.get("error", "Search failed") |
|
|
} |
|
|
|
|
|
|
|
|
class PlaceDetailsTool(Tool): |
|
|
"""Get detailed information about a specific place using its Place ID.""" |
|
|
|
|
|
name: str = "place_details" |
|
|
description: str = "Get comprehensive information about a specific place using its Place ID, including contact info, hours, reviews." |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"place_id": { |
|
|
"type": "string", |
|
|
"description": "Unique Place ID from a place search" |
|
|
}, |
|
|
"fields": { |
|
|
"type": "string", |
|
|
"description": "Optional comma-separated list of fields to return (e.g., 'name,rating,formatted_phone_number')" |
|
|
} |
|
|
} |
|
|
required: List[str] = ["place_id"] |
|
|
|
|
|
def __init__(self, google_maps_base: GoogleMapsBase): |
|
|
super().__init__() |
|
|
self.google_maps_base = google_maps_base |
|
|
|
|
|
def __call__(self, place_id: str, fields: str = None) -> Dict[str, Any]: |
|
|
""" |
|
|
Get detailed place information. |
|
|
|
|
|
Args: |
|
|
place_id: Unique place identifier |
|
|
fields: Optional fields to return |
|
|
|
|
|
Returns: |
|
|
Dictionary with place details |
|
|
""" |
|
|
params = {"place_id": place_id} |
|
|
|
|
|
|
|
|
if not fields: |
|
|
fields = "name,formatted_address,formatted_phone_number,website,rating,user_ratings_total,opening_hours,price_level,types,geometry" |
|
|
|
|
|
params["fields"] = fields |
|
|
|
|
|
result = self.google_maps_base._make_request("place/details/json", params) |
|
|
|
|
|
if result["success"] and result["data"].get("result"): |
|
|
place = result["data"]["result"] |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"place_id": place_id, |
|
|
"name": place.get("name"), |
|
|
"formatted_address": place.get("formatted_address"), |
|
|
"phone_number": place.get("formatted_phone_number"), |
|
|
"international_phone": place.get("international_phone_number"), |
|
|
"website": place.get("website"), |
|
|
"rating": place.get("rating"), |
|
|
"user_ratings_total": place.get("user_ratings_total"), |
|
|
"price_level": place.get("price_level"), |
|
|
"types": place.get("types", []), |
|
|
"opening_hours": place.get("opening_hours"), |
|
|
"geometry": place.get("geometry", {}), |
|
|
"business_status": place.get("business_status"), |
|
|
"reviews": place.get("reviews", []) |
|
|
} |
|
|
else: |
|
|
return { |
|
|
"success": False, |
|
|
"place_id": place_id, |
|
|
"error": result.get("error", "Place not found") |
|
|
} |
|
|
|
|
|
|
|
|
class DirectionsTool(Tool): |
|
|
"""Calculate driving, walking, bicycling, or transit directions between locations.""" |
|
|
|
|
|
name: str = "directions" |
|
|
description: str = "Calculate directions between two or more locations with different travel modes (driving, walking, bicycling, transit)." |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"origin": { |
|
|
"type": "string", |
|
|
"description": "Starting location (address, coordinates, or place ID)" |
|
|
}, |
|
|
"destination": { |
|
|
"type": "string", |
|
|
"description": "Ending location (address, coordinates, or place ID)" |
|
|
}, |
|
|
"mode": { |
|
|
"type": "string", |
|
|
"description": "Travel mode: 'driving', 'walking', 'bicycling', or 'transit' (default: driving)" |
|
|
}, |
|
|
"waypoints": { |
|
|
"type": "string", |
|
|
"description": "Optional waypoints separated by '|' (e.g., 'via:San Francisco|via:Los Angeles')" |
|
|
}, |
|
|
"alternatives": { |
|
|
"type": "boolean", |
|
|
"description": "Whether to return alternative routes (default: false)" |
|
|
} |
|
|
} |
|
|
required: List[str] = ["origin", "destination"] |
|
|
|
|
|
def __init__(self, google_maps_base: GoogleMapsBase): |
|
|
super().__init__() |
|
|
self.google_maps_base = google_maps_base |
|
|
|
|
|
def __call__(self, origin: str, destination: str, mode: str = "driving", |
|
|
waypoints: str = None, alternatives: bool = False) -> Dict[str, Any]: |
|
|
""" |
|
|
Calculate directions between locations. |
|
|
|
|
|
Args: |
|
|
origin: Starting location |
|
|
destination: Ending location |
|
|
mode: Travel mode |
|
|
waypoints: Optional waypoints |
|
|
alternatives: Return alternative routes |
|
|
|
|
|
Returns: |
|
|
Dictionary with directions |
|
|
""" |
|
|
params = { |
|
|
"origin": origin, |
|
|
"destination": destination, |
|
|
"mode": mode, |
|
|
"alternatives": alternatives |
|
|
} |
|
|
|
|
|
if waypoints: |
|
|
params["waypoints"] = waypoints |
|
|
|
|
|
result = self.google_maps_base._make_request("directions/json", params) |
|
|
|
|
|
if result["success"] and result["data"].get("routes"): |
|
|
routes = [] |
|
|
for route in result["data"]["routes"]: |
|
|
|
|
|
legs = [] |
|
|
total_distance = 0 |
|
|
total_duration = 0 |
|
|
|
|
|
for leg in route.get("legs", []): |
|
|
leg_info = { |
|
|
"start_address": leg.get("start_address"), |
|
|
"end_address": leg.get("end_address"), |
|
|
"distance": leg.get("distance", {}), |
|
|
"duration": leg.get("duration", {}), |
|
|
"steps": [] |
|
|
} |
|
|
|
|
|
|
|
|
if leg.get("distance", {}).get("value"): |
|
|
total_distance += leg["distance"]["value"] |
|
|
if leg.get("duration", {}).get("value"): |
|
|
total_duration += leg["duration"]["value"] |
|
|
|
|
|
|
|
|
for step in leg.get("steps", []): |
|
|
leg_info["steps"].append({ |
|
|
"instructions": step.get("html_instructions", ""), |
|
|
"distance": step.get("distance", {}), |
|
|
"duration": step.get("duration", {}), |
|
|
"travel_mode": step.get("travel_mode") |
|
|
}) |
|
|
|
|
|
legs.append(leg_info) |
|
|
|
|
|
routes.append({ |
|
|
"summary": route.get("summary"), |
|
|
"legs": legs, |
|
|
"total_distance_meters": total_distance, |
|
|
"total_duration_seconds": total_duration, |
|
|
"overview_polyline": route.get("overview_polyline", {}), |
|
|
"warnings": route.get("warnings", []), |
|
|
"copyrights": route.get("copyrights") |
|
|
}) |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"origin": origin, |
|
|
"destination": destination, |
|
|
"mode": mode, |
|
|
"routes": routes |
|
|
} |
|
|
else: |
|
|
return { |
|
|
"success": False, |
|
|
"origin": origin, |
|
|
"destination": destination, |
|
|
"error": result.get("error", "No routes found") |
|
|
} |
|
|
|
|
|
|
|
|
class DistanceMatrixTool(Tool): |
|
|
"""Calculate travel times and distances between multiple origins and destinations.""" |
|
|
|
|
|
name: str = "distance_matrix" |
|
|
description: str = "Calculate travel times and distances between multiple origins and destinations. Useful for finding the closest location." |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"origins": { |
|
|
"type": "string", |
|
|
"description": "Origin locations separated by '|' (e.g., 'Seattle,WA|Portland,OR')" |
|
|
}, |
|
|
"destinations": { |
|
|
"type": "string", |
|
|
"description": "Destination locations separated by '|' (e.g., 'San Francisco,CA|Los Angeles,CA')" |
|
|
}, |
|
|
"mode": { |
|
|
"type": "string", |
|
|
"description": "Travel mode: 'driving', 'walking', 'bicycling', or 'transit' (default: driving)" |
|
|
}, |
|
|
"units": { |
|
|
"type": "string", |
|
|
"description": "Unit system: 'metric' or 'imperial' (default: metric)" |
|
|
} |
|
|
} |
|
|
required: List[str] = ["origins", "destinations"] |
|
|
|
|
|
def __init__(self, google_maps_base: GoogleMapsBase): |
|
|
super().__init__() |
|
|
self.google_maps_base = google_maps_base |
|
|
|
|
|
def __call__(self, origins: str, destinations: str, mode: str = "driving", |
|
|
units: str = "metric") -> Dict[str, Any]: |
|
|
""" |
|
|
Calculate distance matrix. |
|
|
|
|
|
Args: |
|
|
origins: Origin locations separated by '|' |
|
|
destinations: Destination locations separated by '|' |
|
|
mode: Travel mode |
|
|
units: Unit system |
|
|
|
|
|
Returns: |
|
|
Dictionary with distance matrix |
|
|
""" |
|
|
params = { |
|
|
"origins": origins, |
|
|
"destinations": destinations, |
|
|
"mode": mode, |
|
|
"units": units |
|
|
} |
|
|
|
|
|
result = self.google_maps_base._make_request("distancematrix/json", params) |
|
|
|
|
|
if result["success"] and result["data"].get("rows"): |
|
|
origin_addresses = result["data"].get("origin_addresses", []) |
|
|
destination_addresses = result["data"].get("destination_addresses", []) |
|
|
|
|
|
matrix = [] |
|
|
for i, row in enumerate(result["data"]["rows"]): |
|
|
origin_results = { |
|
|
"origin_address": origin_addresses[i] if i < len(origin_addresses) else f"Origin {i+1}", |
|
|
"destinations": [] |
|
|
} |
|
|
|
|
|
for j, element in enumerate(row.get("elements", [])): |
|
|
destination_result = { |
|
|
"destination_address": destination_addresses[j] if j < len(destination_addresses) else f"Destination {j+1}", |
|
|
"status": element.get("status"), |
|
|
"distance": element.get("distance", {}), |
|
|
"duration": element.get("duration", {}), |
|
|
"duration_in_traffic": element.get("duration_in_traffic", {}) |
|
|
} |
|
|
origin_results["destinations"].append(destination_result) |
|
|
|
|
|
matrix.append(origin_results) |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"origins": origins.split("|"), |
|
|
"destinations": destinations.split("|"), |
|
|
"mode": mode, |
|
|
"units": units, |
|
|
"matrix": matrix |
|
|
} |
|
|
else: |
|
|
return { |
|
|
"success": False, |
|
|
"origins": origins, |
|
|
"destinations": destinations, |
|
|
"error": result.get("error", "Distance matrix calculation failed") |
|
|
} |
|
|
|
|
|
|
|
|
class TimeZoneTool(Tool): |
|
|
"""Get time zone information for a location.""" |
|
|
|
|
|
name: str = "timezone" |
|
|
description: str = "Get time zone information for a specific location using coordinates." |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"latitude": { |
|
|
"type": "number", |
|
|
"description": "Latitude coordinate" |
|
|
}, |
|
|
"longitude": { |
|
|
"type": "number", |
|
|
"description": "Longitude coordinate" |
|
|
}, |
|
|
"timestamp": { |
|
|
"type": "number", |
|
|
"description": "Optional Unix timestamp for the desired time (default: current time)" |
|
|
} |
|
|
} |
|
|
required: List[str] = ["latitude", "longitude"] |
|
|
|
|
|
def __init__(self, google_maps_base: GoogleMapsBase): |
|
|
super().__init__() |
|
|
self.google_maps_base = google_maps_base |
|
|
|
|
|
def __call__(self, latitude: float, longitude: float, timestamp: float = None) -> Dict[str, Any]: |
|
|
""" |
|
|
Get time zone information. |
|
|
|
|
|
Args: |
|
|
latitude: Latitude coordinate |
|
|
longitude: Longitude coordinate |
|
|
timestamp: Optional Unix timestamp |
|
|
|
|
|
Returns: |
|
|
Dictionary with time zone info |
|
|
""" |
|
|
import time |
|
|
|
|
|
location = self.google_maps_base._format_coordinates(latitude, longitude) |
|
|
params = { |
|
|
"location": location, |
|
|
"timestamp": timestamp or int(time.time()) |
|
|
} |
|
|
|
|
|
result = self.google_maps_base._make_request("timezone/json", params) |
|
|
|
|
|
if result["success"]: |
|
|
data = result["data"] |
|
|
return { |
|
|
"success": True, |
|
|
"latitude": latitude, |
|
|
"longitude": longitude, |
|
|
"time_zone_id": data.get("timeZoneId"), |
|
|
"time_zone_name": data.get("timeZoneName"), |
|
|
"dst_offset": data.get("dstOffset"), |
|
|
"raw_offset": data.get("rawOffset"), |
|
|
"status": data.get("status") |
|
|
} |
|
|
else: |
|
|
return { |
|
|
"success": False, |
|
|
"latitude": latitude, |
|
|
"longitude": longitude, |
|
|
"error": result.get("error", "Time zone lookup failed") |
|
|
} |
|
|
|
|
|
|
|
|
class GoogleMapsToolkit(Toolkit): |
|
|
""" |
|
|
Complete Google Maps Platform toolkit containing all available tools. |
|
|
""" |
|
|
|
|
|
def __init__(self, api_key: str = None, timeout: int = 10, name: str = "GoogleMapsToolkit"): |
|
|
""" |
|
|
Initialize the Google Maps toolkit. |
|
|
|
|
|
Args: |
|
|
api_key (str, optional): Google Maps Platform API key. If not provided, will try to get from GOOGLE_MAPS_API_KEY environment variable. |
|
|
timeout (int): Request timeout in seconds |
|
|
name (str): Toolkit name |
|
|
""" |
|
|
|
|
|
google_maps_base = GoogleMapsBase(api_key=api_key, timeout=timeout) |
|
|
|
|
|
|
|
|
tools = [ |
|
|
GeocodeAddressTool(google_maps_base=google_maps_base), |
|
|
ReverseGeocodeTool(google_maps_base=google_maps_base), |
|
|
PlacesSearchTool(google_maps_base=google_maps_base), |
|
|
PlaceDetailsTool(google_maps_base=google_maps_base), |
|
|
DirectionsTool(google_maps_base=google_maps_base), |
|
|
DistanceMatrixTool(google_maps_base=google_maps_base), |
|
|
TimeZoneTool(google_maps_base=google_maps_base) |
|
|
] |
|
|
|
|
|
|
|
|
super().__init__(name=name, tools=tools) |
|
|
|
|
|
|
|
|
self.google_maps_base = google_maps_base |
|
|
|