nouamanetazi HF staff commited on
Commit
597fb2d
1 Parent(s): 740a372

big refactoring

Browse files
Files changed (7) hide show
  1. app.py +23 -517
  2. src/components.py +159 -0
  3. src/dataframes.py +68 -0
  4. src/filters.py +82 -0
  5. src/markers.py +237 -0
  6. src/text_content.py +0 -23
  7. src/utils.py +0 -10
app.py CHANGED
@@ -1,27 +1,22 @@
1
  import os
2
  import time
3
- from datetime import datetime
 
4
 
5
  import folium
6
  import pandas as pd
7
  import streamlit as st
8
  from huggingface_hub import HfApi
9
  from streamlit_folium import st_folium
10
-
11
  from src.text_content import (
12
- COLOR_MAPPING,
13
  CREDITS_TEXT,
14
- HEADERS_MAPPING,
15
- ICON_MAPPING,
16
- INTRO_TEXT_AR,
17
- INTRO_TEXT_EN,
18
- INTRO_TEXT_FR,
19
  LOGO,
20
- REVIEW_TEXT,
21
  SLOGAN,
22
  )
23
- from src.utils import add_latlng_col, add_village_names, init_map, parse_gg_sheet, is_request_in_list, marker_request, parse_json_file
24
  from src.map_utils import get_legend_macro
 
25
 
26
  TOKEN = os.environ.get("HF_TOKEN", None)
