| from fastapi import FastAPI |
| from fastapi.responses import FileResponse, HTMLResponse |
| import folium |
| import pandas as pd |
| import joblib |
| import requests |
| import os |
|
|
| app = FastAPI() |
|
|
| |
| |
| |
|
|
| flood_model = joblib.load("best_flood_model.pkl") |
| wildfire_model = joblib.load("wildfire_model_gb.pkl") |
|
|
| cities_df = pd.read_csv("cyprus_cities_full.csv") |
|
|
| FLOOD_MAP = "flood_map.html" |
| WILDFIRE_MAP = "wildfire_map.html" |
|
|
|
|
| |
| |
| |
|
|
| @app.get("/", response_class=HTMLResponse) |
| def home(): |
|
|
| return """ |
| <html> |
| <head> |
| <style> |
| body{ |
| font-family:Arial; |
| background:#eef6ff; |
| text-align:center; |
| padding:50px; |
| } |
| |
| .box{ |
| background:white; |
| max-width:900px; |
| margin:auto; |
| padding:40px; |
| border-radius:20px; |
| box-shadow:0 4px 20px rgba(0,0,0,.1); |
| } |
| |
| button{ |
| padding:18px 30px; |
| font-size:18px; |
| margin:15px; |
| border:none; |
| border-radius:12px; |
| color:white; |
| cursor:pointer; |
| } |
| |
| .flood{ |
| background:#2563eb; |
| } |
| |
| .fire{ |
| background:#dc2626; |
| } |
| </style> |
| </head> |
| |
| <body> |
| <div class="box"> |
| |
| <h1>Cyprus Multi-Hazard Risk Platform</h1> |
| |
| <p> |
| Generate real-time flood and wildfire risk maps |
| using weather data and machine learning. |
| </p> |
| |
| <form action="/generate-flood-map" method="post"> |
| <button class="flood"> |
| Generate Flood Risk Map |
| </button> |
| </form> |
| |
| <form action="/generate-wildfire-map" method="post"> |
| <button class="fire"> |
| Generate Wildfire Risk Map |
| </button> |
| </form> |
| |
| <br><br> |
| |
| <a href="/view-flood-map">View Flood Map</a> |
| <br><br> |
| <a href="/view-wildfire-map">View Wildfire Map</a> |
| |
| </div> |
| </body> |
| </html> |
| """ |
|
|
|
|
| |
| |
| |
|
|
| @app.post("/generate-flood-map") |
| def generate_flood_map(): |
|
|
| m = folium.Map(location=[35.1,33.4], zoom_start=8) |
|
|
| for _, row in cities_df.iterrows(): |
|
|
| city = row["city"] |
| lat = row["lat"] |
| lon = row["lon"] |
|
|
| url = ( |
| "https://api.open-meteo.com/v1/forecast" |
| f"?latitude={lat}" |
| f"&longitude={lon}" |
| "&daily=precipitation_sum" |
| "&forecast_days=7" |
| "&timezone=auto" |
| ) |
|
|
| data = requests.get(url).json() |
|
|
| daily_rain = data["daily"]["precipitation_sum"] |
|
|
| rain_mm = daily_rain[-1] |
| rain_3d = sum(daily_rain[-3:]) |
| rain_7d = sum(daily_rain) |
|
|
| X = pd.DataFrame([{ |
| "rain_mm": rain_mm, |
| "rain_3d": rain_3d, |
| "rain_7d": rain_7d, |
| "rain_intensity": rain_mm*0.6 + rain_3d*0.4, |
| "soil_saturation": rain_7d/(rain_3d+1), |
| "storm_index": rain_mm + rain_3d + rain_7d |
| }]) |
|
|
| prob = flood_model.predict_proba(X)[0][1] |
|
|
| if prob < 0.33: |
| color="green" |
| label="Low" |
| elif prob < 0.66: |
| color="orange" |
| label="Medium" |
| else: |
| color="red" |
| label="High" |
|
|
| folium.CircleMarker( |
| [lat,lon], |
| radius=7, |
| color=color, |
| fill=True, |
| fill_color=color, |
| popup=f"{city}<br>Flood Risk:{prob:.2f}<br>{label}" |
| ).add_to(m) |
|
|
| m.save(FLOOD_MAP) |
|
|
| return {"status":"Flood map generated","view":"/view-flood-map"} |
|
|
|
|
| @app.get("/view-flood-map") |
| def view_flood_map(): |
| if os.path.exists(FLOOD_MAP): |
| return FileResponse(FLOOD_MAP) |
| return {"error":"Generate flood map first"} |
|
|
|
|
| |
| |
| |
|
|
| @app.post("/generate-wildfire-map") |
| def generate_wildfire_map(): |
|
|
| m = folium.Map(location=[35.1,33.4], zoom_start=8) |
|
|
| for _, row in cities_df.iterrows(): |
|
|
| city = row["city"] |
| lat = row["lat"] |
| lon = row["lon"] |
|
|
| url = ( |
| "https://api.open-meteo.com/v1/forecast" |
| f"?latitude={lat}" |
| f"&longitude={lon}" |
| "&daily=temperature_2m_max,wind_speed_10m_max" |
| "&forecast_days=7" |
| "&timezone=auto" |
| ) |
|
|
| data = requests.get(url).json() |
|
|
| temp = data["daily"]["temperature_2m_max"][-1] |
| wind = data["daily"]["wind_speed_10m_max"][-1] |
|
|
| X = pd.DataFrame([{ |
| "temperature": temp, |
| "wind_speed": wind |
| }]) |
|
|
| prob = wildfire_model.predict_proba(X)[0][1] |
|
|
| if prob < 0.33: |
| color="green" |
| label="Low" |
| elif prob < 0.66: |
| color="orange" |
| label="Medium" |
| else: |
| color="red" |
| label="High" |
|
|
| folium.CircleMarker( |
| [lat,lon], |
| radius=7, |
| color=color, |
| fill=True, |
| fill_color=color, |
| popup=f"{city}<br>Wildfire Risk:{prob:.2f}<br>{label}" |
| ).add_to(m) |
|
|
| m.save(WILDFIRE_MAP) |
|
|
| return {"status":"Wildfire map generated","view":"/view-wildfire-map"} |
|
|
|
|
| @app.get("/view-wildfire-map") |
| def view_wildfire_map(): |
| if os.path.exists(WILDFIRE_MAP): |
| return FileResponse(WILDFIRE_MAP) |
|
|
| return {"error":"Generate wildfire map first"} |