loubnabnl HF staff commited on
Commit
daf947d
1 Parent(s): 20177be

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +179 -297
app.py CHANGED
@@ -1,209 +1,205 @@
1
  import os
2
  import time
3
- import requests
4
  import folium
5
  import pandas as pd
6
- from datetime import datetime
7
  import streamlit as st
8
- from streamlit_folium import st_folium
9
- from utils import legend_macro
10
- from huggingface_hub import HfApi
11
  from folium import plugins
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
 
14
  TOKEN = os.environ.get("HF_TOKEN", None)
15
- api = HfApi(token=TOKEN)
 
 
 
 
 
16
  st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
17
 
 
18
  if "sleep_time" not in st.session_state:
19
  st.session_state.sleep_time = 2
20
-
21
  if "auto_refresh" not in st.session_state:
22
  st.session_state.auto_refresh = False
23
 
24
- auto_refresh = st.sidebar.checkbox("Auto Refresh?", st.session_state.auto_refresh)
 
25
 
 
26
  if auto_refresh:
27
- number = st.sidebar.number_input("Refresh rate in seconds", value=st.session_state.sleep_time)
 
 
28
  st.session_state.sleep_time = number
29
 
30
- #Logo
31
- st.markdown(
32
- """
33
- <div style="text-align: center;">
34
- <img src="https://storage.googleapis.com/storage-annarabic/Nt3awnou(1).png" width="200" height="200">
35
- </div>
36
- """,
37
- unsafe_allow_html=True,
38
- )
39
 
40
- st.title("Nt3awnou نتعاونو ")
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- # middle slogan
43
- st.markdown(
44
- """
45
- <div style="text-align: center;">
46
- <h4>وَمَنْ أَحْيَاهَا فَكَأَنَّمَا أَحْيَا النَّاسَ جَمِيعاً</h4>
47
- </div>
48
- """,
49
- unsafe_allow_html=True,
50
- )
51
 
52
- # st.markdown(
53
- # """
54
- # <div style="text-align: right;">
 
 
55
 
56
- # نتعاونو هي منصة تعاونية لمساعدة الأفراد المتضررين من الزلزال الأخير في المغرب. مهمتنا هي تسهيل تقديم المساعدة في الوقت المناسب و بفاعلية و تنظيم لجميع المتضررين. كيفاش؟ كنعاونو الناس لي محتاجين للمساعدة إعلمونا بمكانهم و نوع المساعدة لي محتاجين ليها سواء عن طريق ملأ الاستمارة أو عن طريق إرسال تسجيل صوتي عبر واتساب إلى رقم مخصص. بعد معالجة هاد المعلومات، كنجمعوهم فخريطة كتمكن الجمعيات من تنظيم و استهداف تدخلاتهم بدقة باش توصل المساعدة للناس لي محتاجين في وقت أسرع. و كل جمعية قامت باللازم في منطقة معينة تقدر تعلمنا عن طريق ملأ استمارة مخصصة لهاد الأمر. هاد المعلومات كذلك كتضاف للخريطة باش باقي الجمعيات يتاجهو لمناطق أخرى مازال ماوصلاتهم مساعدة.
57
- # تحذير : نظرا لخطورة الطرقان بسبب الحجر اللي كيطيح من الجبال، ننصح المتطوعين اللي بغاو يساعدو المناطق المتضررة يتبرعو عن طريق الجمعيات المختصة.
58
 
59
- # nt3awnou@annarabic.com المتطوعين ليبغاو يعاونوا يقدرو يتصلوا معنا عبر البريد ✉️
60
- # https://forms.gle/nZNCUVog9ka2Vdqu6 : ساعدونا نبلغو الناس ليمحتاجين فهاد الاستمارة 📝<br>
61
- # https://forms.gle/PsNSuHHjTTgwQMmVA : الجمعيات لي عندهم تدخلات يقدرو يبلغونا عبر هاد الاستمار ة📝
62
- # </div>
63
- # """,
64
- # unsafe_allow_html=True,
65
- # )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
 
