from smolagents import Tool from typing import Any, Optional class SimpleTool(Tool): name = "calculate_journey_metrics" description = "Calculates journey metrics including distance and time." inputs = {"start_location":{"type":"string","description":"The starting point of the journey."},"destination_location":{"type":"string","description":"The endpoint of the journey."},"transportation_mode":{"type":"string","nullable":True,"description":"Mode of transport ('driving', 'walking', 'bicycling', 'transit', or 'plane'). Defaults to 'driving'."}} output_type = "string" def forward(self, start_location: str, destination_location: str, transportation_mode: Optional[str] = None) -> str: """Calculates journey metrics including distance and time. Args: start_location: The starting point of the journey. destination_location: The endpoint of the journey. transportation_mode: Mode of transport ('driving', 'walking', 'bicycling', 'transit', or 'plane'). Defaults to 'driving'. Returns: str: Journey distance and estimated time. """ from geopy.geocoders import Nominatim from geopy.distance import geodesic import time try: # Initialize geocoder with increased timeout geolocator = Nominatim(user_agent="journey_metrics_calculator", timeout=10) # Add delay between requests to avoid rate limiting time.sleep(1) start = geolocator.geocode(start_location) time.sleep(1) end = geolocator.geocode(destination_location) if not start or not end: return "Could not find one or both locations. Please check spelling and try again." # Calculate distance distance_km = geodesic( (start.latitude, start.longitude), (end.latitude, end.longitude) ).kilometers # Define speeds (km/h) with more realistic values speeds = { 'driving': {'urban': 50, 'highway': 100, 'average': 80}, 'walking': {'average': 5}, 'bicycling': {'casual': 15, 'average': 20}, 'transit': {'urban': 30, 'intercity': 60}, 'plane': { 'short_haul': 500, # <500km 'medium_haul': 700, # 500-3000km 'long_haul': 850 # >3000km } } # Calculate time based on mode and distance if transportation_mode == 'plane': # Select appropriate plane speed based on distance if distance_km < 500: speed = speeds['plane']['short_haul'] elif distance_km < 3000: speed = speeds['plane']['medium_haul'] else: speed = speeds['plane']['long_haul'] # Calculate flight time flight_hours = distance_km / speed # Add airport procedures time (2 hours total) total_hours = flight_hours + 2 # Format the response for plane travel flight_minutes = int(flight_hours * 60) total_hrs = int(total_hours) total_mins = int((total_hours - total_hrs) * 60) return ( f"Journey metrics:\n" f"Distance: {distance_km:.1f} kilometers\n" f"Flight time: {flight_minutes} minutes\n" f"Total estimated time (including airport procedures): " f"{total_hrs} hours and {total_mins} minutes" ) else: # Get speed for other modes mode = transportation_mode or 'driving' if mode not in speeds: return f"Unsupported transportation mode: {mode}" speed = speeds[mode]['average'] hours = distance_km / speed # Format time string hrs = int(hours) mins = int((hours - hrs) * 60) return ( f"Journey metrics:\n" f"Distance: {distance_km:.1f} kilometers\n" f"Estimated time by {mode}: {hrs} hours and {mins} minutes" ) except Exception as e: return f"Error calculating journey metrics: Please try again with more specific location names. Error: {str(e)}"