27
  VERIFIED_REQUESTS_URL = (
@@ -56,315 +51,6 @@ if auto_refresh:
56
 
57
 
58
  # Streamlit functions
59
- def display_interventions(interventions_df, selected_statuses, map_obj, intervention_fgs):
60
- """Display NGO interventions on the map"""
61
-
62
- for index, row in interventions_df.iterrows():
63
- village_status = row[interventions_df.columns[7]]
64
- is_future_intervention = (
65
- row[interventions_df.columns[5]] == "Intervention prévue dans le futur / Planned future intervention"
66
- )
67
-
68
- if pd.isna(village_status) and not is_future_intervention:
69
- village_status = "Partiellement satisfait / Partially Served"
70
-
71
- if village_status not in selected_statuses:
72
- continue
73
-
74
- if is_future_intervention:
75
- color_mk = "pink"
76
- status = "Planned ⌛"
77
- elif village_status != "Critique, Besoin d'aide en urgence / Critical, in urgent need of help":
78
- # past intervention and village not in a critical condition
79
- color_mk = "green"
80
- status = "Done ✅"
81
-
82
- else:
83
- color_mk = "darkgreen"
84
- status = "Partial 📝"
85
-
86
- intervention_type = row[interventions_df.columns[6]]
87
- org = row[interventions_df.columns[1]]
88
- contact = row[interventions_df.columns[2]]
89
- city = row[interventions_df.columns[9]]
90
- date = row[interventions_df.columns[4]]
91
- population = row[interventions_df.columns[11]]
92
- details = row[interventions_df.columns[8]]
93
- road_state = row[interventions_df.columns[12]]
94
- intervention_info = f"""
95
- <b>Date:</b> {date}<br>
96
- <b>City:</b> {city}<br>
97
- <b>Intervention Status:</b> {status}<br>
98
- <b>Village Status:</b> {village_status}<br>
99
- <b>Org:</b> {org}<br>
100
- <b>Intervention:</b> {intervention_type}<br>
101
- <b>Population:</b> {population}<br>
102
- <b>Road State:</b> {road_state}<br>
103
- <b>Details:</b> {details}<br>
104
- <b>Contact:</b> {contact}<br>
105
- """
106
-
107
- if row["latlng"] is None:
108
- continue
109
-
110
- fg = intervention_fgs[status]
111
- fg.add_child(
112
- folium.Marker(
113
- location=row["latlng"],
114
- tooltip=city,
115
- popup=folium.Popup(intervention_info, max_width=300),
116
- icon=folium.Icon(color=color_mk),
117
- )
118
- )
119
-
120
- def display_solved(solved_verified_requests, selected_statuses):
121
- # Index(['VerificationStatus', 'Verification Date', 'Help Details',
122
- # 'Further details', 'Phone Number', 'Location Details',
123
- # 'Emergency Degree', 'Location Link/GPS Coordinates', 'Status',
124
- # 'Intervenant ', 'Intervention Date', 'Any remarks',
125
- # 'Automatic Extracted Coordinates'],
126
- # dtype='object')
127
-
128
- global fg
129
- for index, row in solved_verified_requests.iterrows():
130
- if row["latlng"] is None:
131
- continue
132
- intervention_status = row[solved_verified_requests.columns[8]]
133
- is_future_intervention = (
134
- intervention_status == "Planned"
135
- )
136
-
137
- if is_future_intervention:
138
- status = "Planned ⌛"
139
- icon = folium.Icon(icon="heart", prefix="glyphicon", color="pink", icon_color="red")
140
- else:
141
- status = "Done ✅"
142
- icon = folium.Icon(icon="heart", prefix="glyphicon", color="darkgreen", icon_color="red")
143
- # if village_status not in selected_statuses:
144
- # continue # TODO: enable filters
145
- intervention_type = row[solved_verified_requests.columns[2]]
146
- details = row[solved_verified_requests.columns[3]]
147
- contact = row[solved_verified_requests.columns[4]]
148
- location = row[solved_verified_requests.columns[5]]
149
- org = row[solved_verified_requests.columns[9]]
150
- intervention_date = row[solved_verified_requests.columns[10]]
151
- remarks = row[solved_verified_requests.columns[11]]
152
- intervention_info = f"""
153
- <b>Intervention Date:</b> {intervention_date}<br>
154
- <b>Org:</b> {org}<br>
155
- <b>Intervention:</b> {intervention_type}<br>
156
- <b>Invervention Status:</b> {status}<br>
157
- <b>Details:</b> {details}<br>
158
- <b>Location:</b> {location}<br>
159
- <b>Remarks:</b> {remarks}<br>
160
- <b>Contact:</b> {contact}<br>
161
- """
162
- # golden color
163
- fg.add_child(
164
- folium.Marker(
165
- location=row["latlng"],
166
- tooltip=location,
167
- popup=folium.Popup(intervention_info, max_width=300),
168
- icon=icon
169
- )
170
- )
171
-
172
- def show_requests(filtered_df):
173
- """Display victim requests on the map"""
174
- global fg
175
- for index, row in filtered_df.iterrows():
176
- request_type = row["ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)"]
177
- displayed_request = marker_request(request_type) # TODO: the marker should depend on selected_options
178
- long_lat = row["latlng"]
179
- maps_url = f"https://maps.google.com/?q={long_lat}"
180
-
181
- douar = row[filtered_df.columns[3]]
182
- person_in_place = row[filtered_df.columns[6]]
183
- douar_info = row[filtered_df.columns[9]]
184
- source = row[filtered_df.columns[10]]
185
- # we display all requests in popup text and use the first one for the icon/color
186
- display_text = f"""
187
- <b>Request Type:</b> {request_type}<br>
188
- <b>Id:</b> {row["id"]}<br>
189
- <b>Source:</b> {source}<br>
190
- <b>Person in place:</b> {person_in_place}<br>
191
- <b>Douar:</b> {douar}<br>
192
- <b>Douar Info:</b> {douar_info}<br>
193
- <a href="{maps_url}" target="_blank" rel="noopener noreferrer"><b>Google Maps</b></a>
194
- """
195
-
196
- icon_name = ICON_MAPPING.get(request_type, "list")
197
- if long_lat is None:
198
- continue
199
-
200
- fg.add_child(
201
- folium.Marker(
202
- location=long_lat,
203
- tooltip=row[" لأي جماعة / قيادة / دوار تنتمون ؟"]
204
- if not pd.isna(row[" لأي جماعة / قيادة / دوار تنتمون ؟"])
205
- else None,
206
- popup=folium.Popup(display_text, max_width=300),
207
- icon=folium.Icon(
208
- color=COLOR_MAPPING.get(displayed_request, "beige"), icon=icon_name, prefix="glyphicon"
209
- ),
210
- )
211
- )
212
-
213
-
214
- def show_verified_requests(filtered_verified_df, emergency_fgs):
215
- """Display verified victim requests on the map"""
216
- global fg
217
-
218
- verified_color_mapping = {
219
- "Low": "beige",
220
- "Medium": "orange",
221
- "High": "red",
222
- }
223
-
224
- for index, row in filtered_verified_df.iterrows():
225
- long_lat = row["latlng"]
226
- # we display all requests in popup text and use the first one for the icon/color
227
- display_text = ""
228
- for col, val in zip(filtered_verified_df.columns, row):
229
- if col == "Help Details":
230
- request_type = row["Help Details"]
231
- marker_request(request_type) # TODO: the marker should depend on selected_options
232
- display_text += f"<b>Request Type:</b> {request_type}<br>"
233
- elif col == "Location Details":
234
- display_text += f"<b>Location:</b> {val}<br>"
235
- elif col == "Emergency Degree":
236
- display_text += f"<b>Emergency Degree:</b> {val}<br>"
237
- elif col == "Verification Date":
238
- display_text += f"<b>Verification Date:</b> {val}<br>"
239
- elif col == "id":
240
- display_text = f"<b>Id:</b> {val}<br>" + display_text
241
- elif col == "latlng":
242
- maps_url = f"https://maps.google.com/?q={val}"
243
- display_text += (
244
- f'<a href="{maps_url}" target="_blank" rel="noopener noreferrer"><b>Google Maps</b></a><br>'
245
- )
246
-
247
- # mark as solved button
248
- id_in_sheet = row["id"] + 2
249
- display_text += f"<a href='https://docs.google.com/forms/d/e/1FAIpQLSdyAcOAULumk4A1DsfrwUsGdZ-9G5xOUuD3vHdQOp3nGNAZXw/viewform?usp=pp_url&entry.1499427789={id_in_sheet}&entry.1666684596={datetime.now().strftime('%Y-%m-%d')}' target='_blank' rel='noopener noreferrer'><b>Mark as solved</b></a><br>"
250
-
251
- icon_name = ICON_MAPPING.get(request_type, "list")
252
- emergency = row.get("Emergency Degree", "Low")
253
- if long_lat is None:
254
- continue
255
- location = row["Location Details"]
256
-
257
- # Select the correct feature group
258
- fg_emergency_group = emergency_fgs[emergency]
259
-
260
- fg_emergency_group.add_child(
261
- folium.Marker(
262
- location=long_lat,
263
- tooltip=location if not pd.isna(location) else None,
264
- popup=folium.Popup(display_text, max_width=300),
265
- icon=folium.Icon(
266
- color=verified_color_mapping.get(emergency, "beige"), icon=icon_name, prefix="glyphicon"
267
- ),
268
- )
269
- )
270
-
271
-
272
- def display_google_sheet_tables(data_url):
273
- """Display the google sheet tables for requests and interventions"""
274
- st.markdown(
275
- f"""<iframe src="{data_url}" width="100%" height="600px"></iframe>""",
276
- unsafe_allow_html=True,
277
- )
278
-
279
-
280
- def display_dataframe(df, drop_cols, data_url, search_id=True, status=False, for_help_requests=False, show_link=True):
281
- """Display the dataframe in a table"""
282
- col_1, col_2 = st.columns([1, 1])
283
-
284
- # has df's first row
285
- df_hash = hash(df.iloc[0].to_string())
286
-
287
- with col_1:
288
- query = st.text_input("🔍 Search for information / بحث عن المعلومات", key=f"query_{df_hash}")
289
- with col_2:
290
- if search_id:
291
- id_number = st.number_input(
292
- "🔍 Search for an id / بحث عن رقم",
293
- min_value=0,
294
- max_value=len(filtered_df),
295
- value=0,
296
- step=1,
297
- key=f"id_{df_hash}",
298
- )
299
- if status:
300
- selected_status = st.selectbox(
301
- "🗓️ Status / حالة", ["all / الكل", "Done / تم", "Planned / مخطط لها"], key=f"status_{df_hash}"
302
- )
303
-
304
- if query:
305
- # Filtering the dataframe based on the query
306
- mask = df.apply(lambda row: row.astype(str).str.contains(query.lower(), case=False).any(), axis=1)
307
- display_df = df[mask]
308
- else:
309
- display_df = df
310
-
311
- if search_id and id_number:
312
- display_df = display_df[display_df["id"] == id_number]
313
-
314
- display_df = display_df.drop(drop_cols, axis=1)
315
-
316
- if status:
317
- target = "Pouvez-vous nous préciser si vous êtes déjà intervenus ou si vous prévoyez de le faire | Tell us if you already made the intervention, or if you're planning to do it"
318
- if selected_status == "Done / تم":
319
- display_df = display_df[display_df[target] == "Intervention déjà passée / Past intevention"]
320
-
321
- elif selected_status == "Planned / مخطط لها":
322
- display_df = display_df[display_df[target] != "Intervention déjà passée / Past intevention"]
323
-
324
- st.dataframe(display_df, height=500)
325
- # Original link to the Google Sheet
326
- if show_link:
327
- st.markdown(
328
- f"To view the full Google Sheet for advanced filtering go to: {data_url} **لعرض الورقة كاملة، اذهب إلى**"
329
- )
330
- # if we want to check hidden contact information
331
- if for_help_requests:
332
- st.markdown(
333
- "We are hiding contact information to protect the privacy of the victims. If you are an NGO and want to contact the victims, please contact us at [email protected]",
334
- )
335
- st.markdown(
336
- """
337
- <div style="text-align: left;">
338
- <a href="mailto:[email protected]">[email protected]</a> نحن نخفي معلومات الاتصال لحماية خصوصية الضحايا. إذا كنت جمعية وتريد الاتصال بالضحايا، يرجى الاتصال بنا على
339
- </div>
340
- """,
341
- unsafe_allow_html=True,
342
- )
343
-
344
-
345
- def id_review_submission():
346
- """Id review submission form"""
347
- # collapse the text
348
- with st.expander("🔍 Review of requests | مراجعة طلب مساعدة"):
349
- st.markdown(REVIEW_TEXT)
350
-
351
- id_to_review = st.number_input("Enter id / أدخل الرقم", min_value=0, max_value=len(df), value=0, step=1)
352
- reason_for_review = st.text_area("Explain why / أدخل سبب المراجعة")
353
- if st.button("Submit / أرسل"):
354
- if reason_for_review == "":
355
- st.error("Please enter a reason / الرجاء إدخال سبب")
356
- else:
357
- filename = f"review_id_{id_to_review}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt"
358
- with open(filename, "w") as f:
359
- f.write(f"id: {id_to_review}, explanation: {reason_for_review}\n")
360
- api.upload_file(
361
- path_or_fileobj=filename,
362
- path_in_repo=filename,
363
- repo_id="nt3awnou/review_requests",
364
- repo_type="dataset",
365
- )
366
- st.success("Submitted at https://huggingface.co/datasets/nt3awnou/review_requests/ تم الإرسال")
367
-
368
 
369
  # Logo and Title
370
  st.markdown(LOGO, unsafe_allow_html=True)
@@ -375,36 +61,8 @@ m, emergency_fgs, intervention_fgs = init_map()
375
  fg = folium.FeatureGroup(name="Markers")
376
 
377
  # Selection of requests
378
- options = [
379
- "إغاثة",
380
- "مساعدة طبية",
381
- "مأوى",
382
- "طعام وماء",
383
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)",
384
- ]
385
- selected_options = []
386
-
387
- col1, col2 = st.columns([1, 1])
388
- with col1:
389
- show_unverified = st.checkbox(
390
- "Display unverified requests / عرض الطلبات غير المؤكدة / Afficher les demandes non vérifiées",
391
- value=False,
392
- )
393
- with col2:
394
- show_interventions = st.checkbox(
395
- "Display Interventions | Afficher les interventions | عرض عمليات المساعدة",
396
- value=True,
397
- )
398
-
399
- st.markdown("👉 **Choose request type | Choissisez le type de demande | اختر نوع الطلب**")
400
- col1, col2, col3, col4, col5 = st.columns([2, 4, 2, 3, 2])
401
- cols = [col1, col2, col3, col4, col5]
402
-
403
- for i, option in enumerate(options):
404
- checked = cols[i].checkbox(HEADERS_MAPPING[option], value=True)
405
- if checked:
406
- selected_options.append(option)
407
 
 
408
  # Load data and initialize map with plugins