68
- # st.markdown("""
69
- # <div style="text-align: left;">
70
- # Nt3awnou نتعاونو is a collaborative platform dedicated to aiding individuals impacted by the recent earthquake in Morocco. Our core mission is to streamline and coordinate timely assistance for everyone affected. How do we achieve this? We assist those in need by allowing them to communicate their location and the specific aid they require, either by completing a form or sending a voice message via WhatsApp to a designated number. Once we receive and process this information, it can be viewed in our dashboard, which allows NGOs to organize and precisely target their interventions, ensuring swift assistance reaches those in need. Any organization that has taken initiative in a particular area can notify us by completing a dedicated form. This data is also incorporated into the dashboard so that other NGOs can help affected areas that still haven't received help.
71
- # Warning : There are still rocks falling down the mountains, making the roads to the affected areas very dangerous. We advise volunteers to donate directly to specialized NGOs.
 
 
 
 
 
 
 
 
72
 
73
- # ✉️ You can contact us via email at nt3awnou@annarabic.com <br>
74
- # 📝 Help us report more people in need by filling this form: https://forms.gle/nZNCUVog9ka2Vdqu6 <br>
75
- # 📝 NGOs can report their interventions by filling this form: https://forms.gle/PsNSuHHjTTgwQMmVA
76
- # </div>
77
- # """,
78
- # unsafe_allow_html=True,
79
- # )
 
 
 
80
 
81
- # Have different streamlit tabs for each language
82
- st.sidebar.title("Language / اللغة")
83
- tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
84
 
85
- with tab_en:
86
- st.markdown("""
87
- <div style="text-align: left;">
88
- Nt3awnou نتعاونو is a collaborative platform dedicated to aiding individuals impacted by the recent earthquake in Morocco. Our core mission is to streamline and coordinate timely assistance for everyone affected. How do we achieve this? We assist those in need by allowing them to communicate their location and the specific aid they require, either by completing a form or sending a voice message via WhatsApp to a designated number. Once we receive and process this information, it can be viewed in our dashboard, which allows NGOs to organize and precisely target their interventions, ensuring swift assistance reaches those in need. Any organization that has taken initiative in a particular area can notify us by completing a dedicated form. This data is also incorporated into the dashboard so that other NGOs can help affected areas that still haven't received help.
89
- Warning : There are still rocks falling down the mountains, making the roads to the affected areas very dangerous. We advise volunteers to donate directly to specialized NGOs.
90
-
91
- ✉️ You can contact us via email at nt3awnou@annarabic.com <br>
92
- 📝 Help us report more people in need by filling this form: https://forms.gle/nZNCUVog9ka2Vdqu6 <br>
93
- 📝 NGOs can report their interventions by filling this form: https://forms.gle/PsNSuHHjTTgwQMmVA
94
- </div>
95
- """,
96
- unsafe_allow_html=True,
97
- )
98
- with tab_ar:
99
  st.markdown(
100
- """
101
- <div style="text-align: right;">
102
-
103
- نتعاونو هي منصة تعاونية لمساعدة الأفراد المتضررين من الزلزال الأخير في المغرب. مهمتنا هي تسهيل تقديم المساعدة في الوقت المناسب و بفاعلية و تنظيم لجميع المتضررين. كيفاش؟ كنعاونو الناس لي محتاجين للمساعدة إعلمونا بمكانهم و نوع المساعدة لي محتاجين ليها سواء عن طريق ملأ الاستمارة أو عن طريق إرسال تسجيل صوتي عبر واتساب إلى رقم مخصص. بعد معالجة هاد المعلومات، كنجمعوهم فخريطة كتمكن الجمعيات من تنظيم و استهداف تدخلاتهم بدقة باش توصل المساعدة للناس لي محتاجين في وقت أسرع. و كل جمعية قامت باللازم في منطقة معينة تقدر تعلمنا عن طريق ملأ استمارة مخصصة لهاد الأمر. هاد المعلومات كذلك كتضاف للخريطة باش باقي الجمعيات يتاجهو لمناطق أخرى مازال ماوصلاتهم مساعدة.
104
- تحذير : نظرا لخطورة الطرقان بسبب الحجر اللي كيطيح من الجبال، ننصح المتطوعين اللي بغاو يساعدو المناطق المتضررة يتبرعو عن طريق الجمعيات المختصة.
105
 
106
- nt3awnou@annarabic.com المتطوعين ليبغاو يعاونوا يقدرو يتصلوا معنا عبر البريد ✉️
107
- https://forms.gle/nZNCUVog9ka2Vdqu6 : ساعدونا نبلغو الناس ليمحتاجين فهاد الاستمارة 📝<br>
108
- https://forms.gle/PsNSuHHjTTgwQMmVA : الجمعيات لي عندهم تدخلات يقدرو يبلغونا عبر هاد الاستمار ة📝
109
- </div>
110
- """,
111
  unsafe_allow_html=True,
112
  )
