Spaces:
Sleeping
Sleeping
| import os | |
| import requests | |
| import pandas as pd | |
| import numpy as np | |
| import joblib | |
| import gradio as gr | |
| from datetime import datetime, timedelta | |
| from tensorflow.keras.models import load_model | |
| from tensorflow.keras.preprocessing import image as keras_image | |
| from tensorflow.keras.applications.vgg16 import preprocess_input as vgg_preprocess | |
| from tensorflow.keras.applications.xception import preprocess_input as xce_preprocess | |
| from tensorflow.keras.losses import BinaryFocalCrossentropy | |
| from PIL import Image | |
| # --- CONFIGURATION --- | |
| FOREST_COORDS = {'Pakistan Forest': (34.0, 73.0)} | |
| API_URL = ( | |
| "https://archive-api.open-meteo.com/v1/archive" | |
| "?latitude={lat}&longitude={lon}" | |
| "&start_date={start}&end_date={end}" | |
| "&daily=temperature_2m_max,temperature_2m_min," | |
| "precipitation_sum,windspeed_10m_max," | |
| "relative_humidity_2m_max,relative_humidity_2m_min" | |
| "&timezone=UTC" | |
| ) | |
| # --- LOAD MODELS --- | |
| def load_models(): | |
| # Fire detector (VGG16) | |
| vgg_model = load_model( | |
| 'vgg16_focal_unfreeze_more.keras', | |
| custom_objects={'BinaryFocalCrossentropy': BinaryFocalCrossentropy} | |
| ) | |
| # Severity classifier (Xception) | |
| def focal_loss_fixed(gamma=2., alpha=.25): | |
| import tensorflow.keras.backend as K | |
| def loss_fn(y_true, y_pred): | |
| eps = K.epsilon(); y_pred = K.clip(y_pred, eps, 1.-eps) | |
| ce = -y_true * K.log(y_pred) | |
| w = alpha * K.pow(1-y_pred, gamma) | |
| return K.mean(w * ce, axis=-1) | |
| return loss_fn | |
| xce_model = load_model( | |
| 'severity_post_tta.keras', | |
| custom_objects={'focal_loss_fixed': focal_loss_fixed()} | |
| ) | |
| # Ensemble and trend models | |
| rf_model = joblib.load('ensemble_rf_model.pkl') | |
| xgb_model = joblib.load('ensemble_xgb_model.pkl') | |
| lr_model = joblib.load('wildfire_logistic_model_synthetic.joblib') | |
| return vgg_model, xce_model, rf_model, xgb_model, lr_model | |
| vgg_model, xception_model, rf_model, xgb_model, lr_model = load_models() | |
| # --- RULES & TEMPLATES --- | |
| target_map = {0: 'mild', 1: 'moderate', 2: 'severe'} | |
| trend_map = {1: 'increase', 0: 'same', -1: 'decrease'} | |
| task_rules = { | |
| 'mild': {'decrease':'mild','same':'mild','increase':'moderate'}, | |
| 'moderate':{'decrease':'mild','same':'moderate','increase':'severe'}, | |
| 'severe': {'decrease':'moderate','same':'severe','increase':'severe'} | |
| } | |
| templates = { | |
| 'mild': ( | |
| "📌 **Immediate Monitoring:** Although fire intensity is low, assign lookouts to monitor hotspots every 30 minutes. Use handheld IR cameras to detect any hidden flare-ups.\n\n" | |
| "📌 **Community Alert:** Send SMS alerts to nearby villages reminding them to stay vigilant. Provide clear instructions on how to report any smoke sightings.\n\n" | |
| "📌 **Fuel Management:** Conduct targeted removal of leaf litter and dry underbrush within a 100 m radius to reduce the chance of flare-ups.\n\n" | |
| "📌 **Preparedness Drills:** Hold a quick drill with ground crews to review communication protocols and ensure equipment (hoses, pumps) is ready.\n\n" | |
| "📌 **Public Education:** Distribute flyers on safe fire-watch practices and set up a hotline for rapid reporting." | |
| ), | |
| 'moderate': ( | |
| "🚒 **Rapid Response:** Dispatch two engine crews and one aerial water-drop helicopter. Coordinate with the regional command center to stage retardant tanks nearby.\n\n" | |
| "🏃♂️ **Evacuation Prep:** Pre-position evacuation buses at community centers. Issue voluntary evacuation notices to residents within 5 km downwind.\n\n" | |
| "🛠 **Containment Lines:** Construct a 10 m fire break using both hand tools and bulldozers. Apply fire-retardant gel along the anticipated flank.\n\n" | |
| "🌱 **Fuel Reduction:** Begin mechanical thinning of small trees and brush in high-risk zones adjacent to critical infrastructure.\n\n" | |
| "📣 **Awareness Campaign:** Launch radio spots explaining what to do if fire approaches, including evacuation routes and shelter locations." | |
| ), | |
| 'severe': ( | |
| "✈️ **Full Suppression:** Mobilize two air tankers for retardant drops and four ground crews with heavy equipment. Integrate real-time satellite imagery for targeting.\n\n" | |
| "🚨 **Mandatory Evacuation:** Issue immediate evacuation orders for all residents within a 10 km radius. Open three emergency shelters with medical staff on standby.\n\n" | |
| "🔥 **Backfire Operations:** Conduct controlled backfires under supervision of senior incident commanders to remove fuel ahead of the main front.\n\n" | |
| "🌳 **Post-Fire Rehabilitation:** Plan reforestation with fire-resistant native species; stabilize soil to prevent erosion in burn scar areas.\n\n" | |
| "🗣 **Crisis Communication:** Hold daily press briefings and social media updates. Provide mental-health support hotlines for displaced families." | |
| ) | |
| } | |
| # --- PIPELINE FUNCTIONS --- | |
| def detect_fire(img): | |
| x = keras_image.img_to_array(img.resize((128,128)))[None] | |
| x = vgg_preprocess(x) | |
| prob = float(vgg_model.predict(x)[0][0]) | |
| return prob >= 0.5, prob | |
| def classify_severity(img): | |
| x = keras_image.img_to_array(img.resize((224,224)))[None] | |
| x = xce_preprocess(x) | |
| preds = xception_model.predict(x) | |
| rf_p = rf_model.predict(preds)[0] | |
| xgb_p = xgb_model.predict(preds)[0] | |
| ensemble = int(round((rf_p + xgb_p)/2)) | |
| return target_map.get(ensemble, 'moderate') | |
| def fetch_weather_trend(lat, lon): | |
| end = datetime.utcnow() | |
| start = end - timedelta(days=1) | |
| url = API_URL.format(lat=lat, lon=lon, | |
| start=start.strftime('%Y-%m-%d'), | |
| end=end.strftime('%Y-%m-%d')) | |
| df = pd.DataFrame(requests.get(url).json().get('daily', {})) | |
| for c in ['precipitation_sum','temperature_2m_max','temperature_2m_min', | |
| 'relative_humidity_2m_max','relative_humidity_2m_min','windspeed_10m_max']: | |
| df[c] = pd.to_numeric(df.get(c,[]), errors='coerce') | |
| df['precipitation'] = df['precipitation_sum'].fillna(0) | |
| df['temperature'] = (df['temperature_2m_max'] + df['temperature_2m_min'])/2 | |
| df['humidity'] = (df['relative_humidity_2m_max'] + df['relative_humidity_2m_min'])/2 | |
| df['wind_speed'] = df['windspeed_10m_max'] | |
| df['fire_risk_score'] = ( | |
| 0.4*(df['temperature']/55) + | |
| 0.2*(1-df['humidity']/100) + | |
| 0.3*(df['wind_speed']/60) + | |
| 0.1*(1-df['precipitation']/50) | |
| ) | |
| feats = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']] | |
| feat = feats.fillna(feats.mean()).iloc[-1].values.reshape(1,-1) | |
| trend_cl = lr_model.predict(feat)[0] | |
| return trend_map.get(trend_cl, 'same') | |
| def generate_recommendations(original_severity, weather_trend): | |
| # determine projected severity | |
| proj = task_rules[original_severity][weather_trend] | |
| rec = templates[proj] | |
| # proper multi-line header | |
| header = f"""**Original:** {original_severity.title()} | |
| **Trend:** {weather_trend.title()} | |
| **Projected:** {proj.title()}\n\n""" | |
| return header + rec | |
| # --- GRADIO INTERFACE --- | |
| def pipeline(image): | |
| img = Image.fromarray(image).convert('RGB') | |
| fire, prob = detect_fire(img) | |
| if not fire: | |
| return f"No wildfire detected (prob={prob:.2f})", "N/A", "N/A", "**No wildfire detected. Stay alert.**" | |
| sev = classify_severity(img) | |
| trend = fetch_weather_trend(*FOREST_COORDS['Pakistan Forest']) | |
| recs = generate_recommendations(sev, trend) | |
| return f"Fire Detected (prob={prob:.2f})", sev.title(), trend, recs | |
| interface = gr.Interface( | |
| fn=pipeline, | |
| inputs=gr.Image(type='numpy', label='Upload Wildfire Image'), | |
| outputs=[ | |
| gr.Textbox(label='Fire Status'), | |
| gr.Textbox(label='Severity Level'), | |
| gr.Textbox(label='Weather Trend'), | |
| gr.Markdown(label='Recommendations') | |
| ], | |
| title='Wildfire Detection & Management Assistant', | |
| description='Upload an image from a forest region in Pakistan to determine wildfire presence, severity, weather-driven trend, projection, and get expert recommendations.' | |
| ) | |
| if __name__ == '__main__': | |
| interface.launch() |