AbdullahImran commited on
Commit
74c1cfd
·
verified ·
1 Parent(s): daf8395

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -68
app.py CHANGED
@@ -18,8 +18,8 @@ API_URL = (
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,9 +34,10 @@ def load_models():
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(); y_pred = K.clip(y_pred, eps, 1.-eps)
 
38
  ce = -y_true * K.log(y_pred)
39
- w = alpha * K.pow(1-y_pred, gamma)
40
  return K.mean(w * ce, axis=-1)
41
  return loss_fn
42
  xce_model = load_model(
@@ -96,37 +97,33 @@ def detect_fire(img):
96
  print(f"Error in fire detection: {e}")
97
  return False, 0.0
98
 
99
-
100
  def classify_severity(img):
101
  try:
102
- if xception_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 = xception_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
-
116
  def fetch_weather_trend(lat, lon):
117
  try:
118
  end = datetime.utcnow()
119
  start = end - timedelta(days=1)
120
- url = API_URL.format(
121
- lat=lat, lon=lon,
122
- start=start.strftime('%Y-%m-%d'),
123
- end=end.strftime('%Y-%m-%d')
124
- )
125
  response = requests.get(url, timeout=5)
126
- if response.status_code != 200:
127
- raise Exception(f"API returned status {response.status_code}")
128
  df = pd.DataFrame(response.json().get('daily', {}))
129
  except Exception:
 
130
  df = pd.DataFrame({
131
  'date': [(datetime.utcnow() - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(1,-1,-1)],
132
  'precipitation_sum': [5, 2],
@@ -136,38 +133,41 @@ def fetch_weather_trend(lat, lon):
136
  'relative_humidity_2m_min': [40, 35],
137
  'windspeed_10m_max': [15, 18]
138
  })
 
139
  for c in ['precipitation_sum','temperature_2m_max','temperature_2m_min',
140
  'relative_humidity_2m_max','relative_humidity_2m_min','windspeed_10m_max']:
141
  df[c] = pd.to_numeric(df[c], errors='coerce')
 
142
  df['precipitation'] = df['precipitation_sum']
143
- df['temperature'] = (df['temperature_2m_max'] + df['temperature_2m_min'])/2
144
- df['humidity'] = (df['relative_humidity_2m_max'] + df['relative_humidity_2m_min'])/2
145
  df['wind_speed'] = df['windspeed_10m_max']
146
  df['fire_risk_score'] = (
147
- 0.4*(df['temperature']/55) +
148
- 0.2*(1-df['humidity']/100) +
149
- 0.3*(df['wind_speed']/60) +
150
- 0.1*(1-df['precipitation']/50)
151
  )
152
  feat = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']].iloc[-1].values.reshape(1,-1)
153
  if lr_model is not None:
154
  trend_cl = lr_model.predict(feat)[0]
155
- return trend_map.get(trend_cl,'same')
156
  return 'same'
157
 
158
-
159
  def generate_recommendations(original_severity, weather_trend):
160
  projected = task_rules[original_severity][weather_trend]
161
  rec = recommendations[projected]
162
- return f"**Original Severity:** {original_severity.title()} \n" \
163
- f"**Weather Trend:** {weather_trend.title()} \n" \
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):
@@ -176,52 +176,74 @@ def pipeline(image):
176
  img = Image.fromarray(image).convert('RGB')
177
  fire, prob = detect_fire(img)
178
  if not fire:
179
- return (f"No wildfire detected (confidence: {(1-prob)*100:.1f}%)",
180
- "N/A","N/A","**No wildfire detected. Stay alert.**")
 
 
 
181
  sev = classify_severity(img)
182
  trend = fetch_weather_trend(*FOREST_COORDS['Pakistan Forest'])
183
  recs = generate_recommendations(sev, trend)
184
- return (f"**Wildfire detected** (confidence: {prob*100:.1f}%)",
185
- f"**{sev.title()}**",
186
- f"**{trend.title()}**",
187
- recs)
 
 
188
 
189
- # --- LOAD MODELS GLOBALLY ---
190
- vgg_model, xception_model, rf_model, xgb_model, lr_model = load_models()
191
 
192
- # --- GRADIO BLOCKS UI & STYLING ---
193
- custom_css = """
194
- .sidebar { background: #2e3440; color: #eceff4; padding: 1rem; border-radius: 1rem; }
195
- #main-title { font-size: 2.5rem; color: #3b4252; }
196
- #sub-title { font-size: 1.125rem; color: #4c566a; }
197
- .card { background: #eceff4; color: #2e3440; border-radius: 0.75rem; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
198
- .gr-button { background: #5e81ac !important; color: white !important; border-radius: 0.5rem; }
199
- .status-badge { padding: 0.25em 0.75em; border-radius: 9999px; font-weight: 600; }
200
- .status-fire { background: #bf616a; color: white; }
201
- .status-no-fire { background: #a3be8c; color: white; }
202
- .gr-markdown { color: #2e3440; }
203
- """
204
 
205
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
206
- with gr.Row():
207
- with gr.Column(scale=2):
 
 
 
 
 
208
  gr.Markdown("# 🔥 Wildfire Command Center", elem_id="main-title")
209
- gr.Markdown(
210
- "Upload a **forest image** to detect wildfire, classify severity, fetch weather trend, and get management recommendations.",
211
- elem_id="sub-title"
212
- )
213
- image_input = gr.Image(type="numpy", label="Upload Forest Image")
214
- run_btn = gr.Button("Analyze Now", variant="primary")
215
- with gr.Column(scale=1, elem_classes="sidebar"):
216
- gr.Markdown("## 📊 Last Analysis")
217
- last_status = gr.Markdown("*No analysis yet*")
218
- last_severity = gr.Markdown("---")
219
- last_trend = gr.Markdown("---")
220
- last_recs = gr.Markdown("---")
221
-
 
 
 
 
 
 
 
 
 
 
222
  run_btn.click(
223
  fn=pipeline,
224
  inputs=image_input,
 
 
 
 
225
  outputs=[last_status, last_severity, last_trend, last_recs]
226
  )
227
 
 
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(
 
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],
 
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):
 
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
+ # --- GLOBAL MODEL LOADING ---
195
+ vgg_model, xce_model, rf_model, xgb_model, lr_model = load_models()
196
 
197
+ # --- UI: CUSTOM CSS & GRADIO LAYOUT ---
198
+ custom_css = '''
199
+ #header { text-align: center; margin: 0 0 1rem; }
200
+ #header img { height: 4rem; margin-right: 1rem; }
201
+ #main-title { font-size: 2.75rem; margin: 0.5rem 0; }
202
+ #sub-title { font-size: 1.25rem; color: #555; }
203
+ .gr-button.primary { background: #ff7043 !important; }
204
+ .output-card { background: #f7f7f7; border-radius: 0.75rem; padding: 1rem;
205
+ box-shadow: 0 1px 6px rgba(0,0,0,0.1); margin-bottom: 1rem; }
206
+ '''
 
 
207
 
208
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
209
+ # Header (add your logo.png in working directory or adjust path)
210
+ with gr.Row(elem_id="header"):
211
+ try:
212
+ gr.Image(value="logo.png", show_label=False)
213
+ except:
214
+ pass
215
+ with gr.Column():
216
  gr.Markdown("# 🔥 Wildfire Command Center", elem_id="main-title")
217
+ gr.Markdown("Upload a forest image to detect wildfire, classify severity, and get actionable recommendations.", elem_id="sub-title")
218
+
219
+ # Tabs: Analyze & Last Analysis
220
+ with gr.Tabs():
221
+ with gr.TabItem("Analyze 🔍"):
222
+ with gr.Row():
223
+ with gr.Column(scale=1):
224
+ image_input = gr.Image(type="numpy", label="Forest Image", tool="editor")
225
+ run_btn = gr.Button("Analyze Now", variant="primary")
226
+ with gr.Column(scale=1):
227
+ with gr.Spinner():
228
+ status_out = gr.Markdown("*Status will appear here*", label="Status")
229
+ severity_out = gr.Markdown("---", label="Severity")
230
+ trend_out = gr.Markdown("---", label="Weather Trend")
231
+ recs_out = gr.Markdown("---", label="Recommendations")
232
+
233
+ with gr.TabItem("Last Analysis 📊"):
234
+ last_status = gr.Markdown("*No analysis yet*", elem_classes="output-card")
235
+ last_severity = gr.Markdown("---", elem_classes="output-card")
236
+ last_trend = gr.Markdown("---", elem_classes="output-card")
237
+ last_recs = gr.Markdown("---", elem_classes="output-card")
238
+
239
+ # Bind actions: analyze then archive outputs
240
  run_btn.click(
241
  fn=pipeline,
242
  inputs=image_input,
243
+ outputs=[status_out, severity_out, trend_out, recs_out]
244
+ ).then(
245
+ fn=lambda s,sv,tr,rc: (s,sv,tr,rc),
246
+ inputs=[status_out, severity_out, trend_out, recs_out],
247
  outputs=[last_status, last_severity, last_trend, last_recs]
248
  )
249