113
 
114
- with tab_fr:
115
- st.markdown("""
116
- <div style="text-align: left;">
117
- Nt3awnou نتعاونو est une plateforme collaborative dédiée à l'aide aux personnes touchées par le récent tremblement de terre au Maroc. Notre mission principale est de rationaliser et de coordonner une assistance rapide pour toutes les personnes touchées. Comment y parvenons-nous ? Nous aidons les personnes dans le besoin en leur permettant de communiquer leur localisation et l'aide spécifique dont elles ont besoin, soit en remplissant un formulaire, soit en envoyant un message vocal via WhatsApp à un numéro désigné. Une fois reçues et traitées, ces informations peuvent être consultées dans notre tableau de bord, qui permet aux associations d'organiser et de cibler précisément leurs interventions, afin que l'aide parvienne rapidement à ceux qui en ont besoin. Toute organisation ayant pris une initiative dans une zone particulière peut nous en informer en remplissant un formulaire prévu à cet effet. Ces données sont également intégrées au tableau de bord afin que d'autres associations puissent aider les zones touchées qui n'ont pas encore reçu d'aide.
118
- Avertissement : Il y a encore des chutes de pierres dans les montagnes, ce qui rend les routes vers les zones touchées très dangereuses. Nous conseillons aux volontaires de faire des dons directement aux associations spécialisées.
119
-
120
- Vous pouvez nous contacter par courrier électronique à l'adresse suivante : nt3awnou@annarabic.com
121
- Aidez-nous à signaler plus de personnes dans le besoin en remplissant ce formulaire : https://forms.gle/nZNCUVog9ka2Vdqu6
122
- Les associations peuvent signaler leurs interventions en remplissant ce formulaire : https://forms.gle/PsNSuHHjTTgwQMmVA
123
- </div>
124
- """
125
- , unsafe_allow_html=True)
126
 
 
 
 
 
127
 
128
- session = requests.Session()
129
- @st.cache_data(persist=True)
130
- def parse_latlng_from_link(url):
131
- try:
132
- # extract latitude and longitude from gmaps link
133
- if "@" not in url:
134
- # We first need to get the redirect URL
135
- resp = session.head(url, allow_redirects=True)
136
- url = resp.url
137
- latlng = url.split('@')[1].split(',')[0:2]
138
- return [float(latlng[0]), float(latlng[1])]
139
- except Exception as e:
140
- print(f"Error parsing latlng from link: {e}")
141
- return None
142
-
143
- def parse_gg_sheet_interventions(url):
144
- url = url.replace("edit#gid=", "export?format=csv&gid=")
145
- print(url)
146
- df = pd.read_csv(url, on_bad_lines='skip')
147
- return df.assign(latlng=df.iloc[:, 3].apply(parse_latlng_from_link))
 
 
 
 
 
 
148
 
149
- def parse_gg_sheet(url):
150
- url = url.replace("edit#gid=", "export?format=csv&gid=")
151
- print(url)
152
- df = pd.read_csv(url, on_bad_lines='warn')
153
-
154
- # parse latlng (column 4) to [lat, lng]
155
- def parse_latlng(latlng):
156
- try:
157
- lat, lng = latlng.split(",")
158
- return [float(lat), float(lng)]
159
- except Exception as e:
160
- print(f"Error parsing latlng: {e}")
161
- return None
162
- if df.shape[1] > 4:
163
- df = df.assign(latlng=df.iloc[:, 4].apply(parse_latlng))
164
- return df
165
-
166
- df = parse_gg_sheet(
167
- "https://docs.google.com/spreadsheets/d/1gYoBBiBo1L18IVakHkf3t1fOGvHWb23loadyFZUeHJs/edit#gid=966953708"
168
- )
169
- interventions_df = parse_gg_sheet_interventions(
170
- "https://docs.google.com/spreadsheets/d/1eXOTqunOWWP8FRdENPs4cU9ulISm4XZWYJJNR1-SrwY/edit#gid=2089222765"
171
- )
172
 
