AbdullahImran commited on
Commit
ec1da24
·
verified ·
1 Parent(s): 3fc634d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +163 -63
app.py CHANGED
@@ -11,7 +11,6 @@ from tensorflow.keras.applications.vgg16 import preprocess_input as vgg_preproce
11
  from tensorflow.keras.applications.xception import preprocess_input as xce_preprocess
12
  from tensorflow.keras.losses import BinaryFocalCrossentropy
13
  from PIL import Image
14
- import traceback
15
 
16
  # --- CONFIGURATION ---
17
  FOREST_COORDS = {'Pakistan Forest': (34.0, 73.0)}
@@ -19,8 +18,8 @@ API_URL = (
19
  "https://archive-api.open-meteo.com/v1/archive"
20
  "?latitude={lat}&longitude={lon}"
21
  "&start_date={start}&end_date={end}"
22
- "&daily=temperature_2m_max,temperature_2m_min,"
23
- "precipitation_sum,windspeed_10m_max,"
24
  "relative_humidity_2m_max,relative_humidity_2m_min"
25
  "&timezone=UTC"
26
  )
@@ -35,9 +34,10 @@ def load_models():
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(
@@ -50,10 +50,9 @@ def load_models():
50
  return vgg_model, xce_model, rf_model, xgb_model, lr_model
51
  except Exception as e:
52
  print(f"Error loading models: {e}")
53
- traceback.print_exc()
54
  return None, None, None, None, None
55
 
56
- # --- RULES & TEMPLATES (no ellipses) ---
57
  target_map = {0: 'mild', 1: 'moderate', 2: 'severe'}
58
  trend_map = {1: 'increase', 0: 'same', -1: 'decrease'}
59
  task_rules = {
@@ -63,97 +62,198 @@ task_rules = {
63
  }
64
  recommendations = {
65
  'mild': {
66
- 'immediate': "Deploy spot crews...",
67
- 'evacuation': "No mass evacuation...",
68
- 'containment': "Establish initial fire lines...",
69
- 'prevention': "Implement controlled underburning...",
70
- 'education': "Inform public on fire watch..."
71
  },
72
  'moderate': {
73
- 'immediate': "Dispatch multiple engines...",
74
- 'evacuation': "Prepare evacuation zones...",
75
- 'containment': "Build substantial fire breaks...",
76
- 'prevention': "Initiate fuel reduction...",
77
- 'education': "Conduct community emergency drills..."
78
  },
79
  'severe': {
80
- 'immediate': "Implement full suppression...",
81
- 'evacuation': "Issue mandatory evacuation orders...",
82
- 'containment': "Deploy fire retardant lines...",
83
- 'prevention': "Plan for reforestation...",
84
- 'education': "Conduct comprehensive training..."
85
  }
86
  }
87
 
88
- # --- PIPELINE & HELPERS ---
89
  def detect_fire(img):
90
  try:
91
- if vgg_model is None: return True, 0.85
 
92
  x = keras_image.img_to_array(img.resize((128,128)))[None]
93
  x = vgg_preprocess(x)
94
  prob = float(vgg_model.predict(x)[0][0])
95
  return prob >= 0.5, prob
96
- except Exception:
97
- traceback.print_exc()
98
  return False, 0.0
99
 
100
  def classify_severity(img):
101
  try:
102
- if xception_model is None: return 'moderate'
 
103
  x = keras_image.img_to_array(img.resize((224,224)))[None]
104
  x = xce_preprocess(x)
105
- preds = xception_model.predict(x)
106
  rf_p = rf_model.predict(preds)[0]
107
  xgb_p = xgb_model.predict(preds)[0]
108
- ensemble = int(round((rf_p + xgb_p)/2))
109
- return target_map.get(ensemble,'moderate')
110
- except Exception:
111
- traceback.print_exc()
112
  return 'moderate'
113
 
114
  def fetch_weather_trend(lat, lon):
115
  try:
116
- end = datetime.utcnow(); start = end - timedelta(days=1)
117
- url = API_URL.format(lat=lat, lon=lon, start=start.strftime('%Y-%m-%d'), end=end.strftime('%Y-%m-%d'))
118
- resp = requests.get(url, timeout=5)
119
- resp.raise_for_status()
120
- df = pd.DataFrame(resp.json().get('daily', {}))
 
 
 
121
  except Exception:
122
- traceback.print_exc()
123
- df = pd.DataFrame({ 'date': ['2025-04-25','2025-04-26'], '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] })
124
- df['temperature'] = (df['temperature_2m_max'] + df['temperature_2m_min'])/2
125
- df['humidity'] = (df['relative_humidity_2m_max'] + df['relative_humidity_2m_min'])/2
126
- df['wind_speed'] = df['windspeed_10m_max']; df['precipitation'] = df['precipitation_sum']
127
- 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))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  feat = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']].iloc[-1].values.reshape(1,-1)
129
- try:
130
- cl = lr_model.predict(feat)[0]; return trend_map.get(cl,'same')
131
- except Exception:
132
- traceback.print_exc(); return 'same'
133
 
134
- def generate_recommendations(orig, trend):
135
- try:
136
- proj = task_rules[orig][trend]; rec = recommendations[proj]
137
- return f"**Original Severity:** {orig.title()} \n**Weather Trend:** {trend.title()} \n**Projected Severity:** {proj.title()}\n\n### Management Recommendations:\n**Immediate:** {rec['immediate']}\n\n**Evacuation:** {rec['evacuation']}\n\n**Containment:** {rec['containment']}\n\n**Prevention:** {rec['prevention']}\n\n**Education:** {rec['education']}"
138
- except Exception:
139
- traceback.print_exc(); return "**Error generating recommendations**"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
- # --- WRAPPER FOR GRADIO ---
142
  def safe_pipeline(image):
143
  try:
144
  return pipeline(image)
145
  except Exception as e:
146
- tb = traceback.format_exc()
147
- return f"Error: {e}\n{tb}", "", "", ""
148
 
149
- # --- LOAD MODELS GLOBALLY ---
150
- vgg_model, xception_model, rf_model, xgb_model, lr_model = load_models()
151
 
152
- # --- UI LAYOUT & STYLING ---
153
- custom_css = "..." # (same as before)
 
 
 
 
 
 
 
 
154
 
155
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
156
- # (UI definition same as before)
157
- run_btn.click(fn=safe_pipeline, inputs=image_input, outputs=[last_status, last_severity, last_trend, last_recs])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- if __name__ == '__main__': demo.queue(api_open=True).launch()
 
 
11
  from tensorflow.keras.applications.xception import preprocess_input as xce_preprocess
12
  from tensorflow.keras.losses import BinaryFocalCrossentropy
13
  from PIL import Image
 
14
 
15
  # --- CONFIGURATION ---
16
  FOREST_COORDS = {'Pakistan Forest': (34.0, 73.0)}
 
18
  "https://archive-api.open-meteo.com/v1/archive"
19
  "?latitude={lat}&longitude={lon}"
20
  "&start_date={start}&end_date={end}"
21
+ "&daily=temperature_2m_max,temperature_2m_min,"
22
+ "precipitation_sum,windspeed_10m_max,"
23
  "relative_humidity_2m_max,relative_humidity_2m_min"
24
  "&timezone=UTC"
25
  )
 
34
  def focal_loss_fixed(gamma=2., alpha=.25):
35
  import tensorflow.keras.backend as K
36
  def loss_fn(y_true, y_pred):
37
+ eps = K.epsilon()
38
+ 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(
 
50
  return vgg_model, xce_model, rf_model, xgb_model, lr_model
51
  except Exception as e:
52
  print(f"Error loading models: {e}")
 
53
  return None, None, None, None, None
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 = {
 
62
  }
63
  recommendations = {
64
  'mild': {
65
+ 'immediate': "Deploy spot crews for initial attack. Establish command post. Monitor fire behavior with drones or aircraft. Alert local fire stations.",
66
+ 'evacuation': "No mass evacuation needed. Notify nearby communities of potential risk. Prepare evacuation routes if conditions change.",
67
+ 'containment': "Establish initial fire lines. Use hand crews for direct attack. Position water resources. Clear fuel breaks where feasible.",
68
+ 'prevention': "Implement controlled underburning in surrounding areas. Manage vegetation density. Create defensible spaces around structures.",
69
+ 'education': "Inform public on fire watch protocols and reporting mechanisms. Train local volunteers in basic firefighting techniques."
70
  },
71
  'moderate': {
72
+ 'immediate': "Dispatch multiple engines and aerial support. Establish unified command system. Deploy heavy equipment. Request additional resources.",
73
+ 'evacuation': "Prepare evacuation zones and staging areas. Advise voluntary evacuation for vulnerable populations. Alert emergency shelters.",
74
+ 'containment': "Build substantial fire breaks. Conduct water drops from helicopters. Implement indirect attack strategies. Protect critical infrastructure.",
75
+ 'prevention': "Initiate fuel reduction programs in adjacent areas. Create wider buffer zones. Assess watershed protection needs.",
76
+ 'education': "Conduct community emergency drills. Launch awareness campaigns on evacuation procedures. Distribute preparedness materials."
77
  },
78
  'severe': {
79
+ 'immediate': "Implement full suppression with air tankers and multiple resources. Establish incident management team. Request state/federal assistance. Deploy specialized teams.",
80
+ 'evacuation': "Issue mandatory evacuation orders. Open multiple emergency shelters. Implement traffic control measures. Assist vulnerable populations.",
81
+ 'containment': "Deploy fire retardant lines from aircraft. Consider backfires and burnout operations. Protect critical infrastructure. Establish multiple control lines.",
82
+ 'prevention': "Plan for reforestation and erosion control. Harden infrastructure against future fires. Implement watershed protection measures.",
83
+ 'education': "Conduct comprehensive emergency response training. Implement risk communication strategies. Develop long-term community resilience programs."
84
  }
85
  }
86
 
87
+ # --- PIPELINE FUNCTIONS ---
88
  def detect_fire(img):
89
  try:
90
+ if vgg_model is None:
91
+ return True, 0.85
92
  x = keras_image.img_to_array(img.resize((128,128)))[None]
93
  x = vgg_preprocess(x)
94
  prob = float(vgg_model.predict(x)[0][0])
95
  return prob >= 0.5, prob
96
+ except Exception as e:
97
+ print(f"Error in fire detection: {e}")
98
  return False, 0.0
99
 
100
  def classify_severity(img):
101
  try:
102
+ if xce_model is None or rf_model is None or xgb_model is None:
103
+ return 'moderate'
104
  x = keras_image.img_to_array(img.resize((224,224)))[None]
105
  x = xce_preprocess(x)
106
+ preds = xce_model.predict(x)
107
  rf_p = rf_model.predict(preds)[0]
108
  xgb_p = xgb_model.predict(preds)[0]
109
+ ensemble = int(round((rf_p + xgb_p) / 2))
110
+ return target_map.get(ensemble, 'moderate')
111
+ except Exception as e:
112
+ print(f"Error in severity classification: {e}")
113
  return 'moderate'
114
 
115
  def fetch_weather_trend(lat, lon):
116
  try:
117
+ end = datetime.utcnow()
118
+ start = end - timedelta(days=1)
119
+ url = API_URL.format(lat=lat, lon=lon,
120
+ start=start.strftime('%Y-%m-%d'),
121
+ end=end.strftime('%Y-%m-%d'))
122
+ response = requests.get(url, timeout=5)
123
+ response.raise_for_status()
124
+ df = pd.DataFrame(response.json().get('daily', {}))
125
  except Exception:
126
+ # Fallback sample data
127
+ df = pd.DataFrame({
128
+ 'date': [(datetime.utcnow() - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(1,-1,-1)],
129
+ 'precipitation_sum': [5, 2],
130
+ 'temperature_2m_max': [28, 30],
131
+ 'temperature_2m_min': [18, 20],
132
+ 'relative_humidity_2m_max': [70, 65],
133
+ 'relative_humidity_2m_min': [40, 35],
134
+ 'windspeed_10m_max': [15, 18]
135
+ })
136
+ # Numeric conversions
137
+ for c in ['precipitation_sum','temperature_2m_max','temperature_2m_min',
138
+ 'relative_humidity_2m_max','relative_humidity_2m_min','windspeed_10m_max']:
139
+ df[c] = pd.to_numeric(df[c], errors='coerce')
140
+ # Feature engineering
141
+ df['precipitation'] = df['precipitation_sum']
142
+ df['temperature'] = (df['temperature_2m_max'] + df['temperature_2m_min']) / 2
143
+ df['humidity'] = (df['relative_humidity_2m_max'] + df['relative_humidity_2m_min']) / 2
144
+ df['wind_speed'] = df['windspeed_10m_max']
145
+ df['fire_risk_score'] = (
146
+ 0.4 * (df['temperature'] / 55) +
147
+ 0.2 * (1 - df['humidity'] / 100) +
148
+ 0.3 * (df['wind_speed'] / 60) +
149
+ 0.1 * (1 - df['precipitation'] / 50)
150
+ )
151
  feat = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']].iloc[-1].values.reshape(1,-1)
152
+ if lr_model is not None:
153
+ trend_cl = lr_model.predict(feat)[0]
154
+ return trend_map.get(trend_cl, 'same')
155
+ return 'same'
156
 
157
+ def generate_recommendations(original_severity, weather_trend):
158
+ projected = task_rules[original_severity][weather_trend]
159
+ rec = recommendations[projected]
160
+ return (f"**Original Severity:** {original_severity.title()} \
161
+ " \
162
+ f"**Weather Trend:** {weather_trend.title()} \
163
+ " \
164
+ f"**Projected Severity:** {projected.title()}\n\n" \
165
+ "### Management Recommendations:\n" \
166
+ f"**Immediate:** {rec['immediate']}\n\n" \
167
+ f"**Evacuation:** {rec['evacuation']}\n\n" \
168
+ f"**Containment:** {rec['containment']}\n\n" \
169
+ f"**Prevention:** {rec['prevention']}\n\n" \
170
+ f"**Education:** {rec['education']}")
171
+
172
+ # --- MAIN PIPELINE ---
173
+ def pipeline(image):
174
+ if image is None:
175
+ return "No image provided","N/A","N/A","**Please upload an image to analyze**"
176
+ img = Image.fromarray(image).convert('RGB')
177
+ fire, prob = detect_fire(img)
178
+ if not fire:
179
+ return (
180
+ f"No wildfire detected (confidence: {(1-prob)*100:.1f}%)",
181
+ "N/A","N/A",
182
+ "**No wildfire detected. Stay alert.**"
183
+ )
184
+ sev = classify_severity(img)
185
+ trend = fetch_weather_trend(*FOREST_COORDS['Pakistan Forest'])
186
+ recs = generate_recommendations(sev, trend)
187
+ return (
188
+ f"**Wildfire detected** (confidence: {prob*100:.1f}%)",
189
+ f"**{sev.title()}**",
190
+ f"**{trend.title()}**",
191
+ recs
192
+ )
193
 
194
+ # --- SAFE WRAPPER FOR UI ---
195
  def safe_pipeline(image):
196
  try:
197
  return pipeline(image)
198
  except Exception as e:
199
+ print(f"Error in pipeline: {e}")
200
+ return "Error during analysis","N/A","N/A", f"**Error: {e}**"
201
 
202
+ # --- GLOBAL MODEL LOADING ---
203
+ vgg_model, xce_model, rf_model, xgb_model, lr_model = load_models()
204
 
205
+ # --- UI: CUSTOM CSS & GRADIO LAYOUT ---
206
+ custom_css = '''
207
+ #header { text-align: center; margin: 0 0 1rem; }
208
+ #header img { height: 4rem; margin-right: 1rem; }
209
+ #main-title { font-size: 2.75rem; margin: 0.5rem 0; }
210
+ #sub-title { font-size: 1.25rem; color: #555; }
211
+ .gr-button.primary { background: #ff7043 !important; }
212
+ .output-card { background: #f7f7f7; border-radius: 0.75rem; padding: 1rem;
213
+ box-shadow: 0 1px 6px rgba(0,0,0,0.1); margin-bottom: 1rem; }
214
+ '''
215
 
216
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
217
+ # Header (add your logo.png in working directory or adjust path)
218
+ with gr.Row(elem_id="header"):
219
+ try:
220
+ gr.Image(value="logo.png", show_label=False)
221
+ except:
222
+ pass
223
+ with gr.Column():
224
+ gr.Markdown("# 🔥 Wildfire Command Center", elem_id="main-title")
225
+ gr.Markdown("Upload a forest image to detect wildfire, classify severity, and get actionable recommendations.", elem_id="sub-title")
226
+
227
+ # Tabs: Analyze & Last Analysis
228
+ with gr.Tabs():
229
+ with gr.TabItem("Analyze 🔍"):
230
+ with gr.Row():
231
+ with gr.Column(scale=1):
232
+ image_input = gr.Image(type="numpy", label="Forest Image", tool="editor")
233
+ run_btn = gr.Button("Analyze Now", variant="primary")
234
+ with gr.Column(scale=1):
235
+ with gr.Spinner():
236
+ status_out = gr.Markdown("*Status will appear here*", label="Status")
237
+ severity_out = gr.Markdown("---", label="Severity")
238
+ trend_out = gr.Markdown("---", label="Weather Trend")
239
+ recs_out = gr.Markdown("---", label="Recommendations")
240
+
241
+ with gr.TabItem("Last Analysis 📊"):
242
+ last_status = gr.Markdown("*No analysis yet*", elem_classes="output-card")
243
+ last_severity = gr.Markdown("---", elem_classes="output-card")
244
+ last_trend = gr.Markdown("---", elem_classes="output-card")
245
+ last_recs = gr.Markdown("---", elem_classes="output-card")
246
+
247
+ # Bind actions: analyze then archive outputs
248
+ run_btn.click(
249
+ fn=safe_pipeline,
250
+ inputs=image_input,
251
+ outputs=[status_out, severity_out, trend_out, recs_out]
252
+ ).then(
253
+ fn=lambda s,sv,tr,rc: (s,sv,tr,rc),
254
+ inputs=[status_out, severity_out, trend_out, recs_out],
255
+ outputs=[last_status, last_severity, last_trend, last_recs]
256
+ )
257
 
258
+ if __name__ == '__main__':
259
+ demo.queue(api_open=True).launch()