|
import requests |
|
import folium |
|
|
|
COUNTRIES_AND_CITIES = { |
|
"Afghanistan": ["Kabul", "Kandahar", "Herat", "Mazar-i-Sharif", "Jalalabad"], |
|
"Albania": ["Tirana", "Durrës", "Vlorë", "Shkodër", "Fier"], |
|
"Algeria": ["Algiers", "Oran", "Constantine", "Annaba", "Blida"], |
|
"Argentina": ["Buenos Aires", "Córdoba", "Rosario", "Mendoza", "La Plata"], |
|
"Armenia": ["Yerevan", "Gyumri", "Vanadzor", "Vagharshapat", "Hrazdan"], |
|
"Australia": [ |
|
"Sydney", |
|
"Melbourne", |
|
"Brisbane", |
|
"Perth", |
|
"Adelaide", |
|
"Gold Coast", |
|
"Newcastle", |
|
"Canberra", |
|
"Sunshine Coast", |
|
"Wollongong", |
|
], |
|
"Austria": ["Vienna", "Graz", "Linz", "Salzburg", "Innsbruck"], |
|
"Azerbaijan": ["Baku", "Ganja", "Sumqayit", "Mingachevir", "Lankaran"], |
|
"Bahrain": ["Manama", "Riffa", "Muharraq", "Hamad Town", "A'ali"], |
|
"Bangladesh": ["Dhaka", "Chittagong", "Sylhet", "Rajshahi", "Khulna"], |
|
"Belarus": ["Minsk", "Gomel", "Mogilev", "Vitebsk", "Grodno"], |
|
"Belgium": ["Brussels", "Antwerp", "Ghent", "Charleroi", "Liège"], |
|
"Bolivia": ["La Paz", "Santa Cruz", "Cochabamba", "Sucre", "Oruro"], |
|
"Bosnia and Herzegovina": ["Sarajevo", "Banja Luka", "Tuzla", "Zenica", "Mostar"], |
|
"Brazil": [ |
|
"São Paulo", |
|
"Rio de Janeiro", |
|
"Brasília", |
|
"Salvador", |
|
"Fortaleza", |
|
"Belo Horizonte", |
|
"Manaus", |
|
"Curitiba", |
|
"Recife", |
|
"Goiânia", |
|
], |
|
"Bulgaria": ["Sofia", "Plovdiv", "Varna", "Burgas", "Ruse"], |
|
"Cambodia": ["Phnom Penh", "Siem Reap", "Battambang", "Sihanoukville", "Poipet"], |
|
"Canada": [ |
|
"Toronto", |
|
"Montreal", |
|
"Vancouver", |
|
"Calgary", |
|
"Edmonton", |
|
"Ottawa", |
|
"Winnipeg", |
|
"Quebec City", |
|
"Hamilton", |
|
"Kitchener", |
|
], |
|
"Chile": ["Santiago", "Valparaíso", "Concepción", "La Serena", "Antofagasta"], |
|
"China": [ |
|
"Shanghai", |
|
"Beijing", |
|
"Chongqing", |
|
"Tianjin", |
|
"Guangzhou", |
|
"Shenzhen", |
|
"Wuhan", |
|
"Dongguan", |
|
"Chengdu", |
|
"Nanjing", |
|
], |
|
"Colombia": ["Bogotá", "Medellín", "Cali", "Barranquilla", "Cartagena"], |
|
"Croatia": ["Zagreb", "Split", "Rijeka", "Osijek", "Zadar"], |
|
"Czech Republic": ["Prague", "Brno", "Ostrava", "Plzen", "Liberec"], |
|
"Denmark": ["Copenhagen", "Aarhus", "Odense", "Aalborg", "Esbjerg"], |
|
"Ecuador": ["Quito", "Guayaquil", "Cuenca", "Santo Domingo", "Machala"], |
|
"Egypt": ["Cairo", "Alexandria", "Giza", "Shubra El Kheima", "Port Said"], |
|
"Estonia": ["Tallinn", "Tartu", "Narva", "Pärnu", "Kohtla-Järve"], |
|
"Ethiopia": ["Addis Ababa", "Dire Dawa", "Mekelle", "Adama", "Awassa"], |
|
"Finland": ["Helsinki", "Espoo", "Tampere", "Vantaa", "Oulu"], |
|
"France": [ |
|
"Paris", |
|
"Lyon", |
|
"Marseille", |
|
"Toulouse", |
|
"Nice", |
|
"Nantes", |
|
"Strasbourg", |
|
"Montpellier", |
|
"Bordeaux", |
|
"Lille", |
|
], |
|
"Georgia": ["Tbilisi", "Batumi", "Kutaisi", "Rustavi", "Gori"], |
|
"Germany": [ |
|
"Berlin", |
|
"Hamburg", |
|
"Munich", |
|
"Cologne", |
|
"Frankfurt", |
|
"Stuttgart", |
|
"Düsseldorf", |
|
"Dortmund", |
|
"Essen", |
|
"Leipzig", |
|
], |
|
"Ghana": ["Accra", "Kumasi", "Tamale", "Takoradi", "Cape Coast"], |
|
"Greece": ["Athens", "Thessaloniki", "Patras", "Heraklion", "Larissa"], |
|
"Hungary": ["Budapest", "Debrecen", "Szeged", "Miskolc", "Pécs"], |
|
"Iceland": ["Reykjavik", "Kópavogur", "Hafnarfjörður", "Akureyri", "Reykjanesbær"], |
|
"India": [ |
|
"Mumbai", |
|
"Delhi", |
|
"Bangalore", |
|
"Hyderabad", |
|
"Chennai", |
|
"Kolkata", |
|
"Ahmedabad", |
|
"Pune", |
|
"Surat", |
|
"Jaipur", |
|
], |
|
"Indonesia": [ |
|
"Jakarta", |
|
"Surabaya", |
|
"Bandung", |
|
"Bekasi", |
|
"Medan", |
|
"Tangerang", |
|
"Depok", |
|
"Semarang", |
|
"Palembang", |
|
"Makassar", |
|
], |
|
"Iran": ["Tehran", "Mashhad", "Isfahan", "Karaj", "Shiraz"], |
|
"Iraq": ["Baghdad", "Basra", "Mosul", "Erbil", "Najaf"], |
|
"Ireland": ["Dublin", "Cork", "Limerick", "Galway", "Waterford"], |
|
"Israel": ["Jerusalem", "Tel Aviv", "Haifa", "Rishon LeZion", "Petah Tikva"], |
|
"Italy": [ |
|
"Rome", |
|
"Milan", |
|
"Naples", |
|
"Turin", |
|
"Palermo", |
|
"Genoa", |
|
"Bologna", |
|
"Florence", |
|
"Bari", |
|
"Catania", |
|
], |
|
"Japan": [ |
|
"Tokyo", |
|
"Osaka", |
|
"Yokohama", |
|
"Nagoya", |
|
"Sapporo", |
|
"Fukuoka", |
|
"Kobe", |
|
"Kawasaki", |
|
"Kyoto", |
|
"Saitama", |
|
], |
|
"Jordan": ["Amman", "Zarqa", "Irbid", "Russeifa", "Wadi as-Ser"], |
|
"Kazakhstan": ["Almaty", "Nur-Sultan", "Shymkent", "Aktobe", "Taraz"], |
|
"Kenya": ["Nairobi", "Mombasa", "Kisumu", "Nakuru", "Eldoret"], |
|
"Kuwait": ["Kuwait City", "Al Ahmadi", "Hawalli", "As Salimiyah", "Sabah as Salim"], |
|
"Latvia": ["Riga", "Daugavpils", "Liepāja", "Jelgava", "Jūrmala"], |
|
"Lebanon": ["Beirut", "Tripoli", "Sidon", "Tyre", "Nabatieh"], |
|
"Lithuania": ["Vilnius", "Kaunas", "Klaipėda", "Šiauliai", "Panevėžys"], |
|
"Luxembourg": [ |
|
"Luxembourg City", |
|
"Esch-sur-Alzette", |
|
"Differdange", |
|
"Dudelange", |
|
"Ettelbruck", |
|
], |
|
"Malaysia": ["Kuala Lumpur", "George Town", "Ipoh", "Shah Alam", "Petaling Jaya"], |
|
"Mexico": [ |
|
"Mexico City", |
|
"Guadalajara", |
|
"Monterrey", |
|
"Puebla", |
|
"Tijuana", |
|
"León", |
|
"Juárez", |
|
"Torreón", |
|
"Querétaro", |
|
"Mérida", |
|
], |
|
"Morocco": ["Casablanca", "Rabat", "Fez", "Marrakech", "Agadir"], |
|
"Nepal": ["Kathmandu", "Pokhara", "Lalitpur", "Bharatpur", "Biratnagar"], |
|
"Netherlands": [ |
|
"Amsterdam", |
|
"Rotterdam", |
|
"The Hague", |
|
"Utrecht", |
|
"Eindhoven", |
|
"Tilburg", |
|
"Groningen", |
|
"Almere", |
|
"Breda", |
|
"Nijmegen", |
|
], |
|
"New Zealand": ["Auckland", "Wellington", "Christchurch", "Hamilton", "Tauranga"], |
|
"Nigeria": ["Lagos", "Abuja", "Kano", "Ibadan", "Port Harcourt"], |
|
"Norway": [ |
|
"Oslo", |
|
"Bergen", |
|
"Trondheim", |
|
"Stavanger", |
|
"Drammen", |
|
"Fredrikstad", |
|
"Kristiansand", |
|
"Sandnes", |
|
"Tromsø", |
|
"Sarpsborg", |
|
], |
|
"Pakistan": ["Karachi", "Lahore", "Faisalabad", "Rawalpindi", "Multan"], |
|
"Peru": ["Lima", "Arequipa", "Trujillo", "Chiclayo", "Huancayo"], |
|
"Philippines": ["Manila", "Quezon City", "Davao", "Cebu City", "Zamboanga"], |
|
"Poland": ["Warsaw", "Kraków", "Łódź", "Wrocław", "Poznań"], |
|
"Portugal": ["Lisbon", "Porto", "Vila Nova de Gaia", "Amadora", "Braga"], |
|
"Qatar": ["Doha", "Al Rayyan", "Umm Salal", "Al Wakrah", "Al Khor"], |
|
"Romania": ["Bucharest", "Cluj-Napoca", "Timișoara", "Iași", "Constanța"], |
|
"Russia": [ |
|
"Moscow", |
|
"Saint Petersburg", |
|
"Novosibirsk", |
|
"Yekaterinburg", |
|
"Kazan", |
|
"Nizhny Novgorod", |
|
"Chelyabinsk", |
|
"Samara", |
|
"Omsk", |
|
"Rostov-on-Don", |
|
], |
|
"Saudi Arabia": ["Riyadh", "Jeddah", "Mecca", "Medina", "Dammam"], |
|
"Serbia": ["Belgrade", "Novi Sad", "Niš", "Kragujevac", "Subotica"], |
|
"Singapore": ["Singapore"], |
|
"Slovakia": ["Bratislava", "Košice", "Prešov", "Žilina", "Banská Bystrica"], |
|
"Slovenia": ["Ljubljana", "Maribor", "Celje", "Kranj", "Velenje"], |
|
"South Africa": [ |
|
"Cape Town", |
|
"Johannesburg", |
|
"Durban", |
|
"Pretoria", |
|
"Port Elizabeth", |
|
], |
|
"South Korea": [ |
|
"Seoul", |
|
"Busan", |
|
"Incheon", |
|
"Daegu", |
|
"Daejeon", |
|
"Gwangju", |
|
"Suwon", |
|
"Ulsan", |
|
"Changwon", |
|
"Goyang", |
|
], |
|
"Spain": [ |
|
"Madrid", |
|
"Barcelona", |
|
"Valencia", |
|
"Seville", |
|
"Zaragoza", |
|
"Málaga", |
|
"Murcia", |
|
"Palma", |
|
"Las Palmas", |
|
"Bilbao", |
|
], |
|
"Sri Lanka": [ |
|
"Colombo", |
|
"Dehiwala-Mount Lavinia", |
|
"Moratuwa", |
|
"Sri Jayawardenepura Kotte", |
|
"Negombo", |
|
], |
|
"Sweden": [ |
|
"Stockholm", |
|
"Gothenburg", |
|
"Malmö", |
|
"Uppsala", |
|
"Västerås", |
|
"Örebro", |
|
"Linköping", |
|
"Helsingborg", |
|
"Jönköping", |
|
"Norrköping", |
|
], |
|
"Switzerland": [ |
|
"Zurich", |
|
"Geneva", |
|
"Basel", |
|
"Bern", |
|
"Lausanne", |
|
"Winterthur", |
|
"Lucerne", |
|
"St. Gallen", |
|
"Lugano", |
|
"Biel/Bienne", |
|
], |
|
"Thailand": ["Bangkok", "Chiang Mai", "Pattaya", "Phuket", "Hat Yai"], |
|
"Turkey": [ |
|
"Istanbul", |
|
"Ankara", |
|
"Izmir", |
|
"Bursa", |
|
"Adana", |
|
"Gaziantep", |
|
"Konya", |
|
"Antalya", |
|
"Kayseri", |
|
"Mersin", |
|
], |
|
"Ukraine": ["Kyiv", "Kharkiv", "Odesa", "Dnipro", "Donetsk"], |
|
"United Arab Emirates": ["Dubai", "Abu Dhabi", "Sharjah", "Al Ain", "Ajman"], |
|
"United Kingdom": [ |
|
"London", |
|
"Birmingham", |
|
"Manchester", |
|
"Leeds", |
|
"Liverpool", |
|
"Sheffield", |
|
"Bristol", |
|
"Glasgow", |
|
"Leicester", |
|
"Edinburgh", |
|
], |
|
"United States": [ |
|
"New York", |
|
"Los Angeles", |
|
"Chicago", |
|
"Houston", |
|
"Phoenix", |
|
"Philadelphia", |
|
"San Antonio", |
|
"San Diego", |
|
"Dallas", |
|
"San Jose", |
|
], |
|
"Uruguay": ["Montevideo", "Salto", "Paysandú", "Las Piedras", "Rivera"], |
|
"Venezuela": ["Caracas", "Maracaibo", "Valencia", "Barquisimeto", "Maracay"], |
|
"Vietnam": ["Ho Chi Minh City", "Hanoi", "Da Nang", "Bien Hoa", "Hue"], |
|
} |
|
|
|
US_STATES = [ |
|
"Alabama", |
|
"Alaska", |
|
"Arizona", |
|
"Arkansas", |
|
"California", |
|
"Colorado", |
|
"Connecticut", |
|
"Delaware", |
|
"Florida", |
|
"Georgia", |
|
"Hawaii", |
|
"Idaho", |
|
"Illinois", |
|
"Indiana", |
|
"Iowa", |
|
"Kansas", |
|
"Kentucky", |
|
"Louisiana", |
|
"Maine", |
|
"Maryland", |
|
"Massachusetts", |
|
"Michigan", |
|
"Minnesota", |
|
"Mississippi", |
|
"Missouri", |
|
"Montana", |
|
"Nebraska", |
|
"Nevada", |
|
"New Hampshire", |
|
"New Jersey", |
|
"New Mexico", |
|
"New York", |
|
"North Carolina", |
|
"North Dakota", |
|
"Ohio", |
|
"Oklahoma", |
|
"Oregon", |
|
"Pennsylvania", |
|
"Rhode Island", |
|
"South Carolina", |
|
"South Dakota", |
|
"Tennessee", |
|
"Texas", |
|
"Utah", |
|
"Vermont", |
|
"Virginia", |
|
"Washington", |
|
"West Virginia", |
|
"Wisconsin", |
|
"Wyoming", |
|
"District of Columbia", |
|
] |
|
|
|
|
|
def get_coordinates_from_dropdown(country: str, city: str, state: str = None) -> tuple: |
|
"""Get coordinates using dropdown selections""" |
|
if not country or not city: |
|
return None, "Please select both country and city." |
|
|
|
if country == "United States" and state: |
|
query = f"{city}, {state}, United States" |
|
else: |
|
query = f"{city}, {country}" |
|
|
|
try: |
|
url = "https://nominatim.openstreetmap.org/search" |
|
params = {"q": query, "format": "json", "limit": 1} |
|
headers = {"User-Agent": "ClimateRiskTool/1.0"} |
|
|
|
response = requests.get(url, params=params, headers=headers, timeout=10) |
|
data = response.json() |
|
|
|
if data: |
|
lat = float(data[0]["lat"]) |
|
lon = float(data[0]["lon"]) |
|
return ( |
|
lat, |
|
lon, |
|
), f"✅ Location found: {data[0].get('display_name', query)}" |
|
else: |
|
return None, f"❌ Location '{city}' not found in {country}." |
|
|
|
except Exception as e: |
|
return None, f"❌ Error looking up location: {str(e)}" |
|
|
|
|
|
def create_risk_map( |
|
lat: float, lon: float, city: str, country: str, risk_analysis: dict = None |
|
) -> str: |
|
import folium |
|
|
|
|
|
m = folium.Map(location=[lat, lon], zoom_start=10, tiles="OpenStreetMap") |
|
|
|
|
|
marker_color = "blue" |
|
popup_html = f"<b>{city}, {country}</b><br>Lat: {lat:.4f}<br>Lon: {lon:.4f}" |
|
|
|
|
|
if risk_analysis and isinstance(risk_analysis, dict): |
|
risks = risk_analysis.get("risk_analysis", {}) |
|
popup_html += "<br><b>Risks for this location:</b><br>" |
|
max_level = 0 |
|
for risk_name, risk_data in risks.items(): |
|
if isinstance(risk_data, dict): |
|
risk_level = risk_data.get("risk_level", 0) |
|
max_level = max(max_level, risk_level) |
|
if risk_level > 80: |
|
emoji = "🔴" |
|
elif risk_level > 60: |
|
emoji = "🟠" |
|
elif risk_level > 40: |
|
emoji = "🟡" |
|
elif risk_level > 20: |
|
emoji = "🟢" |
|
else: |
|
emoji = "⚪" |
|
popup_html += f"{emoji} <b>{risk_name.title()}:</b> {risk_level}/100<br>" |
|
|
|
|
|
if max_level > 80: |
|
marker_color = "red" |
|
elif max_level > 60: |
|
marker_color = "orange" |
|
elif max_level > 40: |
|
marker_color = "lightgreen" |
|
elif max_level > 20: |
|
marker_color = "green" |
|
else: |
|
marker_color = "blue" |
|
|
|
|
|
marker = folium.Marker( |
|
[lat, lon], |
|
popup=popup_html, |
|
tooltip=f"Risks for {city}", |
|
icon=folium.Icon(color=marker_color, icon="info-sign"), |
|
) |
|
marker.add_to(m) |
|
|
|
|
|
script = f""" |
|
<script> |
|
var marker = {marker.get_name()}; |
|
marker.openPopup(); |
|
</script> |
|
""" |
|
m.get_root().html.add_child(folium.Element(script)) |
|
|
|
|
|
legend_html = """ |
|
<div style="position: fixed; |
|
top: 10px; right: 10px; width: 280px; height: auto; |
|
background-color: white; border: 2px solid grey; z-index: 9999; |
|
font-size: 13px; padding: 12px; border-radius: 10px; |
|
box-shadow: 0 4px 8px rgba(0,0,0,0.1);"> |
|
<h4 style="margin: 0 0 10px 0;">🗺️ Legend</h4> |
|
<div><span style="color:red;">🔴</span> High risk<br> |
|
<span style="color:orange;">🟠</span> Moderate risk<br> |
|
<span style="color:yellow;">🟡</span> Mild risk<br> |
|
<span style="color:green;">🟢</span> Low risk</div> |
|
</div> |
|
""" |
|
m.get_root().html.add_child(folium.Element(legend_html)) |
|
|
|
return m._repr_html_() |
|
|
|
def get_city_suggestions(country: str) -> str: |
|
"""Return city suggestions for selected country""" |
|
if country in COUNTRIES_AND_CITIES: |
|
cities = COUNTRIES_AND_CITIES[country] |
|
return f"💡 Popular cities in {country}: {', '.join(cities[:8])}..." |
|
return "" |
|
|