173
- # select requests
174
- with tab_ar:
175
- headers_mapping = {
176
- "إغاثة": "Rescue/إغاثة",
177
- "مساعدة طبية": "Medical Assistance/مساعدة طبية",
178
- "مأوى": "Shelter/مأوى",
179
- "طعام وماء": "Food & Water/طعام وماء",
180
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Danger/مخاطر (تسرب الغاز، تلف في الخدمات العامة...)",
181
- }
182
  with tab_en:
183
- headers_mapping = {
184
- "إغاثة" : "Rescue | إغاثة | Secours",
185
- "مساعدة طبية": "Medical Assistance | مساعدة طبية | Assistance médicale",
186
- "مأوى": "Shelter | مأوى | Abri",
187
- "طعام وماء": "Food & Water | طعام وماء | Nourriture et eau",
188
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Danger | مخاطر (تسرب الغاز، تلف في الخدمات العامة...) | Danger",
189
- }
190
-
191
-
192
- colors_mapping = {
193
- "إغاثة": "red",
194
- "مساعدة طبية": "orange",
195
- "مأوى": "beige",
196
- "طعام وماء": "blue",
197
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "gray",
198
- }
199
- icon_mapping = {
200
- "إغاثة": "bell", # life ring icon for rescue
201
- "مساعدة طبية": "heart", # medical kit for medical assistance
202
- "مأوى": "home", # home icon for shelter
203
- "طعام وماء": "cutlery", # cutlery (fork and knife) for food & water
204
- "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Warning" # warning triangle for dangers
205
- }
206
- options = ["إغاثة", "مساعدة طبية", "مأوى", "طعام وماء", "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)"]
207
  selected_options = []
208
 
209
  with tab_en:
@@ -217,154 +213,40 @@ col1, col2, col3, col4, col5 = st.columns([2, 3, 2, 3, 4])
217
  cols = [col1, col2, col3, col4, col5]
218
 
219
  for i, option in enumerate(options):
220
- checked = cols[i].checkbox(headers_mapping[option], value=True)
221
  if checked:
222
  selected_options.append(option)
223
 
224
- df['id'] = df.index
225
- filtered_df = df[df['ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)'].isin(selected_options)]
226
- selected_headers = [headers_mapping[request] for request in selected_options]
227
-
228
- # select interventions
229
- show_interventions = st.checkbox("Display Interventions | عرض عمليات المساعدة | Afficher les interventions", value=True)
230
-
231
- m = folium.Map(
232
- location=[31.228674, -7.992047],
233
- zoom_start=8.5,
234
- min_zoom=8.5,
235
- max_lat=35.628674,
236
- min_lat=29.628674,
237
- max_lon=-4.992047,
238
- min_lon=-10.992047,
239
- max_bounds=True,
240
- )
241
-
242
- # Add a search bar to the map
243
- plugins.Geocoder(
244
- collapsed=False,
245
- position="topright",
246
- placeholder="Search | البحث",
247
- ).add_to(m)
248
-
249
- # Add Fullscreen button to the map
250
- plugins.Fullscreen(
251
- position='topright',
252
- title='Expand me | تكبير الخريطة',
253
- title_cancel='Exit me | تصغير الخريطة',
254
- force_separate_button=True
255
- ).add_to(m)
256
-
257
- #Satellite View from Mapbox
258
- tileurl = 'https://api.mapbox.com/styles/v1/phd2020/clmer2mra01d001pbgjkictpt/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoicGhkMjAyMCIsImEiOiJja29lZzFwZmUwNHkzMm5wMjZnYjVvcGltIn0.tE0ritrelQOyLdKUH6hgOw'
259
-
260
- folium.TileLayer(
261
- tiles = tileurl,
262
- attr = 'Satellite View',
263
- name = 'Satellite View | عرض القمر الصناعي',
264
- overlay = False,
265
- control = True
266
- ).add_to(m)
267
-
268
- # Add a LayerControl to the map to toggle between layers (Satellite View and Default One)
269
- folium.LayerControl().add_to(m)
270
 
 
 
 
 
 
271
 
