fleetmind-dispatch-ai / chat /route_optimizer.py
mashrur950's picture
feat: Integrate Google Routes API for real-time routing with fallback logic
5769203
"""
Intelligent Route Optimizer for FleetMind
Combines traffic, weather, and vehicle type for optimal routing decisions
"""
import logging
from typing import Dict, List, Optional
from chat.tools import handle_calculate_route, geocoding_service
from chat.weather import weather_service
logger = logging.getLogger(__name__)
def calculate_intelligent_route(
origin: str,
destination: str,
vehicle_type: str = "car",
consider_weather: bool = True,
consider_traffic: bool = True
) -> Dict:
"""
Calculate optimal route considering traffic, weather, and vehicle type
Args:
origin: Starting location (address or coordinates)
destination: Ending location (address or coordinates)
vehicle_type: Type of vehicle (motorcycle, car, van, truck)
consider_weather: Whether to factor in weather conditions
consider_traffic: Whether to factor in traffic conditions
Returns:
Comprehensive routing result with recommendations and warnings
"""
logger.info(f"Intelligent routing: {origin} β†’ {destination} (vehicle: {vehicle_type})")
# Step 1: Calculate base route with traffic data
route_result = handle_calculate_route({
"origin": origin,
"destination": destination,
"vehicle_type": vehicle_type,
"alternatives": True # Get alternative routes
})
if not route_result.get("success"):
return route_result # Return error
# Step 2: Get weather data for the destination area
weather_data = None
weather_impact = None
if consider_weather:
try:
# Geocode destination to get coordinates
dest_geocoded = geocoding_service.geocode(destination)
dest_lat = dest_geocoded["lat"]
dest_lng = dest_geocoded["lng"]
# Get current weather
weather_data = weather_service.get_current_weather(dest_lat, dest_lng)
# Assess weather impact for this vehicle type
weather_impact = weather_service.assess_weather_impact(weather_data, vehicle_type)
logger.info(f"Weather impact: {weather_impact['severity']} (multiplier: {weather_impact['speed_multiplier']}x)")
except Exception as e:
logger.warning(f"Weather data unavailable: {e}")
consider_weather = False
# Step 3: Calculate adjusted duration
base_duration = route_result["duration"]["seconds"]
traffic_duration = route_result["duration_in_traffic"]["seconds"]
# Start with traffic-aware duration
adjusted_duration = traffic_duration
# Apply weather adjustments if available
if consider_weather and weather_impact:
adjusted_duration = int(adjusted_duration * weather_impact["speed_multiplier"])
# Calculate delay percentages
traffic_delay_percent = 0
weather_delay_percent = 0
if consider_traffic and traffic_duration > base_duration:
traffic_delay_percent = int(((traffic_duration - base_duration) / base_duration) * 100)
if consider_weather and weather_impact and weather_impact["speed_multiplier"] > 1.0:
weather_delay_percent = int(((weather_impact["speed_multiplier"] - 1.0) * 100))
total_delay_percent = int(((adjusted_duration - base_duration) / base_duration) * 100) if base_duration > 0 else 0
# Step 4: Generate traffic status
traffic_status = "unknown"
if consider_traffic:
if traffic_delay_percent == 0:
traffic_status = "clear"
elif traffic_delay_percent < 15:
traffic_status = "light"
elif traffic_delay_percent < 30:
traffic_status = "moderate"
elif traffic_delay_percent < 50:
traffic_status = "heavy"
else:
traffic_status = "severe"
# Step 5: Generate recommendations and warnings
recommendations = []
warnings = []
# Traffic recommendations
if consider_traffic:
if traffic_delay_percent > 30:
recommendations.append(f"🚦 Heavy traffic: {traffic_delay_percent}% delay - consider alternate route or timing")
elif traffic_delay_percent > 15:
recommendations.append(f"🚦 Moderate traffic: {traffic_delay_percent}% delay expected")
# Weather recommendations
if consider_weather and weather_impact:
if weather_impact["warnings"]:
warnings.extend(weather_impact["warnings"])
if weather_impact["recommend_delay"]:
recommendations.append("⚠️ SEVERE WEATHER: Consider delaying trip until conditions improve")
if vehicle_type == "motorcycle" and not weather_impact["safe_for_motorcycle"]:
warnings.append("🏍️ WARNING: Current weather not safe for motorcycle - consider alternative vehicle")
# Vehicle-specific recommendations
if vehicle_type == "motorcycle":
if traffic_delay_percent > 40:
recommendations.append("🏍️ TIP: Motorcycles can navigate heavy traffic more efficiently")
# Format durations
def format_duration(seconds):
hours = seconds // 3600
minutes = (seconds % 3600) // 60
if hours > 0:
return f"{hours}h {minutes}m"
return f"{minutes}m"
# Step 6: Build comprehensive response
response = {
"success": True,
"route": {
"origin": route_result["origin"],
"destination": route_result["destination"],
"distance": route_result["distance"],
"vehicle_type": vehicle_type,
"route_summary": route_result["route_summary"],
"confidence": route_result["confidence"]
},
"timing": {
"base_duration": {
"seconds": base_duration,
"text": format_duration(base_duration)
},
"with_traffic": {
"seconds": traffic_duration,
"text": format_duration(traffic_duration)
},
"adjusted_duration": {
"seconds": adjusted_duration,
"text": format_duration(adjusted_duration)
},
"traffic_delay_percent": traffic_delay_percent,
"weather_delay_percent": weather_delay_percent,
"total_delay_percent": total_delay_percent
},
"conditions": {
"traffic_status": traffic_status,
"traffic_considered": consider_traffic,
"weather_considered": consider_weather
},
"recommendations": recommendations,
"warnings": warnings
}
# Add weather data if available
if weather_data:
response["weather"] = {
"conditions": weather_data["conditions"],
"description": weather_data["description"],
"temperature_c": round(weather_data["temperature_c"], 1),
"precipitation_mm": round(weather_data["precipitation_mm"], 1),
"visibility_m": weather_data["visibility_m"],
"impact_severity": weather_impact["severity"] if weather_impact else "none"
}
# Add alternative routes if available
if route_result.get("alternatives"):
response["alternatives"] = route_result["alternatives"]
response["alternatives_count"] = len(route_result["alternatives"])
logger.info(f"Intelligent route calculated: {format_duration(adjusted_duration)} (base: {format_duration(base_duration)})")
return response