Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI | |
| from fastapi.responses import FileResponse, HTMLResponse | |
| from fastapi.staticfiles import StaticFiles | |
| import folium | |
| import pandas as pd | |
| import joblib | |
| import os | |
| import requests | |
| app = FastAPI() | |
| # =============================== | |
| # Serve static files | |
| # =============================== | |
| app.mount("/static", StaticFiles(directory="."), name="static") | |
| # =============================== | |
| # Load ML Model | |
| # =============================== | |
| model = None | |
| model_paths = [ | |
| "wildfire_model_cyprus.pkl", | |
| "models/wildfire_model_cyprus.pkl", | |
| ] | |
| for path in model_paths: | |
| if os.path.exists(path): | |
| model = joblib.load(path) | |
| print(f"✅ Model loaded from: {path}") | |
| break | |
| MAP_FILE = "cyprus_wildfire_risk_map.html" | |
| # =============================== | |
| # Cyprus Cities | |
| # =============================== | |
| cities = { | |
| "Nicosia": (35.1856, 33.3823), | |
| "Limassol": (34.7071, 33.0226), | |
| "Larnaca": (34.9182, 33.6233), | |
| "Paphos": (34.7754, 32.4218), | |
| "Famagusta": (35.1167, 33.9500), | |
| "Kyrenia": (35.3417, 33.3167), | |
| "Morphou": (35.1989, 32.9931), | |
| "Lapta": (35.3389, 33.1611), | |
| "Alsancak": (35.3444, 33.1936), | |
| "Dikmen": (35.2681, 33.3408), | |
| "Değirmenlik": (35.2897, 33.4356), | |
| "Geçitkale": (35.2606, 33.7922), | |
| "Iskele": (35.2722, 33.9458), | |
| "Geroskipou": (34.7567, 32.4547), | |
| "Chloraka": (34.8075, 32.4064), | |
| "Ypsonas": (34.6889, 32.9556), | |
| "Kato Polemidia": (34.6967, 33.0111), | |
| "Aradippou": (34.9517, 33.5928), | |
| "Athienou": (35.0608, 33.5419), | |
| "Polis": (35.0367, 32.4250), | |
| "Peyia": (34.8833, 32.3833), | |
| "Kathikas": (34.9175, 32.4686), | |
| "Ayia Napa": (34.9889, 34.0018), | |
| "Paralimni": (35.0394, 33.9819), | |
| "Deryneia": (35.0648, 33.9566), | |
| "Kakopetria": (34.9894, 32.9033), | |
| "Platres": (34.8633, 32.8575), | |
| } | |
| # =============================== | |
| # Home Page | |
| # =============================== | |
| def home(): | |
| return """ | |
| <html> | |
| <head> | |
| <title>Cyprus Wildfire Risk</title> | |
| </head> | |
| <body style="font-family: Arial; text-align:center;"> | |
| <h1>🔥 Cyprus Wildfire Risk Map</h1> | |
| <form action="/generate-map" method="post"> | |
| <button style="padding:15px;font-size:18px;"> | |
| Generate Wildfire Map | |
| </button> | |
| </form> | |
| <br><br> | |
| <a href="/view-map">View Map</a> | |
| </body> | |
| </html> | |
| """ | |
| # =============================== | |
| # Generate Map | |
| # =============================== | |
| def generate_map(): | |
| if model is None: | |
| return {"error": "Model not loaded"} | |
| m = folium.Map(location=[35.1, 33.4], zoom_start=8) | |
| for city, (lat, lon) in cities.items(): | |
| # =============================== | |
| # REAL WEATHER API CALL | |
| # =============================== | |
| url = ( | |
| "https://api.open-meteo.com/v1/forecast" | |
| f"?latitude={lat}" | |
| f"&longitude={lon}" | |
| "&hourly=temperature_2m,relative_humidity_2m,wind_speed_100m,precipitation" | |
| "&forecast_days=7" | |
| "&timezone=auto" | |
| ) | |
| try: | |
| response = requests.get(url, timeout=8) | |
| data = response.json() | |
| hourly = data["hourly"] | |
| # 3-day averages | |
| temp = sum(hourly["temperature_2m"][:72]) / 72 | |
| humidity = sum(hourly["relative_humidity_2m"][:72]) / 72 | |
| wind = sum(hourly["wind_speed_100m"][:72]) / 72 | |
| # 7-day rainfall | |
| rainfall = sum(hourly["precipitation"][:168]) | |
| except Exception as e: | |
| print("Weather API failed:", e) | |
| temp = 30 | |
| humidity = 50 | |
| wind = 12 | |
| rainfall = 5 | |
| # =============================== | |
| # Prepare ML Input | |
| # =============================== | |
| X = pd.DataFrame({ | |
| "temp_c": [temp], | |
| "humidity": [humidity], | |
| "wind_speed": [wind], | |
| "precipitation": [0], | |
| "temp_3d_avg": [temp], | |
| "humidity_3d_avg": [humidity], | |
| "precipitation_7d": [rainfall], | |
| "wind_3d_avg": [wind] | |
| }) | |
| prediction = model.predict(X)[0] | |
| # =============================== | |
| # Risk Classification | |
| # =============================== | |
| if prediction == 1 or (temp > 32 and humidity < 35): | |
| color = "red" | |
| risk = "High Risk" | |
| elif temp > 28 and humidity < 45 and rainfall < 10: | |
| color = "orange" | |
| risk = "Medium Risk" | |
| else: | |
| color = "green" | |
| risk = "Low Risk" | |
| # =============================== | |
| # Add marker to map | |
| # =============================== | |
| folium.CircleMarker( | |
| location=[lat, lon], | |
| radius=7, | |
| color=color, | |
| fill=True, | |
| fill_color=color, | |
| fill_opacity=0.8, | |
| popup=f""" | |
| <b>{city}</b><br> | |
| Temperature: {temp:.1f} °C<br> | |
| Humidity: {humidity:.1f}%<br> | |
| Wind Speed: {wind:.1f} km/h<br> | |
| Rainfall (7d): {rainfall:.1f} mm<br> | |
| <b>{risk}</b> | |
| """ | |
| ).add_to(m) | |
| m.save(MAP_FILE) | |
| return {"status": "map generated", "view": "/view-map"} | |
| # =============================== | |
| # View Map | |
| # =============================== | |
| def view_map(): | |
| if os.path.exists(MAP_FILE): | |
| return FileResponse(MAP_FILE) | |
| return {"error": "Generate map first"} | |