272
  if show_interventions:
273
- for index, row in interventions_df.iterrows():
274
- status = "Done ✅" if row[interventions_df.columns[5]]!="Intervention prévue dans le futur / Planned future intervention" else "Planned ⌛"
275
- color_mk = "green" if row[interventions_df.columns[5]]!="Intervention prévue dans le futur / Planned future intervention" else "pink"
276
- intervention_type = row[interventions_df.columns[6]].split("/")[0].strip()
277
- org = row[interventions_df.columns[1]]
278
- city = row[interventions_df.columns[9]]
279
- date = row[interventions_df.columns[4]]
280
- intervention_info = f"<b>Status:</b> {status}<br><b>Org:</b> {org}<br><b>Intervention:</b> {intervention_type}<br><b>📅 Date:</b> {date}"
281
- if row["latlng"] is None:
282
- continue
283
- folium.Marker(
284
- location=row["latlng"],
285
- tooltip=city,
286
- popup=folium.Popup(intervention_info, max_width=300),
287
- icon=folium.Icon(color=color_mk)
288
- ).add_to(m)
289
-
290
- for index, row in filtered_df.iterrows():
291
- request_type = row['ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)']
292
- long_lat = row["هل يمكنك تقديم الإحداثيات الدقيقة للموقع؟ (ادا كنت لا توجد بعين المكان) متلاً \n31.01837503440344, -6.781405948842175"]
293
- maps_url = f"https://maps.google.com/?q={long_lat}"
294
- display_text = f'<b>Request Type:</b> {request_type}<br><b>Id:</b> {row["id"]}<br><a href="{maps_url}" target="_blank" rel="noopener noreferrer"><b>Google Maps</b></a>'
295
- icon_name = icon_mapping.get(request_type, 'info-sign')
296
- if row["latlng"] is None:
297
- continue
298
 
299
- folium.Marker(
300
- location=row["latlng"],
301
- tooltip=row[' لأي جماعة / قيادة / دوار تنتمون ؟'] if not pd.isna(row[' لأي جماعة / قيادة / دوار تنتمون ؟']) else None,
302
- popup=folium.Popup(display_text, max_width=300),
303
- icon=folium.Icon(color=colors_mapping.get(request_type, "blue"), icon=icon_name)
304
- ).add_to(m)
305
-
306
-
307
- # Macro to add legend
308
- m.get_root().add_child(legend_macro)
309
 
310
  st_data = st_folium(m, use_container_width=True)
311
 
312
- # Google Sheet Table
313
- st.subheader("📝 **Table of requests / جدول الطلبات** https://forms.gle/nZNCUVog9ka2Vdqu6")
314
- st.markdown(
315
- """
316
- <iframe src="https://docs.google.com/spreadsheets/d/1gYoBBiBo1L18IVakHkf3t1fOGvHWb23loadyFZUeHJs/" width="100%" height="600px"></iframe>
317
- <br>
318
- """,
319
- unsafe_allow_html=True,
320
- )
321
-
322
- # Google Sheet Table
323
- st.subheader("📝 **Table of interventions / جدول عمليات المساعدة** https://forms.gle/PsNSuHHjTTgwQMmVA")
324
- st.markdown(
325
- """
326
- <iframe src="https://docs.google.com/spreadsheets/d/1eXOTqunOWWP8FRdENPs4cU9ulISm4XZWYJJNR1-SrwY/?single=true&gid=419657423&range=f2:g6&widget=false&chrome=false" width="100%" height="600px"></iframe>
327
- <br>
328
- """,
329
- unsafe_allow_html=True,
330
- )
331
 
332
  # Submit an id for review
