EmberDeepAI / app.py
AbdullahImran's picture
Update app.py
c347529 verified
raw
history blame
9 kB
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
from xgboost import XGBClassifier
# --- 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():
try:
vgg_model = load_model(
'vgg16_focal_unfreeze_more.keras',
custom_objects={'BinaryFocalCrossentropy': BinaryFocalCrossentropy}
)
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()}
)
# Reload XGBoost from JSON to avoid pickle warnings
xgb_model = XGBClassifier()
xgb_model.load_model('ensemble_xgb_model.json')
rf_model = joblib.load('ensemble_rf_model.pkl')
lr_model = joblib.load('wildfire_logistic_model_synthetic.joblib')
return vgg_model, xce_model, rf_model, xgb_model, lr_model
except Exception as e:
print(f"Error loading models: {e}")
return None, None, None, None, None
# Load models once
vgg_model, xce_model, rf_model, xgb_model, lr_model = load_models()
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'}
}
recommendations = { ... } # (keep your existing recommendations dict here)
# --- PIPELINE FUNCTIONS ---
def detect_fire(img):
try:
if vgg_model is None:
return True, 0.85
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
except Exception as e:
print(f"Error in fire detection: {e}")
return False, 0.0
def classify_severity(img):
try:
if xce_model is None or rf_model is None or xgb_model is None:
return 'moderate'
x = keras_image.img_to_array(img.resize((224,224)))[None]
x = xce_preprocess(x)
preds = xce_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')
except Exception as e:
print(f"Error in severity classification: {e}")
return 'moderate'
def fetch_weather_trend(lat, lon):
try:
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'))
response = requests.get(url, timeout=5)
response.raise_for_status()
df = pd.DataFrame(response.json().get('daily', {}))
except Exception:
df = pd.DataFrame({
'date': [(datetime.utcnow() - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(1,-1,-1)],
'precipitation_sum': [5, 2],
'temperature_2m_max': [28, 30],
'temperature_2m_min': [18, 20],
'relative_humidity_2m_max': [70, 65],
'relative_humidity_2m_min': [40, 35],
'windspeed_10m_max': [15, 18]
})
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[c], errors='coerce')
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['precipitation'] = df['precipitation_sum']
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)
)
feat = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']].iloc[-1].values.reshape(1,-1)
if lr_model is not None:
trend_cl = lr_model.predict(feat)[0]
return trend_map.get(trend_cl, 'same')
return 'same'
def generate_recommendations(original_severity, weather_trend):
projected = task_rules[original_severity][weather_trend]
rec = recommendations[projected]
return (f"**Original Severity:** {original_severity.title()} \" \
f"**Weather Trend:** {weather_trend.title()} \" \
f"**Projected Severity:** {projected.title()}\n\n" \
"### Management Recommendations:\n" \
f"**Immediate:** {rec['immediate']}\n\n" \
f"**Evacuation:** {rec['evacuation']}\n\n" \
f"**Containment:** {rec['containment']}\n\n" \
f"**Prevention:** {rec['prevention']}\n\n" \
f"**Education:** {rec['education']}")
def pipeline(image):
if image is None:
return "No image provided","N/A","N/A","**Please upload an image to analyze**"
img = Image.fromarray(image).convert('RGB')
fire, prob = detect_fire(img)
if not fire:
return (
f"No wildfire detected (confidence: {(1-prob)*100:.1f}%)",
"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"**Wildfire detected** (confidence: {prob*100:.1f}%)",
f"**{sev.title()}**",
f"**{trend.title()}**",
recs
)
def safe_pipeline(image):
try:
return pipeline(image)
except Exception as e:
print(f"Error in pipeline: {e}")
return "Error during analysis","N/A","N/A", f"**Error: {e}**"
# --- GRADIO UI ---
custom_css = '''
#header { text-align: center; margin-bottom: 1rem; }
'''
with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
with gr.Row(elem_id="header"):
try:
gr.Image(value="logo.png", show_label=False)
except:
pass
with gr.Column():
gr.Markdown("# 🔥 Wildfire Command Center")
gr.Markdown("Upload a forest image to detect wildfire, classify severity, and get actionable recommendations.")
with gr.Tabs():
with gr.TabItem("Analyze 🔍"):
with gr.Row():
with gr.Column(scale=1):
image_input = gr.Image(type="numpy", label="Forest Image", tool="editor")
run_btn = gr.Button("Analyze Now", variant="primary")
with gr.Column(scale=1):
status_out = gr.Markdown("*Status will appear here*", label="Status")
severity_out = gr.Markdown("---", label="Severity")
trend_out = gr.Markdown("---", label="Weather Trend")
recs_out = gr.Markdown("---", label="Recommendations")
with gr.TabItem("Last Analysis 📊"):
last_status = gr.Markdown("*No analysis yet*", elem_classes="output-card")
last_severity = gr.Markdown("---", elem_classes="output-card")
last_trend = gr.Markdown("---", elem_classes="output-card")
last_recs = gr.Markdown("---", elem_classes="output-card")
run_btn.click(
fn=safe_pipeline,
inputs=image_input,
outputs=[status_out, severity_out, trend_out, recs_out]
).then(
fn=lambda s,sv,tr,rc: (s,sv,tr,rc),
inputs=[status_out, severity_out, trend_out, recs_out],
outputs=[last_status, last_severity, last_trend, last_recs]
)
if __name__ == '__main__':
demo.queue(api_open=True).launch()