AbdullahImran commited on
Commit
7681b94
·
verified ·
1 Parent(s): d8e87f2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +177 -44
app.py CHANGED
@@ -52,70 +52,203 @@ def load_models():
52
  return None, None, None, None, None
53
 
54
  # --- RULES & TEMPLATES ---
55
- target_map = {0: 'Mild', 1: 'Moderate', 2: 'Severe'}
56
- trend_map = {1: 'Increasing', 0: 'Stable', -1: 'Decreasing'}
57
-
58
- # Severity progression rules based on current severity and weather trend
59
  task_rules = {
60
- 'Mild': {'Decreasing':'Mild','Stable':'Mild','Increasing':'Moderate'},
61
- 'Moderate':{'Decreasing':'Mild','Stable':'Moderate','Increasing':'Severe'},
62
- 'Severe': {'Decreasing':'Moderate','Stable':'Severe','Increasing':'Severe'}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
64
-
65
- recommendations = { ... } # same as before
66
 
67
  # --- PIPELINE FUNCTIONS ---
68
- def detect_fire(img): ...
69
- def classify_severity(img): ...
70
- def fetch_weather_trend(lat, lon): ...
71
- def generate_recommendations(original_severity, weather_trend): ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
  # --- MAIN PIPELINE ---
74
- def pipeline(image, progress=gr.Progress()):
75
- progress(0.1, "Analyzing image…")
76
  if image is None:
77
- return ("No image provided", "N/A", "N/A", "**Please upload an image to analyze.**")
78
  img = Image.fromarray(image).convert('RGB')
79
  fire, prob = detect_fire(img)
80
- progress(0.3, "Detecting fire presence…")
81
  if not fire:
82
- return (f"No wildfire detected (confidence {(1-prob)*100:.1f}% )", "N/A", "N/A", "**No wildfire detected. Continue monitoring.**")
83
  severity = classify_severity(img)
84
- progress(0.6, "Classifying severity…")
85
  trend = fetch_weather_trend(*FOREST_COORDS['Pakistan Forest'])
86
- progress(0.8, "Computing recommendations…")
87
- recs = generate_recommendations(severity, trend)
88
- return (f"🔥 Wildfire detected! Confidence: {prob*100:.1f}%", severity, trend, recs)
89
 
 
90
  vgg_model, xception_model, rf_model, xgb_model, lr_model = load_models()
91
 
92
- # --- GRADIO BLOCKS UI ---
93
- css = '''
94
- .sidebar { background: #111827; color: #F9FAFB; padding: 1rem; border-radius: 0.5rem; }
95
- .card { background: #FFFFFF; border-radius: 1rem; box-shadow: 0 4px 12px rgba(0,0,0,0.1); padding: 1rem; margin-bottom: 1rem; }
96
- #title { font-size: 2.25rem; font-weight: 700; color: #1F2937; }
97
- #desc { font-size: 1rem; color: #4B5563; margin-bottom: 1rem; }
98
- .gr-button { background: #EF4444 !important; color: white !important; border-radius: 0.75rem; padding: 0.75rem 1.25rem; }
99
- '''
 
 
 
100
 
101
- with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
102
  with gr.Row():
103
- with gr.Column(scale=1):
104
- gr.Markdown("<div id='title'>Wildfire Command Center</div>", elem_id="title")
105
- gr.Markdown("<div id='desc'>Upload a forest image from Pakistan to detect wildfires, assess severity, forecast weather-driven trends, and receive expert management plans.</div>", elem_id="desc")
106
- image_input = gr.Image(type='numpy', label='Upload Forest Image', tool='editor')
107
- run_btn = gr.Button("🔍 Analyze Now", variant="primary")
108
- with gr.Column(scale=0.6, elem_classes="sidebar"):
109
- gr.Markdown("### Last Analysis", elem_classes="card")
110
- last_status = gr.Textbox(label='Fire Status', interactive=False)
111
- last_severity = gr.Textbox(label='Severity Level', interactive=False)
112
- last_trend = gr.Textbox(label='Weather Trend', interactive=False)
113
- last_recs = gr.Markdown(label='Recommendations', interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  run_btn.click(
115
- fn=pipeline,
116
  inputs=image_input,
117
  outputs=[last_status, last_severity, last_trend, last_recs]
118
  )
119
 
120
  if __name__ == '__main__':
121
- demo.queue(api_open=True).launch(share=False)
 
52
  return None, None, None, None, None
53
 
54
  # --- RULES & TEMPLATES ---
55
+ target_map = {0: 'mild', 1: 'moderate', 2: 'severe'}
56
+ trend_map = {1: 'increase', 0: 'same', -1: 'decrease'}
 
 
57
  task_rules = {
58
+ 'mild': {'decrease':'mild','same':'mild','increase':'moderate'},
59
+ 'moderate':{'decrease':'mild','same':'moderate','increase':'severe'},
60
+ 'severe': {'decrease':'moderate','same':'severe','increase':'severe'}
61
+ }
62
+ recommendations = {
63
+ 'mild': {
64
+ 'immediate': "Deploy spot crews for initial attack. Establish command post. Monitor fire behavior with drones or aircraft. Alert local fire stations.",
65
+ 'evacuation': "No mass evacuation needed. Notify nearby communities of potential risk. Prepare evacuation routes if conditions change.",
66
+ 'containment': "Establish initial fire lines. Use hand crews for direct attack. Position water resources. Clear fuel breaks where feasible.",
67
+ 'prevention': "Implement controlled underburning in surrounding areas. Manage vegetation density. Create defensible spaces around structures.",
68
+ 'education': "Inform public on fire watch protocols and reporting mechanisms. Train local volunteers in basic firefighting techniques."
69
+ },
70
+ 'moderate': {
71
+ 'immediate': "Dispatch multiple engines and aerial support. Establish unified command system. Deploy heavy equipment. Request additional resources.",
72
+ 'evacuation': "Prepare evacuation zones and staging areas. Advise voluntary evacuation for vulnerable populations. Alert emergency shelters.",
73
+ 'containment': "Build substantial fire breaks. Conduct water drops from helicopters. Implement indirect attack strategies. Protect critical infrastructure.",
74
+ 'prevention': "Initiate fuel reduction programs in adjacent areas. Create wider buffer zones. Assess watershed protection needs.",
75
+ 'education': "Conduct community emergency drills. Launch awareness campaigns on evacuation procedures. Distribute preparedness materials."
76
+ },
77
+ 'severe': {
78
+ 'immediate': "Implement full suppression with air tankers and multiple resources. Establish incident management team. Request state/federal assistance. Deploy specialized teams.",
79
+ 'evacuation': "Issue mandatory evacuation orders. Open multiple emergency shelters. Implement traffic control measures. Assist vulnerable populations.",
80
+ 'containment': "Deploy fire retardant lines from aircraft. Consider backfires and burnout operations. Protect critical infrastructure. Establish multiple control lines.",
81
+ 'prevention': "Plan for reforestation and erosion control. Harden infrastructure against future fires. Implement watershed protection measures.",
82
+ 'education': "Conduct comprehensive emergency response training. Implement risk communication strategies. Develop long-term community resilience programs."
83
+ }
84
  }
 
 
85
 
86
  # --- PIPELINE FUNCTIONS ---
87
+ def detect_fire(img):
88
+ try:
89
+ if vgg_model is None:
90
+ return True, 0.85
91
+ x = keras_image.img_to_array(img.resize((128,128)))[None]
92
+ x = vgg_preprocess(x)
93
+ prob = float(vgg_model.predict(x)[0][0])
94
+ return prob >= 0.5, prob
95
+ except Exception as e:
96
+ print(f"Error in fire detection: {e}")
97
+ return False, 0.0
98
+
99
+ def classify_severity(img):
100
+ try:
101
+ if xception_model is None or rf_model is None or xgb_model is None:
102
+ 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 as e:
111
+ print(f"Error in severity classification: {e}")
112
+ return 'moderate'
113
+
114
+ def fetch_weather_trend(lat, lon):
115
+ try:
116
+ try:
117
+ end = datetime.utcnow()
118
+ start = end - timedelta(days=1)
119
+ url = API_URL.format(lat=lat, lon=lon, start=start.strftime('%Y-%m-%d'), end=end.strftime('%Y-%m-%d'))
120
+ response = requests.get(url, timeout=5)
121
+ if response.status_code != 200:
122
+ raise Exception(f"API returned status code {response.status_code}")
123
+ df = pd.DataFrame(response.json().get('daily', {}))
124
+ except Exception as e:
125
+ print(f"API error: {e}. Using synthetic data.")
126
+ df = pd.DataFrame({
127
+ 'date': [(datetime.utcnow() - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(1, -1, -1)],
128
+ 'precipitation_sum': [5, 2],
129
+ 'temperature_2m_max': [28, 30],
130
+ 'temperature_2m_min': [18, 20],
131
+ 'relative_humidity_2m_max': [70, 65],
132
+ 'relative_humidity_2m_min': [40, 35],
133
+ 'windspeed_10m_max': [15, 18]
134
+ })
135
+ for c in ['precipitation_sum','temperature_2m_max','temperature_2m_min',
136
+ 'relative_humidity_2m_max','relative_humidity_2m_min','windspeed_10m_max']:
137
+ df[c] = pd.to_numeric(df.get(c,[]), errors='coerce')
138
+ df['precipitation'] = df['precipitation_sum'].fillna(0)
139
+ df['temperature'] = (df['temperature_2m_max'] + df['temperature_2m_min'])/2
140
+ df['humidity'] = (df['relative_humidity_2m_max'] + df['relative_humidity_2m_min'])/2
141
+ df['wind_speed'] = df['windspeed_10m_max']
142
+ df['fire_risk_score'] = (
143
+ 0.4*(df['temperature']/55) +
144
+ 0.2*(1-df['humidity']/100) +
145
+ 0.3*(df['wind_speed']/60) +
146
+ 0.1*(1-df['precipitation']/50)
147
+ )
148
+ feats = df[['temperature','humidity','wind_speed','precipitation','fire_risk_score']]
149
+ feat = feats.fillna(feats.mean()).iloc[-1].values.reshape(1,-1)
150
+ if lr_model is not None:
151
+ trend_cl = lr_model.predict(feat)[0]
152
+ return trend_map.get(trend_cl, 'same')
153
+ else:
154
+ if df['fire_risk_score'].iloc[-1] > 0.6:
155
+ return 'increase'
156
+ elif df['fire_risk_score'].iloc[-1] < 0.4:
157
+ return 'decrease'
158
+ return 'same'
159
+ except Exception as e:
160
+ print(f"Error in weather trend analysis: {e}")
161
+ return 'same'
162
+
163
+ def generate_recommendations(original_severity, weather_trend):
164
+ projected_severity = task_rules[original_severity][weather_trend]
165
+ rec = recommendations[projected_severity]
166
+ recommendation_text = f"""**Original Severity:** {original_severity.title()}
167
+ **Weather Trend:** {weather_trend.title()}
168
+ **Projected Severity:** {projected_severity.title()}
169
+
170
+ ### Management Recommendations:
171
+
172
+ **1. Immediate Actions:**
173
+ {rec['immediate']}
174
+
175
+ **2. Evacuation Guidelines:**
176
+ {rec['evacuation']}
177
+
178
+ **3. Short-term Containment:**
179
+ {rec['containment']}
180
+
181
+ **4. Long-term Prevention & Recovery:**
182
+ {rec['prevention']}
183
+
184
+ **5. Community Education:**
185
+ {rec['education']}
186
+ """
187
+ return recommendation_text
188
 
189
  # --- MAIN PIPELINE ---
190
+ def pipeline(image):
 
191
  if image is None:
192
+ return "No image provided", "N/A", "N/A", "**Please upload an image to analyze**"
193
  img = Image.fromarray(image).convert('RGB')
194
  fire, prob = detect_fire(img)
 
195
  if not fire:
196
+ return f"No wildfire detected (confidence: {(1-prob)*100:.1f}%)", "N/A", "N/A", "**No wildfire detected. Stay alert and maintain regular monitoring.**"
197
  severity = classify_severity(img)
 
198
  trend = fetch_weather_trend(*FOREST_COORDS['Pakistan Forest'])
199
+ recommendations_text = generate_recommendations(severity, trend)
200
+ return f"Wildfire detected (confidence: {prob*100:.1f}%)", severity.title(), trend.title(), recommendations_text
 
201
 
202
+ # --- LOAD MODELS GLOBALLY ---
203
  vgg_model, xception_model, rf_model, xgb_model, lr_model = load_models()
204
 
205
+ # --- GRADIO BLOCKS UI WITH ENHANCED TEXT & STYLING ---
206
+ custom_css = """
207
+ .sidebar { background: #1f2937; color: #f9fafb; padding: 1rem; border-radius: 1rem; height: 100%; }
208
+ #main-title { font-size: 2.75rem; font-weight: 700; color: #111827; margin-bottom: 0.25em; }
209
+ #sub-title { font-size: 1.125rem; color: #4b5563; margin-bottom: 1.5em; }
210
+ .card { background: #ffffff; border-radius: 1rem; box-shadow: 0 4px 16px rgba(0,0,0,0.08); padding: 1rem; margin-bottom: 1rem; }
211
+ .gr-button { border-radius: 0.75rem; padding: 0.75rem 1.5rem; font-size: 1rem; }
212
+ .status-badge { display: inline-block; padding: 0.25em 0.75em; border-radius: 9999px; font-weight: 600; margin-bottom: 0.5em; }
213
+ .status-fire { background: #dc2626; color: white; }
214
+ .status-no-fire { background: #16a34a; color: white; }
215
+ """
216
 
217
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
218
  with gr.Row():
219
+ with gr.Column(scale=2):
220
+ gr.Markdown("🔥 **Wildfire Command Center**", elem_id="main-title")
221
+ gr.Markdown(
222
+ "Upload a **forest image** from Pakistan to automatically detect wildfire, "
223
+ "classify its severity, fetch the latest weather-driven risk trend, "
224
+ "and receive expert management recommendations.",
225
+ elem_id="sub-title"
226
+ )
227
+ image_input = gr.Image(type="numpy", label="Select Forest Image")
228
+ run_btn = gr.Button("Analyze Image", variant="primary")
229
+ with gr.Column(scale=1, elem_classes="sidebar"):
230
+ gr.Markdown("### 📊 Last Analysis")
231
+ last_status = gr.HTML("<div class='card'>No run yet</div>")
232
+ last_severity = gr.HTML("<div class='card'>–</div>")
233
+ last_trend = gr.HTML("<div class='card'>–</div>")
234
+ last_recs = gr.HTML("<div class='card'><i>Recommendations will appear here</i></div>")
235
+
236
+ def run_and_update(image):
237
+ status, sev, trend, recs = pipeline(image)
238
+ badge_class = "status-fire" if "Wildfire detected" in status else "status-no-fire"
239
+ status_html = f"<div class='card'><span class='status-badge {badge_class}'>{status}</span></div>"
240
+ return (
241
+ status_html,
242
+ f"<div class='card'><b>{sev}</b></div>",
243
+ f"<div class='card'><b>{trend}</b></div>",
244
+ f"<div class='card'>{recs}</div>"
245
+ )
246
+
247
  run_btn.click(
248
+ fn=run_and_update,
249
  inputs=image_input,
250
  outputs=[last_status, last_severity, last_trend, last_recs]
251
  )
252
 
253
  if __name__ == '__main__':
254
+ demo.queue(api_open=True).launch()