333
- st.subheader("🔍 Review of requests")
334
- st.markdown("If you intervened to solve a request, please fill this [form](https://docs.google.com/forms/d/e/1FAIpQLSe8D6T__DJDTVGMrIWMT-H-hQ0qDUWVOncKnrSXgv4NbwHCrQ/viewform)")
335
- st.markdown("إذا تدخلت لحل طلب، يرجى ملء هذا [النموذج](https://docs.google.com/forms/d/e/1FAIpQLSe8D6T__DJDTVGMrIWMT-H-hQ0qDUWVOncKnrSXgv4NbwHCrQ/viewform)")
336
- st.markdown("**If a request should be reviewed or dropped submit its id here/ إذا كان يجب مراجعة أو حذف طلب، أدخل رقمه هنا:**")
337
-
338
- id_to_review = st.number_input("Enter id / أدخل الرقم", min_value=0, max_value=len(df), value=0, step=1)
339
- reason_for_review = st.text_area("Explain why / أدخل سبب المراجعة")
340
- if st.button("Submit / أرسل"):
341
- if reason_for_review == "":
342
- st.error("Please enter a reason / الرجاء إدخال سبب")
343
- else:
344
- filename = f"review_id_{id_to_review}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt"
345
- with open(filename, "w") as f:
346
- f.write(f"id: {id_to_review}, explanation: {reason_for_review}\n")
347
- api.upload_file(
348
- path_or_fileobj=filename,
349
- path_in_repo=filename,
350
- repo_id="nt3awnou/review_requests",
351
- repo_type="dataset",
352
- )
353
- st.success("Submitted at https://huggingface.co/datasets/nt3awnou/review_requests/ تم الإرسال")
354
-
355
 
356
 
357
  # Credits
358
  st.markdown(
359
- """
360
- <hr>
361
- <div style="text-align: center;">
362
- <p>By <b>Moroccans</b> for <b>Moroccans</b> 🤝</p>
363
- <p>Bot powered by <a href="https://www.annarabic.com/">Annarabic</a></p>
364
- <p>Collaboration made possible thanks to <a href="https://summerschool.morocco.ai/">AI Summer School</a></p>
365
- """,
366
  unsafe_allow_html=True,
367
  )
368
  if auto_refresh:
369
  time.sleep(number)
370
- st.experimental_rerun()
 
1
  import os
2
  import time
3
+
4
  import folium
5
  import pandas as pd
6
+ import requests
7
  import streamlit as st
 
 
 
8
  from folium import plugins
9
+ from huggingface_hub import HfApi
10
+ from streamlit_folium import st_folium
11
+
12
+ from src.text_content import (
13
+ COLOR_MAPPING,
14
+ CREDITS_TEXT,
15
+ HEADERS_MAPPING,
16
+ ICON_MAPPING,
17
+ INTRO_TEXT_AR,
18
+ INTRO_TEXT_EN,
19
+ INTRO_TEXT_FR,
20
+ LOGO,
21
+ REVIEW_TEXT,
22
+ SLOGAN,
23
+ )
24
+ from src.utils import init_map, parse_gg_sheet
25
 
26
 
27
  TOKEN = os.environ.get("HF_TOKEN", None)
28
+ REQUESTS_URL = "https://docs.google.com/spreadsheets/d/1gYoBBiBo1L18IVakHkf3t1fOGvHWb23loadyFZUeHJs/edit#gid=966953708"
29
+ INTERVENTIONS_URL = "https://docs.google.com/spreadsheets/d/1eXOTqunOWWP8FRdENPs4cU9ulISm4XZWYJJNR1-SrwY/edit#gid=2089222765"
30
+ api = HfApi(TOKEN)
31
+
32
+
33
+ # Initialize Streamlit Config
34
  st.set_page_config(layout="wide", initial_sidebar_state="collapsed")
35
 
36
+ # Initialize States
37
  if "sleep_time" not in st.session_state:
38
  st.session_state.sleep_time = 2
 
39
  if "auto_refresh" not in st.session_state:
40
  st.session_state.auto_refresh = False
41
 
42
+ # Session for Requests
43
+ session = requests.Session()
44
 
45
+ auto_refresh = st.sidebar.checkbox("Auto Refresh?", st.session_state.auto_refresh)
46
  if auto_refresh:
47
+ number = st.sidebar.number_input(
48
+ "Refresh rate in seconds", value=st.session_state.sleep_time
49
+ )
50
  st.session_state.sleep_time = number
51
 
 
 
 
 
 
 
 
 
 
52
 
