DataSprint / location_config.py
sujana05's picture
Upload folder using huggingface_hub
b4ce589 verified
"""
Location Configuration Module for Fleet Optimization
Flexible location management for any geographic area
"""
import json
import requests
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
import logging
logger = logging.getLogger(__name__)
@dataclass
class LocationConfig:
"""Configuration for a specific location/city"""
name: str
center_lat: float
center_lng: float
bounds: Dict[str, float] # north, south, east, west
hotspots: List[Dict[str, any]] # demand hotspots with metadata
timezone: str
country: str
city: str
class LocationManager:
"""Manages location configurations and geographic data"""
def __init__(self, google_maps_api_key: str):
self.api_key = google_maps_api_key
self.current_location = None
self.predefined_locations = self._load_predefined_locations()
def _load_predefined_locations(self) -> Dict[str, LocationConfig]:
"""Load predefined location configurations"""
return {
'new_york': LocationConfig(
name='New York City',
center_lat=40.7589,
center_lng=-73.9851,
bounds={'north': 40.8, 'south': 40.7, 'east': -73.9, 'west': -74.0},
hotspots=[
{'name': 'Times Square', 'lat': 40.7589, 'lng': -73.9851, 'peak_hours': [18, 19, 20, 21], 'base_rate': 0.4},
{'name': 'Penn Station', 'lat': 40.7505, 'lng': -73.9934, 'peak_hours': [7, 8, 17, 18], 'base_rate': 0.5},
{'name': 'Grand Central', 'lat': 40.7527, 'lng': -73.9772, 'peak_hours': [7, 8, 17, 18], 'base_rate': 0.4},
{'name': 'Empire State', 'lat': 40.7484, 'lng': -73.9857, 'peak_hours': [10, 11, 14, 15], 'base_rate': 0.3},
{'name': 'Rockefeller', 'lat': 40.7587, 'lng': -73.9787, 'peak_hours': [12, 13, 19, 20], 'base_rate': 0.3},
{'name': 'Financial District', 'lat': 40.7282, 'lng': -74.0776, 'peak_hours': [8, 9, 17, 18], 'base_rate': 0.4},
],
timezone='America/New_York',
country='USA',
city='New York'
),
'london': LocationConfig(
name='London',
center_lat=51.5074,
center_lng=-0.1278,
bounds={'north': 51.6, 'south': 51.4, 'east': -0.1, 'west': -0.2},
hotspots=[
{'name': 'Trafalgar Square', 'lat': 51.5081, 'lng': -0.1281, 'peak_hours': [12, 13, 18, 19], 'base_rate': 0.4},
{'name': 'King\'s Cross', 'lat': 51.5308, 'lng': -0.1238, 'peak_hours': [7, 8, 17, 18], 'base_rate': 0.5},
{'name': 'London Bridge', 'lat': 51.5045, 'lng': -0.0865, 'peak_hours': [8, 9, 17, 18], 'base_rate': 0.4},
{'name': 'Covent Garden', 'lat': 51.5118, 'lng': -0.1233, 'peak_hours': [12, 13, 19, 20], 'base_rate': 0.3},
{'name': 'Oxford Circus', 'lat': 51.5154, 'lng': -0.1415, 'peak_hours': [11, 12, 18, 19], 'base_rate': 0.4},
{'name': 'Canary Wharf', 'lat': 51.5054, 'lng': -0.0235, 'peak_hours': [8, 9, 17, 18], 'base_rate': 0.4},
],
timezone='Europe/London',
country='UK',
city='London'
),
'tokyo': LocationConfig(
name='Tokyo',
center_lat=35.6762,
center_lng=139.6503,
bounds={'north': 35.8, 'south': 35.5, 'east': 139.8, 'west': 139.5},
hotspots=[
{'name': 'Shibuya Crossing', 'lat': 35.6598, 'lng': 139.7006, 'peak_hours': [18, 19, 20, 21], 'base_rate': 0.5},
{'name': 'Tokyo Station', 'lat': 35.6812, 'lng': 139.7671, 'peak_hours': [7, 8, 17, 18], 'base_rate': 0.5},
{'name': 'Ginza', 'lat': 35.6719, 'lng': 139.7650, 'peak_hours': [12, 13, 19, 20], 'base_rate': 0.4},
{'name': 'Shinjuku', 'lat': 35.6896, 'lng': 139.6917, 'peak_hours': [18, 19, 20, 21], 'base_rate': 0.4},
{'name': 'Harajuku', 'lat': 35.6702, 'lng': 139.7026, 'peak_hours': [12, 13, 18, 19], 'base_rate': 0.3},
{'name': 'Roppongi', 'lat': 35.6654, 'lng': 139.7296, 'peak_hours': [19, 20, 21, 22], 'base_rate': 0.4},
],
timezone='Asia/Tokyo',
country='Japan',
city='Tokyo'
),
'singapore': LocationConfig(
name='Singapore',
center_lat=1.3521,
center_lng=103.8198,
bounds={'north': 1.4, 'south': 1.3, 'east': 103.9, 'west': 103.7},
hotspots=[
{'name': 'Marina Bay', 'lat': 1.2833, 'lng': 103.8607, 'peak_hours': [12, 13, 18, 19], 'base_rate': 0.4},
{'name': 'Orchard Road', 'lat': 1.3048, 'lng': 103.8318, 'peak_hours': [12, 13, 19, 20], 'base_rate': 0.4},
{'name': 'Chinatown', 'lat': 1.2833, 'lng': 103.8444, 'peak_hours': [11, 12, 18, 19], 'base_rate': 0.3},
{'name': 'Little India', 'lat': 1.3048, 'lng': 103.8522, 'peak_hours': [11, 12, 18, 19], 'base_rate': 0.3},
{'name': 'Clarke Quay', 'lat': 1.2924, 'lng': 103.8444, 'peak_hours': [19, 20, 21, 22], 'base_rate': 0.4},
{'name': 'Sentosa', 'lat': 1.2494, 'lng': 103.8303, 'peak_hours': [10, 11, 15, 16], 'base_rate': 0.3},
],
timezone='Asia/Singapore',
country='Singapore',
city='Singapore'
)
}
def set_location(self, location_identifier: str) -> bool:
"""Set the current location by identifier"""
if location_identifier in self.predefined_locations:
self.current_location = self.predefined_locations[location_identifier]
logger.info(f"Location set to: {self.current_location.name}")
return True
else:
logger.error(f"Location '{location_identifier}' not found in predefined locations")
return False
def create_custom_location(self, name: str, center_lat: float, center_lng: float,
bounds: Dict[str, float], hotspots: List[Dict] = None) -> LocationConfig:
"""Create a custom location configuration"""
if hotspots is None:
# Generate default hotspots around the center
hotspots = self._generate_default_hotspots(center_lat, center_lng)
location = LocationConfig(
name=name,
center_lat=center_lat,
center_lng=center_lng,
bounds=bounds,
hotspots=hotspots,
timezone='UTC', # Default timezone
country='Unknown',
city=name
)
self.current_location = location
logger.info(f"Custom location created: {name}")
return location
def _generate_default_hotspots(self, center_lat: float, center_lng: float,
num_hotspots: int = 6) -> List[Dict]:
"""Generate default hotspots around a center point"""
import random
hotspots = []
for i in range(num_hotspots):
# Generate hotspots within a reasonable radius
lat_offset = random.uniform(-0.01, 0.01)
lng_offset = random.uniform(-0.01, 0.01)
hotspot = {
'name': f'Hotspot {i+1}',
'lat': center_lat + lat_offset,
'lng': center_lng + lng_offset,
'peak_hours': random.sample(range(24), 4), # Random peak hours
'base_rate': random.uniform(0.2, 0.5)
}
hotspots.append(hotspot)
return hotspots
def get_location_info(self) -> Dict:
"""Get current location information"""
if not self.current_location:
return {'error': 'No location set'}
return {
'name': self.current_location.name,
'center': [self.current_location.center_lat, self.current_location.center_lng],
'bounds': self.current_location.bounds,
'hotspots': self.current_location.hotspots,
'timezone': self.current_location.timezone,
'country': self.current_location.country,
'city': self.current_location.city
}
def get_available_locations(self) -> List[str]:
"""Get list of available predefined locations"""
return list(self.predefined_locations.keys())
def reverse_geocode(self, lat: float, lng: float) -> Optional[Dict]:
"""Get location information from coordinates using Google Maps API"""
try:
url = f"https://maps.googleapis.com/maps/api/geocode/json"
params = {
'latlng': f"{lat},{lng}",
'key': self.api_key
}
response = requests.get(url, params=params, timeout=10)
if response.status_code == 200:
data = response.json()
if data['results']:
result = data['results'][0]
return {
'formatted_address': result['formatted_address'],
'components': result['address_components'],
'place_id': result['place_id']
}
return None
except Exception as e:
logger.error(f"Error in reverse geocoding: {e}")
return None
def geocode(self, address: str) -> Optional[Tuple[float, float]]:
"""Get coordinates from address using Google Maps API"""
try:
url = f"https://maps.googleapis.com/maps/api/geocode/json"
params = {
'address': address,
'key': self.api_key
}
response = requests.get(url, params=params, timeout=10)
if response.status_code == 200:
data = response.json()
if data['results']:
location = data['results'][0]['geometry']['location']
return (location['lat'], location['lng'])
return None
except Exception as e:
logger.error(f"Error in geocoding: {e}")
return None
def validate_coordinates(self, lat: float, lng: float) -> bool:
"""Validate if coordinates are within reasonable bounds"""
return -90 <= lat <= 90 and -180 <= lng <= 180
def get_bounds_from_center(self, center_lat: float, center_lng: float,
radius_km: float = 10) -> Dict[str, float]:
"""Calculate bounds from center point and radius"""
# Approximate conversion: 1 degree ≈ 111 km
lat_delta = radius_km / 111
lng_delta = radius_km / (111 * abs(center_lat / 90)) # Adjust for latitude
return {
'north': center_lat + lat_delta,
'south': center_lat - lat_delta,
'east': center_lng + lng_delta,
'west': center_lng - lng_delta
}
def save_custom_location(self, location: LocationConfig, filename: str = None):
"""Save custom location to file"""
if filename is None:
filename = f"custom_location_{location.name.lower().replace(' ', '_')}.json"
location_data = {
'name': location.name,
'center_lat': location.center_lat,
'center_lng': location.center_lng,
'bounds': location.bounds,
'hotspots': location.hotspots,
'timezone': location.timezone,
'country': location.country,
'city': location.city
}
with open(filename, 'w') as f:
json.dump(location_data, f, indent=2)
logger.info(f"Custom location saved to {filename}")
def load_custom_location(self, filename: str) -> Optional[LocationConfig]:
"""Load custom location from file"""
try:
with open(filename, 'r') as f:
location_data = json.load(f)
location = LocationConfig(
name=location_data['name'],
center_lat=location_data['center_lat'],
center_lng=location_data['center_lng'],
bounds=location_data['bounds'],
hotspots=location_data['hotspots'],
timezone=location_data.get('timezone', 'UTC'),
country=location_data.get('country', 'Unknown'),
city=location_data.get('city', location_data['name'])
)
self.current_location = location
logger.info(f"Custom location loaded: {location.name}")
return location
except Exception as e:
logger.error(f"Error loading custom location: {e}")
return None
# Global location manager instance
location_manager = None
def initialize_location_manager(google_maps_api_key: str):
"""Initialize the global location manager"""
global location_manager
location_manager = LocationManager(google_maps_api_key)
return location_manager
def get_location_manager():
"""Get the global location manager instance"""
return location_manager
if __name__ == "__main__":
# Test the location manager
api_key = "AIzaSyBTA3eACtpCPR9DDi8EhOt1cI7Cy08Mkfg"
manager = LocationManager(api_key)
# Test predefined locations
print("Available locations:", manager.get_available_locations())
# Test setting a location
manager.set_location('new_york')
print("Current location:", manager.get_location_info())
# Test custom location
custom_location = manager.create_custom_location(
name="San Francisco",
center_lat=37.7749,
center_lng=-122.4194,
bounds={'north': 37.8, 'south': 37.7, 'east': -122.3, 'west': -122.5}
)
print("Custom location:", custom_location.name)
# Test geocoding
coords = manager.geocode("Times Square, New York")
if coords:
print(f"Times Square coordinates: {coords}")
# Test reverse geocoding
location_info = manager.reverse_geocode(40.7589, -73.9851)
if location_info:
print(f"Location info: {location_info['formatted_address']}")