409
  df = parse_gg_sheet(REQUESTS_URL)
410
  if show_unverified:
@@ -436,51 +94,23 @@ filtered_verified_df = verified_df[
436
 
437
 
438
  # Selection of interventions
439
-
440
- st.markdown(
441
- "👉 **State of villages visited by NGOs| Etat de villages visités par les ONGs | وضعية القرى التي زارتها الجمعيات**",
442
- unsafe_allow_html=True,
443
- )
444
- col_1, col_2, col_3 = st.columns([1, 1, 1])
445
- critical_villages = col_1.checkbox(
446
- "🚨 Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة",
447
- value=True,
448
- )
449
- partially_satisfied_villages = col_2.checkbox(
450
- "⚠️ Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات",
451
- value=True,
452
- )
453
- fully_satisfied_villages = col_3.checkbox(
454
- "✅ Fully served / تمت المساعدة بشكل كامل",
455
- value=True,
456
- )
457
- selected_village_types = []
458
- if critical_villages:
459
- selected_village_types.append("🚨 Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة")
460
-
461
- if partially_satisfied_villages:
462
- selected_village_types.append("⚠️ Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات")
463
-
464
- if fully_satisfied_villages:
465
- selected_village_types.append("✅ Fully served / تمت المساعدة بشكل كامل")
466
-
467
- status_mapping = {
468
- "🚨 Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة": "Critique, Besoin d'aide en urgence / Critical, in urgent need of help",
469
- "⚠️ Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات": "Partiellement satisfait / Partially Served",
470
- "✅ Fully served / تمت المساعدة بشكل كامل": "Entièrement satisfait / Fully served",
471
- }
472
- selected_statuses = [status_mapping[status] for status in selected_village_types]
473
-
474
  if show_interventions:
475
- display_solved(solved_verified_requests, selected_statuses)
476
  display_interventions(interventions_df, selected_statuses, m, intervention_fgs)
477
 
478
-
479
- # Show requests
480
  if show_unverified:
481
- show_requests(filtered_df)
482
 
483
- # Show verified requests
484
  show_verified_requests(verified_df, emergency_fgs)
485
 
486
  # Add legend
@@ -495,83 +125,10 @@ m.get_root().add_child(legend_macro)
495
  st_folium(m, use_container_width=True, returned_objects=[], feature_group_to_add=fg, key="map")
496
 
497
  # Embed code
498
- with st.expander("💻 For Developers only, embed code for the map | للمطورين فقط، يمكنك نسخ كود الخريطة"):
499
- st.code(
500
- """
501
- <iframe id="nt3awnou-map"
502
- src="https://nt3awnou-embed-rescue-map.hf.space/?embed=true" width="1200" height="720"
503
- frameborder="0"
504
- width="850"
505
- height="450"
506
- title="Nt3awno Rescue Map">
507
- </iframe>
508
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/js/iframeResizer.min.js"></script>
509
- <script>
510
- iFrameResize({}, "#nt3awnou-map");
511
- </script>
512
- """,
513
- language="html",
514
- )
515
-
516
-
517
- tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
518
-
519
-
520
- with tab_en:
521
- st.markdown(INTRO_TEXT_EN, unsafe_allow_html=True)
522
- col1, col2, col3 = st.columns([1, 1, 1])
523
- with col1:
524
- st.metric(
525
- "# Number of help requests",
526
- len_requests,
527
- )
528
- with col2:
529
- st.metric(
530
- "# Number of interventions",
531
- len_interventions + len_solved_verified_requests,
532
- )
533
- with col3:
534
- st.metric(
535
- "# Number of solved requests",
536
- len_solved_verified_requests,
537
- )
538
- with tab_ar:
539
- st.markdown(INTRO_TEXT_AR, unsafe_allow_html=True)
540
- col1, col2, col3 = st.columns([1, 1, 1])
541
- with col1:
542
- st.metric(
543
- "# عدد طلبات المساعدة",
544
- len_requests,
545
- )
546
- with col2:
547
- st.metric(
548
- "# عدد التدخلات",
549
- len_interventions + len_solved_verified_requests,
550
- )
551
- with col3:
552
- st.metric(
553
- "# عدد الطلبات المستجاب لها",
554
- len_solved_verified_requests,
555
- )
556
- with tab_fr:
557
- st.markdown(INTRO_TEXT_FR, unsafe_allow_html=True)
558
- col1, col2, col3 = st.columns([1, 1, 1])
559
- with col1:
560
- st.metric(
561
- "# Nombre de demandes d'aide",
562
- len_requests,
563
- )
564
- with col2:
565
- st.metric(
566
- "# Nombre d'interventions",
567
- len_interventions + len_solved_verified_requests,
568
- )
569
- with col3:
570
- st.metric(
571
- "# Nombre de demandes résolues",
572
- len_solved_verified_requests,
573
- )
574
 
 
 
575
 
576
  # Verified Requests table
577
  st.divider()
@@ -618,63 +175,12 @@ display_dataframe(
618
 
619
  # Submit an id for review
620
  st.divider()
621
- id_review_submission()
622
 
623
 
624
  # Donations can be made to the gouvernmental fund under the name
625
  st.divider()
626
- st.subheader("📝 **Donations / التبرعات / Dons**")
627
- tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
628
- with tab_en:
629
- st.markdown(
630
- """
631
- <div style="text-align: center;">
632
- <h4>The official bank account dedicated to tackle the consequences of the earthquake is:</h4>
633
- <b>Account number:</b>
634
- <h2>126</h2>
635
- <b>RIB:</b> 001-810-0078000201106203-18
636
- <br>
637
- <b>For the money transfers coming from outside Morocco</b>
638
- <br>
639
- <b>IBAN:</b> MA64001810007800020110620318
640
- <br>
641
- """,
642
- unsafe_allow_html=True,
643
- )
644
- with tab_ar:
645
- st.markdown(
646
- """
647
- <div style="text-align: center;">
648
- <h4>الحساب البنكي الرسمي المخصص لمواجهة عواقب الزلزال</h4>
649
- <b>رقم الحساب</b>
650
- <h2>126</h2>
651
- <b>RIB:</b> 001-810-0078000201106203-18
652
- <br>
653
- <b>للتحويلات القادمة من خارج المغرب</b>
654
- <br>
655
- <b>IBAN:</b> MA64001810007800020110620318
656
- <br>
657
- </div>
658
- """,
659
- unsafe_allow_html=True,
660
- )
661
- with tab_fr:
662
- st.markdown(
663
- """
664
- <div style="text-align: center;">
665
- <h4>Le compte bancaire officiel dédié à la lutte contre les conséquences du séisme est le suivant:</h4>
666
- <b>Numéro de compte:</b>
667
- <h2>126</h2>
668
- <b>RIB:</b> 001-810-0078000201106203-18
669
- <br>
670
- <b>Pour les transferts d'argent en provenance de l'étranger</b>
671
- <br>
672
- <b>IBAN:</b> MA64001810007800020110620318
673
- <br>
674
- """,
675
- unsafe_allow_html=True,
676
- )
677
-
678
 
679
  # Credits
680
  st.markdown(
 
1
  import os
2
  import time
3
+ from src.markers import display_interventions, display_solved, show_requests, show_verified_requests
4
+ from src.filters import show_requests_filters, show_interventions_filters
5
 
6
  import folium
7
  import pandas as pd
8
  import streamlit as st
9
  from huggingface_hub import HfApi
10
  from streamlit_folium import st_folium
11
+ from src.components import show_dataframes_metrics, show_embed_code, id_review_submission, show_donations
12
  from src.text_content import (
 
13
  CREDITS_TEXT,
 
 
 
 
 
14
  LOGO,
 
15
  SLOGAN,
16
  )
17
+ from src.utils import add_latlng_col, init_map, parse_gg_sheet, is_request_in_list, parse_json_file
18
  from src.map_utils import get_legend_macro
19
+ from src.dataframes import display_dataframe
20
 
21
  TOKEN = os.environ.get("HF_TOKEN", None)
22
  VERIFIED_REQUESTS_URL = (
 
51
 
52
 
53
  # Streamlit functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  # Logo and Title
56
  st.markdown(LOGO, unsafe_allow_html=True)
 
61
  fg = folium.FeatureGroup(name="Markers")
62
 
63
  # Selection of requests
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ selected_options, options, show_unverified, show_interventions = show_requests_filters()
66
  # Load data and initialize map with plugins
67
  df = parse_gg_sheet(REQUESTS_URL)
68
  if show_unverified:
 
94
 
95
 
96
  # Selection of interventions
97
+ (
98
+ selected_statuses,
99
+ critical_villages,
100
+ partially_satisfied_villages,
101
+ fully_satisfied_villages,
102
+ ) = show_interventions_filters()
103
+
104
+ # Add interventions markers to map
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  if show_interventions:
106
+ display_solved(solved_verified_requests, selected_statuses, fg)
107
  display_interventions(interventions_df, selected_statuses, m, intervention_fgs)
108
 
109
+ # Add requests markers to map
 
110
  if show_unverified:
111
+ show_requests(filtered_df, fg)
112
 
113
+ # Add verified requests markers to map
114
  show_verified_requests(verified_df, emergency_fgs)
115
 
116
  # Add legend
 
125
  st_folium(m, use_container_width=True, returned_objects=[], feature_group_to_add=fg, key="map")
126
 
127
  # Embed code
128
+ show_embed_code()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
+ # Show metrics
131
+ show_dataframes_metrics(len_requests, len_interventions, len_solved_verified_requests)
132
 
133
  # Verified Requests table
134
  st.divider()
 
175
 
176
  # Submit an id for review
177
  st.divider()
178
+ id_review_submission(api)
179
 
180
 
181
  # Donations can be made to the gouvernmental fund under the name
182
  st.divider()
183
+ show_donations()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
185
  # Credits
186
  st.markdown(
src/components.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from datetime import datetime
3
+ from huggingface_hub import HfApi
4
+ from src.text_content import REVIEW_TEXT, INTRO_TEXT_AR, INTRO_TEXT_EN, INTRO_TEXT_FR
5
+
6
+
7
+ def id_review_submission(api: HfApi):
8
+ """Id review submission form"""
9
+ # collapse the text
10
+ with st.expander("🔍 Review of requests | مراجعة طلب مساعدة"):
11
+ st.markdown(REVIEW_TEXT)
12
+
13
+ id_to_review = st.number_input("Enter id / أدخل الرقم", min_value=0, value=0, step=1)
14
+ reason_for_review = st.text_area("Explain why / أدخل سبب المراجعة")
15
+ if st.button("Submit / أرسل"):
16
+ if reason_for_review == "":
17
+ st.error("Please enter a reason / الرجاء إدخال سبب")
18
+ else:
19
+ filename = f"review_id_{id_to_review}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt"
20
+ with open(filename, "w") as f:
21
+ f.write(f"id: {id_to_review}, explanation: {reason_for_review}\n")
22
+ api.upload_file(
23
+ path_or_fileobj=filename,
24
+ path_in_repo=filename,
25
+ repo_id="nt3awnou/review_requests",
26
+ repo_type="dataset",
27
+ )
28
+ st.success("Submitted at https://huggingface.co/datasets/nt3awnou/review_requests/ تم الإرسال")
29
+
30
+
31
+ def show_embed_code():
32
+ with st.expander("💻 For Developers only, embed code for the map | للمطورين فقط، يمكنك نسخ كود الخريطة"):
33
+ st.code(
34
+ """
35
+ <iframe id="nt3awnou-map"
36
+ src="https://nt3awnou-embed-rescue-map.hf.space/?embed=true" width="1200" height="720"
37
+ frameborder="0"
38
+ width="850"
39
+ height="450"
40
+ title="Nt3awno Rescue Map">
41
+ </iframe>
42
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/js/iframeResizer.min.js"></script>
43
+ <script>
44
+ iFrameResize({}, "#nt3awnou-map");
45
+ </script>
46
+ """,
47
+ language="html",
48
+ )
49
+
50
+
51
+ def show_dataframes_metrics(len_requests, len_interventions, len_solved_verified_requests):
52
+ tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
53
+ with tab_en:
54
+ st.markdown(INTRO_TEXT_EN, unsafe_allow_html=True)
55
+ col1, col2, col3 = st.columns([1, 1, 1])
56
+ with col1:
57
+ st.metric(
58
+ "# Number of help requests",
59
+ len_requests,
60
+ )
61
+ with col2:
62
+ st.metric(
63
+ "# Number of interventions",
64
+ len_interventions + len_solved_verified_requests,
65
+ )
66
+ with col3:
67
+ st.metric(
68
+ "# Number of solved requests",
69
+ len_solved_verified_requests,
70
+ )
71
+ with tab_ar:
72
+ st.markdown(INTRO_TEXT_AR, unsafe_allow_html=True)
73
+ col1, col2, col3 = st.columns([1, 1, 1])
74
+ with col1:
75
+ st.metric(
76
+ "# عدد طلبات المساعدة",
77
+ len_requests,
78
+ )
79
+ with col2:
80
+ st.metric(
81
+ "# عدد التدخلات",
82
+ len_interventions + len_solved_verified_requests,
83
+ )
84
+ with col3:
85
+ st.metric(
86
+ "# عدد الطلبات المستجاب لها",
87
+ len_solved_verified_requests,
88
+ )
89
+ with tab_fr:
90
+ st.markdown(INTRO_TEXT_FR, unsafe_allow_html=True)
91
+ col1, col2, col3 = st.columns([1, 1, 1])
92
+ with col1:
93
+ st.metric(
94
+ "# Nombre de demandes d'aide",
95
+ len_requests,
96
+ )
97
+ with col2:
98
+ st.metric(
99
+ "# Nombre d'interventions",
100
+ len_interventions + len_solved_verified_requests,
101
+ )
102
+ with col3:
103
+ st.metric(
104
+ "# Nombre de demandes résolues",
105
+ len_solved_verified_requests,
106
+ )
107
+
108
+ def show_donations():
109
+ st.subheader("📝 **Donations / التبرعات / Dons**")
110
+ tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
111
+ with tab_en:
112
+ st.markdown(
113
+ """
114
+ <div style="text-align: center;">
115
+ <h4>The official bank account dedicated to tackle the consequences of the earthquake is:</h4>
116
+ <b>Account number:</b>
117
+ <h2>126</h2>
118
+ <b>RIB:</b> 001-810-0078000201106203-18
119
+ <br>
120
+ <b>For the money transfers coming from outside Morocco</b>
121
+ <br>
122
+ <b>IBAN:</b> MA64001810007800020110620318
123
+ <br>
124
+ """,
125
+ unsafe_allow_html=True,
126
+ )
127
+ with tab_ar:
128
+ st.markdown(
129
+ """
130
+ <div style="text-align: center;">
131
+ <h4>الحساب البنكي الرسمي المخصص لمواجهة عواقب الزلزال</h4>
132
+ <b>رقم الحساب</b>
133
+ <h2>126</h2>
134
+ <b>RIB:</b> 001-810-0078000201106203-18
135
+ <br>
136
+ <b>للتحويلات القادمة من خارج المغرب</b>
137
+ <br>
138
+ <b>IBAN:</b> MA64001810007800020110620318
139
+ <br>
140
+ </div>
141
+ """,
142
+ unsafe_allow_html=True,
143
+ )
144
+ with tab_fr:
145
+ st.markdown(
146
+ """
147
+ <div style="text-align: center;">
148
+ <h4>Le compte bancaire officiel dédié à la lutte contre les conséquences du séisme est le suivant:</h4>
149
+ <b>Numéro de compte:</b>
150
+ <h2>126</h2>
151
+ <b>RIB:</b> 001-810-0078000201106203-18
152
+ <br>
153
+ <b>Pour les transferts d'argent en provenance de l'étranger</b>
154
+ <br>
155
+ <b>IBAN:</b> MA64001810007800020110620318
156
+ <br>
157
+ """,
158
+ unsafe_allow_html=True,
159
+ )
src/dataframes.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import streamlit as st
3
+
4
+
5
+ def display_dataframe(df, drop_cols, data_url, search_id=True, status=False, for_help_requests=False, show_link=True):
6
+ """Display the dataframe in a table"""
7
+ col_1, col_2 = st.columns([1, 1])
8
+
9
+ # has df's first row
10
+ df_hash = hash(df.iloc[0].to_string())
11
+
12
+ with col_1:
13
+ query = st.text_input("🔍 Search for information / بحث عن المعلومات", key=f"query_{df_hash}")
14
+ with col_2:
15
+ if search_id:
16
+ id_number = st.number_input(
17
+ "🔍 Search for an id / بحث عن رقم",
18
+ min_value=0,
19
+ # max_value=len(df),
20
+ value=0,
21
+ step=1,
22
+ key=f"id_{df_hash}",
23
+ )
24
+ if status:
25
+ selected_status = st.selectbox(
26
+ "🗓️ Status / حالة", ["all / الكل", "Done / تم", "Planned / مخطط لها"], key=f"status_{df_hash}"
27
+ )
28
+
29
+ if query:
30
+ # Filtering the dataframe based on the query
31
+ mask = df.apply(lambda row: row.astype(str).str.contains(query.lower(), case=False).any(), axis=1)
32
+ display_df = df[mask]
33
+ else:
34
+ display_df = df
35
+
36
+ if search_id and id_number:
37
+ display_df = display_df[display_df["id"] == id_number]
38
+
39
+ display_df = display_df.drop(drop_cols, axis=1)
40
+
41
+ if status:
42
+ target = "Pouvez-vous nous préciser si vous êtes déjà intervenus ou si vous prévoyez de le faire | Tell us if you already made the intervention, or if you're planning to do it"
43
+ if selected_status == "Done / تم":
44
+ display_df = display_df[display_df[target] == "Intervention déjà passée / Past intevention"]
45
+
46
+ elif selected_status == "Planned / مخطط لها":
47
+ display_df = display_df[display_df[target] != "Intervention déjà passée / Past intevention"]
48
+
49
+ st.dataframe(display_df, height=500)
50
+ # Original link to the Google Sheet
51
+ if show_link:
52
+ st.markdown(
53
+ f"To view the full Google Sheet for advanced filtering go to: {data_url} **لعرض الورقة كاملة، اذهب إلى**"
54
+ )
55
+ # if we want to check hidden contact information
56
+ if for_help_requests:
57
+ st.markdown(
58
+ "We are hiding contact information to protect the privacy of the victims. If you are an NGO and want to contact the victims, please contact us at [email protected]",
59
+ )
60
+ st.markdown(
61
+ """
62
+ <div style="text-align: left;">
63
+ <a href="mailto:[email protected]">[email protected]</a> نحن نخفي معلومات الاتصال لحماية خصوصية الضحايا. إذا كنت جمعية وتريد الاتصال بالضحايا، يرجى الاتصال بنا على
64
+ </div>
65
+ """,
66
+ unsafe_allow_html=True,
67
+ )
68
+
src/filters.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import streamlit as st
3
+
4
+
5
+ HEADERS_MAPPING = {
6
+ "إغاثة" : "Rescue | إغاثة | Secours",
7
+ "مساعدة طبية": "Medical Assistance | مساعدة طبية | Assistance médicale",
8
+ "مأوى": "Shelter | مأوى | Abri",
9
+ "طعام وماء": "Food & Water | طعام وماء | Nourriture et eau",
10
+ "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Danger | مخاطر | Danger",
11
+ }
12
+
13
+
14
+ def show_requests_filters():
15
+ options = [
16
+ "إغاثة",
17
+ "مساعدة طبية",
18
+ "مأوى",
19
+ "طعام وماء",
20
+ "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)",
21
+ ]
22
+ selected_options = []
23
+
24
+ col1, col2 = st.columns([1, 1])
25
+ with col1:
26
+ show_unverified = st.checkbox(
27
+ "Display unverified requests / عرض الطلبات غير المؤكدة / Afficher les demandes non vérifiées",
28
+ value=False,
29
+ )
30
+ with col2:
31
+ show_interventions = st.checkbox(
32
+ "Display Interventions | Afficher les interventions | عرض عمليات المساعدة",
33
+ value=True,
34
+ )
35
+
36
+ st.markdown("👉 **Choose request type | Choissisez le type de demande | اختر نوع الطلب**")
37
+ col1, col2, col3, col4, col5 = st.columns([2, 4, 2, 3, 2])
38
+ cols = [col1, col2, col3, col4, col5]
39
+
40
+ for i, option in enumerate(options):
41
+ checked = cols[i].checkbox(HEADERS_MAPPING[option], value=True)
42
+ if checked:
43
+ selected_options.append(option)
44
+
45
+ return selected_options, options, show_unverified, show_interventions
46
+
47
+ def show_interventions_filters():
48
+ st.markdown(
49
+ "👉 **State of villages visited by NGOs| Etat de villages visités par les ONGs | وضعية القرى التي زارتها الجمعيات**",
50
+ unsafe_allow_html=True,
51
+ )
52
+ col_1, col_2, col_3 = st.columns([1, 1, 1])
53
+ critical_villages = col_1.checkbox(
54
+ "🚨 Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة",
55
+ value=True,
56
+ )
57
+ partially_satisfied_villages = col_2.checkbox(
58
+ "⚠️ Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات",
59
+ value=True,
60
+ )
61
+ fully_satisfied_villages = col_3.checkbox(
62
+ "✅ Fully served / تمت المساعدة بشكل كامل",
63
+ value=True,
64
+ )
65
+ selected_village_types = []
66
+ if critical_villages:
67
+ selected_village_types.append("🚨 Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة")
68
+
69
+ if partially_satisfied_villages:
70
+ selected_village_types.append("⚠️ Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات")
71
+
72
+ if fully_satisfied_villages:
73
+ selected_village_types.append("✅ Fully served / تمت المساعدة بشكل كامل")
74
+
75
+ status_mapping = {
76
+ "🚨 Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة": "Critique, Besoin d'aide en urgence / Critical, in urgent need of help",
77
+ "⚠️ Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات": "Partiellement satisfait / Partially Served",
78
+ "✅ Fully served / تمت المساعدة بشكل كامل": "Entièrement satisfait / Fully served",
79
+ }
80
+ selected_statuses = [status_mapping[status] for status in selected_village_types]
81
+
82
+ return selected_statuses, critical_villages, partially_satisfied_villages, fully_satisfied_villages
src/markers.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+ import folium
3
+ import pandas as pd
4
+
5
+
6
+ COLOR_MAPPING = {
7
+ "إغاثة": "red",
8
+ "مساعدة طبية": "orange",
9
+ "مأوى": "beige",
10
+ "طعام وماء": "blue",
11
+ "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "gray",
12
+ }
13
+
14
+ ICON_MAPPING = {
15
+ "إغاثة": "bell", # life ring icon for rescue
16
+ "مساعدة طبية": "heart", # medical kit for medical assistance
17
+ "مأوى": "home", # home icon for shelter
18
+ "طعام وماء": "cutlery", # cutlery (fork and knife) for food & water
19
+ "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Warning" # warning triangle for dangers
20
+ }
21
+
22
+ def marker_request(request):
23
+ # in case of multiple requests we use the first one for the marker's icon
24
+ # requests are already sorted by priority from the form
25
+ try:
26
+ displayed_request = request.split(',')[0]
27
+ except:
28
+ displayed_request = request
29
+ return displayed_request
30
+
31
+
32
+ ## Interventions
33
+ def display_interventions(interventions_df, selected_statuses, map_obj, intervention_fgs):
34
+ """Display NGO interventions on the map"""
35
+
36
+ for index, row in interventions_df.iterrows():
37
+ village_status = row[interventions_df.columns[7]]
38
+ is_future_intervention = (
39
+ row[interventions_df.columns[5]] == "Intervention prévue dans le futur / Planned future intervention"
40
+ )
41
+
42
+ if pd.isna(village_status) and not is_future_intervention:
43
+ village_status = "Partiellement satisfait / Partially Served"
44
+
45
+ if village_status not in selected_statuses:
46
+ continue
47
+
48
+ if is_future_intervention:
49
+ color_mk = "pink"
50
+ status = "Planned ⌛"
51
+ elif village_status != "Critique, Besoin d'aide en urgence / Critical, in urgent need of help":
52
+ # past intervention and village not in a critical condition
53
+ color_mk = "green"
54
+ status = "Done ✅"
55
+
56
+ else:
57
+ color_mk = "darkgreen"
58
+ status = "Partial 📝"
59
+
60
+ intervention_type = row[interventions_df.columns[6]]
61
+ org = row[interventions_df.columns[1]]
62
+ contact = row[interventions_df.columns[2]]
63
+ city = row[interventions_df.columns[9]]
64
+ date = row[interventions_df.columns[4]]
65
+ population = row[interventions_df.columns[11]]
66
+ details = row[interventions_df.columns[8]]
67
+ road_state = row[interventions_df.columns[12]]
68
+ intervention_info = f"""
69
+ <b>Date:</b> {date}<br>
70
+ <b>City:</b> {city}<br>
71
+ <b>Intervention Status:</b> {status}<br>
72
+ <b>Village Status:</b> {village_status}<br>
73
+ <b>Org:</b> {org}<br>
74
+ <b>Intervention:</b> {intervention_type}<br>
75
+ <b>Population:</b> {population}<br>
76
+ <b>Road State:</b> {road_state}<br>
77
+ <b>Details:</b> {details}<br>
78
+ <b>Contact:</b> {contact}<br>
79
+ """
80
+
81
+ if row["latlng"] is None:
82
+ continue
83
+
84
+ fg = intervention_fgs[status]
85
+ fg.add_child(
86
+ folium.Marker(
87
+ location=row["latlng"],
88
+ tooltip=city,
89
+ popup=folium.Popup(intervention_info, max_width=300),
90
+ icon=folium.Icon(color=color_mk),
91
+ )
92
+ )
93
+
94
+
95
+
96
+ def display_solved(solved_verified_requests, selected_statuses, feature_group):
97
+ for index, row in solved_verified_requests.iterrows():
98
+ if row["latlng"] is None:
99
+ continue
100
+ intervention_status = row[solved_verified_requests.columns[8]]
101
+ is_future_intervention = (
102
+ intervention_status == "Planned"
103
+ )
104
+
105
+ if is_future_intervention:
106
+ status = "Planned ⌛"
107
+ icon = folium.Icon(icon="heart", prefix="glyphicon", color="pink", icon_color="red")
108
+ else:
109
+ status = "Done ✅"
110
+ icon = folium.Icon(icon="heart", prefix="glyphicon", color="darkgreen", icon_color="red")
111
+ # if village_status not in selected_statuses:
112
+ # continue # TODO: enable filters
113
+ intervention_type = row[solved_verified_requests.columns[2]]
114
+ details = row[solved_verified_requests.columns[3]]
115
+ contact = row[solved_verified_requests.columns[4]]
116
+ location = row[solved_verified_requests.columns[5]]
117
+ org = row[solved_verified_requests.columns[9]]
118
+ intervention_date = row[solved_verified_requests.columns[10]]
119
+ remarks = row[solved_verified_requests.columns[11]]
120
+ intervention_info = f"""
121
+ <b>Intervention Date:</b> {intervention_date}<br>
122
+ <b>Org:</b> {org}<br>
123
+ <b>Intervention:</b> {intervention_type}<br>
124
+ <b>Invervention Status:</b> {status}<br>
125
+ <b>Details:</b> {details}<br>
126
+ <b>Location:</b> {location}<br>
127
+ <b>Remarks:</b> {remarks}<br>
128
+ <b>Contact:</b> {contact}<br>
129
+ """
130
+ # golden color
131
+ feature_group.add_child(
132
+ folium.Marker(
133
+ location=row["latlng"],
134
+ tooltip=location,
135
+ popup=folium.Popup(intervention_info, max_width=300),
136
+ icon=icon
137
+ )
138
+ )
139
+
140
+
141
+ ## Requests
142
+ def show_requests(filtered_df, feature_group):
143
+ """Display victim requests on the map"""
144
+ for index, row in filtered_df.iterrows():
145
+ request_type = row["ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)"]
146
+ displayed_request = marker_request(request_type) # TODO: the marker should depend on selected_options
147
+ long_lat = row["latlng"]
148
+ maps_url = f"https://maps.google.com/?q={long_lat}"
149
+
150
+ douar = row[filtered_df.columns[3]]
151
+ person_in_place = row[filtered_df.columns[6]]
152
+ douar_info = row[filtered_df.columns[9]]
153
+ source = row[filtered_df.columns[10]]
154
+ # we display all requests in popup text and use the first one for the icon/color
155
+ display_text = f"""
156
+ <b>Request Type:</b> {request_type}<br>
157
+ <b>Id:</b> {row["id"]}<br>
158
+ <b>Source:</b> {source}<br>
159
+ <b>Person in place:</b> {person_in_place}<br>
160
+ <b>Douar:</b> {douar}<br>
161
+ <b>Douar Info:</b> {douar_info}<br>
162
+ <a href="{maps_url}" target="_blank" rel="noopener noreferrer"><b>Google Maps</b></a>
163
+ """
164
+
165
+ icon_name = ICON_MAPPING.get(request_type, "list")
166
+ if long_lat is None:
167
+ continue
168
+
169
+ feature_group.add_child(
170
+ folium.Marker(
171
+ location=long_lat,
172
+ tooltip=row[" لأي جماعة / قيادة / دوار تنتمون ؟"]
173
+ if not pd.isna(row[" لأي جماعة / قيادة / دوار تنتمون ؟"])
174
+ else None,
175
+ popup=folium.Popup(display_text, max_width=300),
176
+ icon=folium.Icon(
177
+ color=COLOR_MAPPING.get(displayed_request, "beige"), icon=icon_name, prefix="glyphicon"
178
+ ),
179
+ )
180
+ )
181
+
182
+ def show_verified_requests(filtered_verified_df, emergency_fgs):
183
+ """Display verified victim requests on the map"""
184
+ global fg
185
+
186
+ verified_color_mapping = {
187
+ "Low": "beige",
188
+ "Medium": "orange",
189
+ "High": "red",
190
+ }
191
+
192
+ for index, row in filtered_verified_df.iterrows():
193
+ long_lat = row["latlng"]
194
+ # we display all requests in popup text and use the first one for the icon/color
195
+ display_text = ""
196
+ for col, val in zip(filtered_verified_df.columns, row):
197
+ if col == "Help Details":
198
+ request_type = row["Help Details"]
199
+ marker_request(request_type) # TODO: the marker should depend on selected_options
200
+ display_text += f"<b>Request Type:</b> {request_type}<br>"
201
+ elif col == "Location Details":
202
+ display_text += f"<b>Location:</b> {val}<br>"
203
+ elif col == "Emergency Degree":
204
+ display_text += f"<b>Emergency Degree:</b> {val}<br>"
205
+ elif col == "Verification Date":
206
+ display_text += f"<b>Verification Date:</b> {val}<br>"
207
+ elif col == "id":
208
+ display_text = f"<b>Id:</b> {val}<br>" + display_text
209
+ elif col == "latlng":
210
+ maps_url = f"https://maps.google.com/?q={val}"
211
+ display_text += (
212
+ f'<a href="{maps_url}" target="_blank" rel="noopener noreferrer"><b>Google Maps</b></a><br>'
213
+ )
214
+
215
+ # mark as solved button
216
+ id_in_sheet = row["id"] + 2
217
+ display_text += f"<a href='https://docs.google.com/forms/d/e/1FAIpQLSdyAcOAULumk4A1DsfrwUsGdZ-9G5xOUuD3vHdQOp3nGNAZXw/viewform?usp=pp_url&entry.1499427789={id_in_sheet}&entry.1666684596={datetime.now().strftime('%Y-%m-%d')}' target='_blank' rel='noopener noreferrer'><b>Mark as solved</b></a><br>"
218
+
219
+ icon_name = ICON_MAPPING.get(request_type, "list")
220
+ emergency = row.get("Emergency Degree", "Low")
221
+ if long_lat is None:
222
+ continue
223
+ location = row["Location Details"]
224
+
225
+ # Select the correct feature group
226
+ fg_emergency_group = emergency_fgs[emergency]
227
+
228
+ fg_emergency_group.add_child(
229
+ folium.Marker(
230
+ location=long_lat,
231
+ tooltip=location if not pd.isna(location) else None,
232
+ popup=folium.Popup(display_text, max_width=300),
233
+ icon=folium.Icon(
234
+ color=verified_color_mapping.get(emergency, "beige"), icon=icon_name, prefix="glyphicon"
235
+ ),
236
+ )
237
+ )
src/text_content.py CHANGED
@@ -48,29 +48,6 @@ SLOGAN = """
48
  </div>
49
  """
50
 
51
- HEADERS_MAPPING = {
52
- "إغاثة" : "Rescue | إغاثة | Secours",
53
- "مساعدة طبية": "Medical Assistance | مساعدة طبية | Assistance médicale",
54
- "مأوى": "Shelter | مأوى | Abri",
55
- "طعام وماء": "Food & Water | طعام وماء | Nourriture et eau",
56
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Danger | مخاطر | Danger",
57
- }
58
-
59
- COLOR_MAPPING = {
60
- "إغاثة": "red",
61
- "مساعدة طبية": "orange",
62
- "مأوى": "beige",
63
- "طعام وماء": "blue",
64
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "gray",
65
- }
66
-
67
- ICON_MAPPING = {
68
- "إغاثة": "bell", # life ring icon for rescue
69
- "مساعدة طبية": "heart", # medical kit for medical assistance
70
- "مأوى": "home", # home icon for shelter
71
- "طعام وماء": "cutlery", # cutlery (fork and knife) for food & water
72
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Warning" # warning triangle for dangers
73
- }
74
 
75
  CREDITS_TEXT = """
76
  <hr>
 
48
  </div>
49
  """
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  CREDITS_TEXT = """
53
  <hr>
src/utils.py CHANGED
@@ -38,16 +38,6 @@ def is_request_in_list(request, selection_list, options):
38
  return True
39
  return False
40
 
41
- def marker_request(request):
42
- # in case of multiple requests we use the first one for the marker's icon
43
- # requests are already sorted by priority from the form
44
- try:
45
- displayed_request = request.split(',')[0]
46
- except:
47
- displayed_request = request
48
- return displayed_request
49
-
50
-
51
  def add_latlng_col(df, process_column: Union[str, int]):
52
  """Add a latlng column to the dataframe"""
53
  if isinstance(process_column, str):
 
38
  return True
39
  return False
40
 
 
 
 
 
 
 
 
 
 
 
41
  def add_latlng_col(df, process_column: Union[str, int]):
42
  """Add a latlng column to the dataframe"""
43
  if isinstance(process_column, str):