53
+ # Utility functions
54
+ @st.cache_data(persist=True)
55
+ def parse_latlng_from_link(url):
56
+ try:
57
+ # extract latitude and longitude from gmaps link
58
+ if "@" not in url:
59
+ resp = session.head(url, allow_redirects=True)
60
+ url = resp.url
61
+ latlng = url.split("@")[1].split(",")[0:2]
62
+ return [float(latlng[0]), float(latlng[1])]
63
+ except Exception as e:
64
+ print(f"Error parsing latlng from link: {e}")
65
+ return None
66
 
 
 
 
 
 
 
 
 
 
67
 
68
+ def parse_gg_sheet_interventions(url):
69
+ url = url.replace("edit#gid=", "export?format=csv&gid=")
70
+ print(url)
71
+ df = pd.read_csv(url, on_bad_lines="skip")
72
+ return df.assign(latlng=df.iloc[:, 3].apply(parse_latlng_from_link))
73
 
 
 
74
 
75
+ # Streamlit functions
76
+ def display_interventions(interventions_df, m):
77
+ """Display NGO interventions on the map"""
78
+ for index, row in interventions_df.iterrows():
79
+ status = (
80
+ "Done ✅"
81
+ if row[interventions_df.columns[5]]
82
+ != "Intervention prévue dans le futur / Planned future intervention"
83
+ else "Planned ⌛"
84
+ )
85
+ color_mk = (
86
+ "green"
87
+ if row[interventions_df.columns[5]]
88
+ != "Intervention prévue dans le futur / Planned future intervention"
89
+ else "pink"
90
+ )
91
+ intervention_type = row[interventions_df.columns[6]].split("/")[0].strip()
92
+ org = row[interventions_df.columns[1]]
93
+ city = row[interventions_df.columns[9]]
94
+ date = row[interventions_df.columns[4]]
95
+ intervention_info = f"<b>Status:</b> {status}<br><b>Org:</b> {org}<br><b>Intervention:</b> {intervention_type}<br><b>📅 Date:</b> {date}"
96
+ if row["latlng"] is None:
97
+ continue
98
+ folium.Marker(
99
+ location=row["latlng"],
100
+ tooltip=city,
101
+ popup=folium.Popup(intervention_info, max_width=300),
102
+ icon=folium.Icon(color=color_mk),
103
+ ).add_to(m)
104
 
105
 
106
+ def show_requests(filtered_df, m):
107
+ """Display victim requests on the map"""
108
+ for index, row in filtered_df.iterrows():
109
+ request_type = row["ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)"]
110
+ long_lat = row[
111
+ "هل يمكنك تقديم الإحداثيات الدقيقة للموقع؟ (ادا كنت لا توجد بعين المكان) متلاً \n31.01837503440344, -6.781405948842175"
112
+ ]
113
+ maps_url = f"https://maps.google.com/?q={long_lat}"
114
+ display_text = f'<b>Request Type:</b> {request_type}<br><b>Id:</b> {row["id"]}<br><a href="{maps_url}" target="_blank" rel="noopener noreferrer"><b>Google Maps</b></a>'
115
+ icon_name = ICON_MAPPING.get(request_type, "info-sign")
116
+ if row["latlng"] is None:
117
+ continue
118
 
119
+ folium.Marker(
120
+ location=row["latlng"],
121
+ tooltip=row[" لأي جماعة / قيادة / دوار تنتمون ؟"]
122
+ if not pd.isna(row[" لأي جماعة / قيادة / دوار تنتمون ؟"])
123
+ else None,
124
+ popup=folium.Popup(display_text, max_width=300),
125
+ icon=folium.Icon(
126
+ color=COLOR_MAPPING.get(request_type, "blue"), icon=icon_name
127
+ ),
128
+ ).add_to(m)
129
 
 
 
 
130
 
131
+ def display_google_sheet_tables():
132
+ """Display the google sheet tables for requests and interventions"""
133
+ st.subheader("📝 **Table of requests / جدول الطلبات**")
 
 
 
 
 
 
 
 
 
 
 
134
  st.markdown(
135
+ f"""<iframe src="{REQUESTS_URL}" width="100%" height="600px"></iframe>""",
136
+ unsafe_allow_html=True,
137
+ )
 
 
138
 
