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 # =============================== @app.get("/", response_class=HTMLResponse) def home(): return """ Cyprus Wildfire Risk

🔥 Cyprus Wildfire Risk Map



View Map """ # =============================== # Generate Map # =============================== @app.post("/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""" {city}
Temperature: {temp:.1f} °C
Humidity: {humidity:.1f}%
Wind Speed: {wind:.1f} km/h
Rainfall (7d): {rainfall:.1f} mm
{risk} """ ).add_to(m) m.save(MAP_FILE) return {"status": "map generated", "view": "/view-map"} # =============================== # View Map # =============================== @app.get("/view-map") def view_map(): if os.path.exists(MAP_FILE): return FileResponse(MAP_FILE) return {"error": "Generate map first"}