|
|
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: |
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
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: |
|
|
|
|
|
routes = client_ors.directions( |
|
|
coordinates=coords, |
|
|
profile=profile_map[mode], |
|
|
) |
|
|
|
|
|
|
|
|
summary = routes['routes'][0]['summary'] |
|
|
print("get_route_details summary:", summary) |
|
|
distance_km = round(summary['distance'] / 1000, 1) |
|
|
duration_sec = summary['duration'] |
|
|
|
|
|
|
|
|
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}" |
|
|
|