139
+ st.subheader("📝 **Table of interventions / جدول التدخلات**")
140
+ st.markdown(
141
+ f"""<iframe src="{INTERVENTIONS_URL}" width="100%" height="600px"></iframe>""",
 
 
142
  unsafe_allow_html=True,
143
  )
144
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ def id_review_submission():
147
+ """Id review submission form"""
148
+ st.subheader("🔍 Review of requests")
149
+ st.markdown(REVIEW_TEXT)
150
 
151
+ id_to_review = st.number_input(
152
+ "Enter id / أدخل الرقم", min_value=0, max_value=len(df), value=0, step=1
153
+ )
154
+ reason_for_review = st.text_area("Explain why / أدخل سبب المراجعة")
155
+ if st.button("Submit / أرسل"):
156
+ if reason_for_review == "":
157
+ st.error("Please enter a reason / الرجاء إدخال سبب")
158
+ else:
159
+ filename = f"review_id_{id_to_review}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt"
160
+ with open(filename, "w") as f:
161
+ f.write(f"id: {id_to_review}, explanation: {reason_for_review}\n")
162
+ api.upload_file(
163
+ path_or_fileobj=filename,
164
+ path_in_repo=filename,
165
+ repo_id="nt3awnou/review_requests",
166
+ repo_type="dataset",
167
+ )
168
+ st.success(
169
+ "Submitted at https://huggingface.co/datasets/nt3awnou/review_requests/ تم الإرسال"
170
+ )
171
+
172
+
173
+ # Logo and Title
174
+ st.markdown(LOGO, unsafe_allow_html=True)
175
+ st.title("Nt3awnou نتعاونو ")
176
+ st.markdown(SLOGAN, unsafe_allow_html=True)
177
 
178
+ # Language tabs
179
+ st.sidebar.title("Language / اللغة")
180
+ tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
 
 
 
 
 
 
 
 
 
 
182
  with tab_en:
183
+ st.markdown(INTRO_TEXT_EN, unsafe_allow_html=True)
184
+ with tab_ar:
185
+ st.markdown(INTRO_TEXT_AR, unsafe_allow_html=True)
186
+ with tab_fr:
187
+ st.markdown(INTRO_TEXT_FR, unsafe_allow_html=True)
188
+
189
+
190
+ # Load data and initialize map with plugins
191
+ df = parse_gg_sheet(REQUESTS_URL)
192
+ interventions_df = parse_gg_sheet_interventions(INTERVENTIONS_URL)
193
+ m = init_map()
194
+
195
+ # Selection of requests
196
+ options = [
197
+ "إغاثة",
198
+ "مساعدة طبية",
199
+ "مأوى",
200
+ "طعام وماء",
201
+ "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)",
202
+ ]
 
 
 
 
203
  selected_options = []
204
 
205
  with tab_en:
 
213
  cols = [col1, col2, col3, col4, col5]
214
 
215
  for i, option in enumerate(options):
216
+ checked = cols[i].checkbox(HEADERS_MAPPING[option], value=True)
217
  if checked:
218
  selected_options.append(option)
219
 
220
+ df["id"] = df.index
221
+ filtered_df = df[df["ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)"].isin(selected_options)]
222
+ selected_headers = [HEADERS_MAPPING[request] for request in selected_options]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
+ # Selection of interventions
225
+ show_interventions = st.checkbox(
226
+ "Display Interventions | عرض عمليات المساعدة | Afficher les interventions",
227
+ value=True,
228
+ )
229
 
230
  if show_interventions:
231
+ display_interventions(interventions_df, m)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
+ # Show requests
234
+ show_requests(filtered_df, m)
 
 
 
 
 
 
 
 
235
 
236
  st_data = st_folium(m, use_container_width=True)
237
 
238
+ # Google Sheet Tables
239
+ display_google_sheet_tables()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
 
241
  # Submit an id for review
242
+ id_review_submission()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
 
244
 
245
  # Credits
246
  st.markdown(
247
+ CREDITS_TEXT,
 
 
 
 
 
 
248
  unsafe_allow_html=True,
249
  )
250
  if auto_refresh:
251
  time.sleep(number)
252
+ st.experimental_rerun()