geocalc-mcp / tools.py
renzoide's picture
Add route planner interface and integrate OpenRouteService for route details
135d1c5
raw
history blame
4 kB
from geopy.geocoders import Nominatim
from geopy import distance
import openrouteservice
from openrouteservice.exceptions import ApiError
import os
from dotenv import load_dotenv
load_dotenv()
def get_coords_from_address(address: str) -> str:
"""
Converts a street address into latitude and longitude coordinates.
Args:
address (str): The address to search for (e.g., "Eiffel Tower, Paris").
Returns:
str: A formatted string with the coordinates "Lat: XX.XXXX, Lon: YY.YYYY"
or an error message if the address is not found.
"""
try:
geolocator = Nominatim(user_agent="geocalc_mcp_app_hackathon")
location = geolocator.geocode(address)
if location:
# If a location is found, format the latitude and longitude into a string.
lat = round(location.latitude, 4)
lon = round(location.longitude, 4)
return f"Lat: {lat}, Lon: {lon}"
else:
return "Address not found. Please try being more specific. E.g., '1600 Amphitheatre Parkway, Mountain View, CA'"
except Exception as e:
print(f"An error occurred: {e}")
return "An error occurred while trying to contact the geocoding service."
def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float, unit: str = "km") -> str:
"""
Calculates the distance between two points on the Earth's surface using the Haversine formula.
Args:
lat1 (float): Latitude of the first point.
lon1 (float): Longitude of the first point.
lat2 (float): Latitude of the second point.
lon2 (float): Longitude of the second point.
unit (str, optional): Unit of measurement for the distance. Default is "km".
Returns:
float: The distance between the two points in kilometers.
"""
print("calculate_distance", lat1, lon1, lat2, lon2, unit)
if unit == "km":
return distance.distance((lat1, lon1), (lat2, lon2)).km
else:
return distance.distance((lat1, lon1), (lat2, lon2)).miles
# This is now a standard, synchronous function
def get_route_details(start_lat: float, start_lon: float, end_lat: float, end_lon: float, mode: str) -> str:
"""
Calculates route distance and duration using the OpenRouteService API.
Args:
start_lat (float): Latitude of the starting point.
start_lon (float): Longitude of the starting point.
end_lat (float): Latitude of the ending point.
end_lon (float): Longitude of the ending point.
mode (str): The mode of transportation (e.g., "car", "walk", "bike").
Returns:
str: A string containing the route distance and duration.
"""
profile_map = {
"car": "driving-car",
"walk": "foot-walking",
"bike": "cycling-road"
}
if mode not in profile_map:
return "Invalid mode. Please use 'car', 'walk', or 'bike'."
ORS_API_KEY = os.getenv("ORS_API_KEY")
client_ors = openrouteservice.Client(key=ORS_API_KEY)
coords = ((start_lon, start_lat), (end_lon, end_lat))
try:
# Call the directions API
routes = client_ors.directions(
coordinates=coords,
profile=profile_map[mode],
)
# Extract summary data from the response
summary = routes['routes'][0]['summary']
print("get_route_details summary:", summary)
distance_km = round(summary['distance'] / 1000, 1) # Distance in meters
duration_sec = summary['duration'] # Duration in seconds
# Format the duration into hours and minutes
hours = int(duration_sec // 3600)
minutes = int((duration_sec % 3600) // 60)
return f"The route by {mode} is {distance_km} km and will take approximately {hours} hours and {minutes} minutes."
except ApiError as e:
return f"Could not find a route. API Error: {e}"
except Exception as e:
return f"An unexpected error occurred: {e}"