AbdullahImran commited on
Commit
fe9a939
·
verified ·
1 Parent(s): c1a8779

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -171
app.py CHANGED
@@ -26,201 +26,141 @@ API_URL = (
26
 
27
  # --- LOAD MODELS ---
28
  def load_models():
29
- try:
30
- # VGG fire detection model
31
- vgg_model = load_model(
32
- 'vgg16_focal_unfreeze_more.keras',
33
- custom_objects={'BinaryFocalCrossentropy': BinaryFocalCrossentropy}
34
- )
35
- # Xception severity model
36
- def focal_loss_fixed(gamma=2., alpha=.25):
37
- import tensorflow.keras.backend as K
38
- def loss_fn(y_true, y_pred):
39
- eps = K.epsilon()
40
- y_pred = K.clip(y_pred, eps, 1. - eps)
41
- ce = -y_true * K.log(y_pred)
42
- w = alpha * K.pow(1 - y_pred, gamma)
43
- return K.mean(w * ce, axis=-1)
44
- return loss_fn
45
- xce_model = load_model(
46
- 'severity_post_tta.keras',
47
- custom_objects={'focal_loss_fixed': focal_loss_fixed()}
48
- )
49
- # Reload ensemble models from .pkl
50
- rf_model = joblib.load('ensemble_rf_model.pkl')
51
- xgb_model = joblib.load('ensemble_xgb_model.pkl')
52
- lr_model = joblib.load('wildfire_logistic_model_synthetic.joblib')
53
- return vgg_model, xce_model, rf_model, xgb_model, lr_model
54
- except Exception as e:
55
- print(f"Error loading models: {e}")
56
- return None, None, None, None, None
57
 
58
- # Load models once
59
- vgg_model, xce_model, rf_model, xgb_model, lr_model = load_models()
60
 
 
61
  target_map = {0: 'mild', 1: 'moderate', 2: 'severe'}
62
- trend_map = {1: 'increase', 0: 'same', -1: 'decrease'}
63
  task_rules = {
64
- 'mild': {'decrease': 'mild', 'same': 'mild', 'increase': 'moderate'},
65
- 'moderate': {'decrease': 'mild', 'same': 'moderate', 'increase': 'severe'},
66
- 'severe': {'decrease': 'moderate', 'same': 'severe', 'increase': 'severe'}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
- recommendations = { ... } # (your existing recommendations dict)
69
 
70
  # --- PIPELINE FUNCTIONS ---
71
  def detect_fire(img):
72
- try:
73
- if vgg_model is None:
74
- return True, 0.85
75
- x = keras_image.img_to_array(img.resize((128,128)))[None]
76
- x = vgg_preprocess(x)
77
- prob = float(vgg_model.predict(x)[0][0])
78
- return prob >= 0.5, prob
79
- except Exception as e:
80
- print(f"Error in fire detection: {e}")
81
- return False, 0.0
82
 
83
  def classify_severity(img):
84
- try:
85
- if xce_model is None or rf_model is None or xgb_model is None:
86
- return 'moderate'
87
- x = keras_image.img_to_array(img.resize((224,224)))[None]
88
- x = xce_preprocess(x)
89
- preds = xce_model.predict(x)
90
- rf_p = rf_model.predict(preds)[0]
91
- xgb_p = xgb_model.predict(preds)[0]
92
- ensemble = int(round((rf_p + xgb_p) / 2))
93
- return target_map.get(ensemble, 'moderate')
94
- except Exception as e:
95
- print(f"Error in severity classification: {e}")
96
- return 'moderate'
97
 
98
 
99
  def fetch_weather_trend(lat, lon):
100
- try:
101
- end = datetime.utcnow()
102
- start = end - timedelta(days=1)
103
- url = API_URL.format(lat=lat, lon=lon,
104
- start=start.strftime('%Y-%m-%d'),
105
- end=end.strftime('%Y-%m-%d'))
106
- response = requests.get(url, timeout=5)
107
- response.raise_for_status()
108
- df = pd.DataFrame(response.json().get('daily', {}))
109
- except Exception:
110
- # fallback dummy data
111
- df = pd.DataFrame({
112
- 'date': [(datetime.utcnow() - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(1,-1,-1)],
113
- 'precipitation_sum': [5, 2],
114
- 'temperature_2m_max': [28, 30],
115
- 'temperature_2m_min': [18, 20],
116
- 'relative_humidity_2m_max': [70, 65],
117
- 'relative_humidity_2m_min': [40, 35],
118
- 'windspeed_10m_max': [15, 18]
119
- })
120
- # compute features
121
- df['temperature'] = (df['temperature_2m_max'] + df['temperature_2m_min']) / 2
122
- df['humidity'] = (df['relative_humidity_2m_max'] + df['relative_humidity_2m_min']) / 2
123
  df['wind_speed'] = df['windspeed_10m_max']
124
- df['precipitation'] = df['precipitation_sum']
125
  df['fire_risk_score'] = (
126
- 0.4 * (df['temperature'] / 55) +
127
- 0.2 * (1 - df['humidity'] / 100) +
128
- 0.3 * (df['wind_speed'] / 60) +
129
- 0.1 * (1 - df['precipitation'] / 50)
130
  )
131
- feat = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']].iloc[-1].values.reshape(1,-1)
132
- if lr_model is not None:
133
- trend_cl = lr_model.predict(feat)[0]
134
- return trend_map.get(trend_cl, 'same')
135
- return 'same'
136
 
137
 
138
  def generate_recommendations(original_severity, weather_trend):
139
- projected = task_rules[original_severity][weather_trend]
140
- rec = recommendations[projected]
141
- return (
142
- f"**Original Severity:** {original_severity.title()}\n"
143
- f"**Weather Trend:** {weather_trend.title()}\n"
144
- f"**Projected Severity:** {projected.title()}\n\n"
145
- "### Management Recommendations:\n"
146
- f"**Immediate:** {rec['immediate']}\n\n"
147
- f"**Evacuation:** {rec['evacuation']}\n\n"
148
- f"**Containment:** {rec['containment']}\n\n"
149
- f"**Prevention:** {rec['prevention']}\n\n"
150
- f"**Education:** {rec['education']}"
151
- )
152
-
153
-
154
  def pipeline(image):
155
- if image is None:
156
- return "No image provided", "N/A", "N/A", "**Please upload an image to analyze**"
157
  img = Image.fromarray(image).convert('RGB')
158
  fire, prob = detect_fire(img)
159
  if not fire:
160
- return (
161
- f"No wildfire detected (confidence: {(1-prob)*100:.1f}%)",
162
- "N/A", "N/A",
163
- "**No wildfire detected. Stay alert.**"
164
- )
165
- sev = classify_severity(img)
166
  trend = fetch_weather_trend(*FOREST_COORDS['Pakistan Forest'])
167
- recs = generate_recommendations(sev, trend)
168
- return (
169
- f"**Wildfire detected** (confidence: {prob*100:.1f}%)",
170
- f"**{sev.title()}**",
171
- f"**{trend.title()}**",
172
- recs
173
- )
174
-
175
-
176
- def safe_pipeline(image):
177
- try:
178
- return pipeline(image)
179
- except Exception as e:
180
- print(f"Error in pipeline: {e}")
181
- return "Error during analysis", "N/A", "N/A", f"**Error: {e}**"
182
-
183
- # --- GRADIO UI ---
184
- custom_css = '''
185
- #header { text-align: center; margin-bottom: 1rem; }
186
- '''
187
- with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
188
- with gr.Row(elem_id="header"):
189
- try:
190
- gr.Image(value="logo.png", show_label=False)
191
- except:
192
- pass
193
- with gr.Column():
194
- gr.Markdown("# 🔥 Wildfire Command Center")
195
- gr.Markdown("Upload a forest image to detect wildfire, classify severity, and get actionable recommendations.")
196
-
197
- with gr.Tabs():
198
- with gr.TabItem("Analyze 🔍"):
199
- with gr.Row():
200
- with gr.Column(scale=1):
201
- # use ImageEditor if in-browser annotation is needed, otherwise simple Image
202
- image_input = gr.Image(type="numpy", label="Forest Image")
203
- run_btn = gr.Button("Analyze Now", variant="primary")
204
- with gr.Column(scale=1):
205
- status_out = gr.Markdown("*Status will appear here*", label="Status")
206
- severity_out = gr.Markdown("---", label="Severity")
207
- trend_out = gr.Markdown("---", label="Weather Trend")
208
- recs_out = gr.Markdown("---", label="Recommendations")
209
- with gr.TabItem("Last Analysis 📊"):
210
- last_status = gr.Markdown("*No analysis yet*", elem_classes="output-card")
211
- last_severity = gr.Markdown("---", elem_classes="output-card")
212
- last_trend = gr.Markdown("---", elem_classes="output-card")
213
- last_recs = gr.Markdown("---", elem_classes="output-card")
214
-
215
- run_btn.click(
216
- fn=safe_pipeline,
217
- inputs=image_input,
218
- outputs=[status_out, severity_out, trend_out, recs_out]
219
- ).then(
220
- fn=lambda s,sv,tr,rc: (s,sv,tr,rc),
221
- inputs=[status_out, severity_out, trend_out, recs_out],
222
- outputs=[last_status, last_severity, last_trend, last_recs]
223
- )
224
 
225
  if __name__ == '__main__':
226
  demo.queue(api_open=True).launch()
 
26
 
27
  # --- LOAD MODELS ---
28
  def load_models():
29
+ # Fire detector (VGG16)
30
+ vgg_model = load_model(
31
+ 'vgg16_focal_unfreeze_more.keras',
32
+ custom_objects={'BinaryFocalCrossentropy': BinaryFocalCrossentropy}
33
+ )
34
+ # Severity classifier (Xception)
35
+ def focal_loss_fixed(gamma=2., alpha=.25):
36
+ import tensorflow.keras.backend as K
37
+ def loss_fn(y_true, y_pred):
38
+ eps = K.epsilon(); y_pred = K.clip(y_pred, eps, 1.-eps)
39
+ ce = -y_true * K.log(y_pred)
40
+ w = alpha * K.pow(1-y_pred, gamma)
41
+ return K.mean(w * ce, axis=-1)
42
+ return loss_fn
43
+ xce_model = load_model(
44
+ 'severity_post_tta.keras',
45
+ custom_objects={'focal_loss_fixed': focal_loss_fixed()}
46
+ )
47
+ # Ensemble and trend models
48
+ rf_model = joblib.load('ensemble_rf_model.pkl')
49
+ xgb_model = joblib.load('ensemble_xgb_model.pkl')
50
+ lr_model = joblib.load('wildfire_logistic_model_synthetic.joblib')
51
+ return vgg_model, xce_model, rf_model, xgb_model, lr_model
 
 
 
 
 
52
 
53
+ vgg_model, xception_model, rf_model, xgb_model, lr_model = load_models()
 
54
 
55
+ # --- RULES & TEMPLATES ---
56
  target_map = {0: 'mild', 1: 'moderate', 2: 'severe'}
57
+ trend_map = {1: 'increase', 0: 'same', -1: 'decrease'}
58
  task_rules = {
59
+ 'mild': {'decrease':'mild','same':'mild','increase':'moderate'},
60
+ 'moderate':{'decrease':'mild','same':'moderate','increase':'severe'},
61
+ 'severe': {'decrease':'moderate','same':'severe','increase':'severe'}
62
+ }
63
+ templates = {
64
+ 'mild': (
65
+ "**1. Immediate actions:** Monitor fire; deploy spot crews.\n"
66
+ "**2. Evacuation:** No mass evacuation; notify nearby communities.\n"
67
+ "**3. Short-term containment:** Establish fire lines.\n"
68
+ "**4. Long-term prevention:** Controlled underburning; vegetation management.\n"
69
+ "**5. Education:** Inform public on firewatch and reporting."
70
+ ),
71
+ 'moderate': (
72
+ "**1. Immediate actions:** Dispatch engines and aerial support.\n"
73
+ "**2. Evacuation:** Prepare evacuation zones; advise voluntary evacuation.\n"
74
+ "**3. Short-term containment:** Build fire breaks; water drops.\n"
75
+ "**4. Long-term prevention:** Fuel reduction programs.\n"
76
+ "**5. Education:** Community drills and awareness campaigns."
77
+ ),
78
+ 'severe': (
79
+ "**1. Immediate actions:** Full suppression with air tankers.\n"
80
+ "**2. Evacuation:** Mandatory evacuation; open shelters.\n"
81
+ "**3. Short-term containment:** Fire retardant lines; backfires.\n"
82
+ "**4. Long-term prevention:** Reforestation; infrastructure hardening.\n"
83
+ "**5. Education:** Emergency response training; risk communication."
84
+ )
85
  }
 
86
 
87
  # --- PIPELINE FUNCTIONS ---
88
  def detect_fire(img):
89
+ x = keras_image.img_to_array(img.resize((128,128)))[None]
90
+ x = vgg_preprocess(x)
91
+ prob = float(vgg_model.predict(x)[0][0])
92
+ return prob >= 0.5, prob
93
+
 
 
 
 
 
94
 
95
  def classify_severity(img):
96
+ x = keras_image.img_to_array(img.resize((224,224)))[None]
97
+ x = xce_preprocess(x)
98
+ preds = xception_model.predict(x)
99
+ rf_p = rf_model.predict(preds)[0]
100
+ xgb_p = xgb_model.predict(preds)[0]
101
+ ensemble = int(round((rf_p + xgb_p)/2))
102
+ return target_map.get(ensemble, 'moderate')
 
 
 
 
 
 
103
 
104
 
105
  def fetch_weather_trend(lat, lon):
106
+ end = datetime.utcnow()
107
+ start = end - timedelta(days=1)
108
+ url = API_URL.format(lat=lat, lon=lon,
109
+ start=start.strftime('%Y-%m-%d'),
110
+ end=end.strftime('%Y-%m-%d'))
111
+ df = pd.DataFrame(requests.get(url).json().get('daily', {}))
112
+ for c in ['precipitation_sum','temperature_2m_max','temperature_2m_min',
113
+ 'relative_humidity_2m_max','relative_humidity_2m_min','windspeed_10m_max']:
114
+ df[c] = pd.to_numeric(df.get(c,[]), errors='coerce')
115
+ df['precipitation'] = df['precipitation_sum'].fillna(0)
116
+ df['temperature'] = (df['temperature_2m_max'] + df['temperature_2m_min'])/2
117
+ df['humidity'] = (df['relative_humidity_2m_max'] + df['relative_humidity_2m_min'])/2
 
 
 
 
 
 
 
 
 
 
 
118
  df['wind_speed'] = df['windspeed_10m_max']
 
119
  df['fire_risk_score'] = (
120
+ 0.4*(df['temperature']/55) +
121
+ 0.2*(1-df['humidity']/100) +
122
+ 0.3*(df['wind_speed']/60) +
123
+ 0.1*(1-df['precipitation']/50)
124
  )
125
+ feats = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']]
126
+ feat = feats.fillna(feats.mean()).iloc[-1].values.reshape(1,-1)
127
+ trend_cl = lr_model.predict(feat)[0]
128
+ return trend_map.get(trend_cl, 'same')
 
129
 
130
 
131
  def generate_recommendations(original_severity, weather_trend):
132
+ # determine projected severity
133
+ proj = task_rules[original_severity][weather_trend]
134
+ rec = templates[proj]
135
+ # proper multi-line header
136
+ header = f"""**Original:** {original_severity.title()}
137
+ **Trend:** {weather_trend.title()}
138
+ **Projected:** {proj.title()}\n\n"""
139
+ return header + rec
140
+
141
+ # --- GRADIO INTERFACE ---
 
 
 
 
 
142
  def pipeline(image):
 
 
143
  img = Image.fromarray(image).convert('RGB')
144
  fire, prob = detect_fire(img)
145
  if not fire:
146
+ return f"No wildfire detected (prob={prob:.2f})", "N/A", "N/A", "**No wildfire detected. Stay alert.**"
147
+ sev = classify_severity(img)
 
 
 
 
148
  trend = fetch_weather_trend(*FOREST_COORDS['Pakistan Forest'])
149
+ recs = generate_recommendations(sev, trend)
150
+ return f"Fire Detected (prob={prob:.2f})", sev.title(), trend, recs
151
+
152
+ interface = gr.Interface(
153
+ fn=pipeline,
154
+ inputs=gr.Image(type='numpy', label='Upload Wildfire Image'),
155
+ outputs=[
156
+ gr.Textbox(label='Fire Status'),
157
+ gr.Textbox(label='Severity Level'),
158
+ gr.Textbox(label='Weather Trend'),
159
+ gr.Markdown(label='Recommendations')
160
+ ],
161
+ title='Wildfire Detection & Management Assistant',
162
+ description='Upload an image from a forest region in Pakistan to determine wildfire presence, severity, weather-driven trend, projection, and get expert recommendations.'
163
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
  if __name__ == '__main__':
166
  demo.queue(api_open=True).launch()