File size: 14,531 Bytes
549a2cc
 
 
b10dbaa
 
549a2cc
 
b10dbaa
ebc2ece
549a2cc
a04f639
b10dbaa
549a2cc
 
 
a8969c3
b10dbaa
01defef
b10dbaa
 
01defef
1df563c
b10dbaa
01defef
b10dbaa
 
01defef
b10dbaa
 
49d14ca
 
 
 
e2c81e5
49d14ca
 
 
 
 
edb7355
01defef
4618b5e
 
 
 
 
 
 
 
 
d72c3e5
 
 
 
 
e5dbe27
 
 
 
 
7e32c39
d72c3e5
 
 
 
 
 
edb7355
d72c3e5
e5dbe27
 
a472331
d72c3e5
e5dbe27
 
d72c3e5
 
 
 
01defef
ebc2ece
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6d4d03f
86f908d
 
 
6d4d03f
b10dbaa
 
01defef
86f908d
 
01defef
b10dbaa
 
bbbf293
01defef
b10dbaa
86f908d
 
 
 
 
 
01defef
 
 
 
6d4d03f
86f908d
6d4d03f
b10dbaa
6d4d03f
8a8cff3
 
 
 
 
96da45a
8a8cff3
caddedc
 
 
a49ed6f
caddedc
a49ed6f
caddedc
6d4d03f
 
 
 
 
 
 
 
8a8cff3
 
 
1df563c
a472331
 
8a8cff3
 
96da45a
8a8cff3
96da45a
8a8cff3
96da45a
caddedc
1fb0b3b
96da45a
6d4d03f
 
 
15d58ea
8a8cff3
1df563c
15d58ea
1df563c
 
 
 
 
 
 
 
b10dbaa
68160ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886bf76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6d4d03f
 
a49ed6f
 
6d4d03f
 
 
 
 
34dfd2a
 
6d4d03f
 
 
 
 
 
caddedc
8a8cff3
1fb0b3b
c072865
 
 
6d4d03f
01defef
b10dbaa
4482a4e
b10dbaa
01defef
0db7492
4482a4e
6d4d03f
b10dbaa
ebc2ece
 
 
 
 
b10dbaa
 
1e7a1cd
bd8b954
01defef
 
 
 
 
 
 
bbbf293
bd8b954
bbbf293
 
15d58ea
bbbf293
 
 
 
549a2cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
01defef
49d14ca
 
 
 
d8404d9
49d14ca
d8404d9
bfad8fc
15d58ea
49d14ca
 
 
b10dbaa
 
4482a4e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
import os
import time
import requests
import folium
import pandas as pd
from datetime import datetime
import streamlit as st
from streamlit_folium import st_folium
from utils import legend_macro
from huggingface_hub import HfApi
from folium import plugins


TOKEN = os.environ.get("HF_TOKEN", None)
api = HfApi(token=TOKEN)
st.set_page_config(layout="wide", initial_sidebar_state="collapsed")

if "sleep_time" not in st.session_state:
    st.session_state.sleep_time = 2

if "auto_refresh" not in st.session_state:
    st.session_state.auto_refresh = False

auto_refresh = st.sidebar.checkbox("Auto Refresh?", st.session_state.auto_refresh)

if auto_refresh:
    number = st.sidebar.number_input("Refresh rate in seconds", value=st.session_state.sleep_time)
    st.session_state.sleep_time = number

#Logo
st.markdown(
    """
    <div style="text-align: center;">
    <img src="https://storage.googleapis.com/storage-annarabic/Nt3awnou(1).png" width="200" height="200">
    </div>
    """,
    unsafe_allow_html=True,
)

st.title("Nt3awnou نتعاونو ")

# middle slogan
st.markdown(
    """
    <div style="text-align: center;">
    <h4>وَمَنْ أَحْيَاهَا فَكَأَنَّمَا أَحْيَا النَّاسَ جَمِيعاً</h4>
    </div>
    """,
    unsafe_allow_html=True,
)

st.markdown(
    """
    <div style="text-align: right;">

نتعاونو هي منصة تعاونية لمساعدة الأفراد المتضررين من الزلزال الأخير في المغرب. مهمتنا هي تسهيل تقديم المساعدة في الوقت المناسب و بفاعلية و تنظيم لجميع المتضررين. كيفاش؟ كنعاونو الناس لي محتاجين للمساعدة إعلمونا بمكانهم و نوع المساعدة لي محتاجين ليها سواء عن طريق ملأ الاستمارة أو عن طريق إرسال تسجيل صوتي عبر واتساب إلى رقم مخصص. بعد معالجة هاد المعلومات، كنجمعوهم فخريطة كتمكن الجمعيات من تنظيم و استهداف تدخلاتهم بدقة باش توصل المساعدة للناس لي محتاجين في وقت أسرع. و كل جمعية قامت باللازم في منطقة معينة تقدر تعلمنا عن طريق ملأ استمارة مخصصة لهاد الأمر. هاد المعلومات كذلك كتضاف للخريطة باش باقي الجمعيات يتاجهو لمناطق أخرى مازال ماوصلاتهم مساعدة.
تحذير : نظرا لخطورة الطرقان بسبب الحجر اللي كيطيح من الجبال، ننصح المتطوعين اللي بغاو يساعدو المناطق المتضررة يتبرعو عن طريق الجمعيات المختصة. 

[email protected] المتطوعين ليبغاو يعاونوا يقدرو يتصلوا معنا عبر البريد ✉️   
https://forms.gle/nZNCUVog9ka2Vdqu6 : ساعدونا نبلغو الناس ليمحتاجين فهاد الاستمارة 📝<br>
https://forms.gle/PsNSuHHjTTgwQMmVA : الجمعيات لي عندهم تدخلات يقدرو يبلغونا عبر هاد الاستمار  ة📝
    </div>
    """,
    unsafe_allow_html=True,
)


st.markdown("""
            <div style="text-align: left;">
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.
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.

✉️ You can contact us via email at [email protected] <br>
📝 Help us report more people in need by filling this form: https://forms.gle/nZNCUVog9ka2Vdqu6 <br>
📝 NGOs can report their interventions by filling this form: https://forms.gle/PsNSuHHjTTgwQMmVA        
            </div>
            """,
            unsafe_allow_html=True,
            )

session = requests.Session()
@st.cache_data(persist=True)
def parse_latlng_from_link(url):
    try:
        # extract latitude and longitude from gmaps link 
        if "@" not in url:
            # We first need to get the redirect URL
            resp = session.head(url, allow_redirects=True)
            url = resp.url
        latlng = url.split('@')[1].split(',')[0:2]
        return [float(latlng[0]), float(latlng[1])]
    except Exception as e:
        print(f"Error parsing latlng from link: {e}")
        return None
    
def parse_gg_sheet_interventions(url):
    url = url.replace("edit#gid=", "export?format=csv&gid=")
    print(url)
    df = pd.read_csv(url, on_bad_lines='skip')
    return df.assign(latlng=df.iloc[:, 3].apply(parse_latlng_from_link))

def parse_gg_sheet(url):
    url = url.replace("edit#gid=", "export?format=csv&gid=")
    print(url)
    df = pd.read_csv(url, on_bad_lines='warn')

    # parse latlng (column 4) to [lat, lng]
    def parse_latlng(latlng):
        try:
            lat, lng = latlng.split(",")
            return [float(lat), float(lng)]
        except Exception as e:
            print(f"Error parsing latlng: {e}")
            return None
    if df.shape[1] > 4:
        df = df.assign(latlng=df.iloc[:, 4].apply(parse_latlng))
    return df

df = parse_gg_sheet(
    "https://docs.google.com/spreadsheets/d/1gYoBBiBo1L18IVakHkf3t1fOGvHWb23loadyFZUeHJs/edit#gid=966953708"
)
interventions_df = parse_gg_sheet_interventions(
    "https://docs.google.com/spreadsheets/d/1eXOTqunOWWP8FRdENPs4cU9ulISm4XZWYJJNR1-SrwY/edit#gid=2089222765"
)

# select requests
headers_mapping = {
    "إغاثة": "Rescue/إغاثة",
    "مساعدة طبية": "Medical Assistance/مساعدة طبية",
    "مأوى": "Shelter/مأوى",
    "طعام وماء": "Food & Water/طعام وماء",
    "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Danger/مخاطر (تسرب الغاز، تلف في الخدمات العامة...)",
}
colors_mapping = {
    "إغاثة": "red",
    "مساعدة طبية": "orange",
    "مأوى": "beige",
    "طعام وماء": "blue",
    "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "gray",
}
icon_mapping = {
    "إغاثة": "bell",        # life ring icon for rescue
    "مساعدة طبية": "heart",     # medical kit for medical assistance
    "مأوى": "home",              # home icon for shelter
    "طعام وماء": "cutlery",      # cutlery (fork and knife) for food & water
    "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)": "Warning"  # warning triangle for dangers
}

options = ["إغاثة", "مساعدة طبية", "مأوى", "طعام وماء", "مخاطر (تسرب الغاز، تلف في الخدمات العامة...)"]
selected_options = []

st.markdown("👉 **Choose request type / اختر نوع الطلب**")
col1, col2, col3, col4, col5 = st.columns([2, 3, 2, 3, 4])
cols = [col1, col2, col3, col4, col5]

for i, option in enumerate(options):
    checked = cols[i].checkbox(headers_mapping[option], value=True)
    if checked:
        selected_options.append(headers_mapping[option])

arabic_options = [e.split("/")[1] for e in selected_options]
df['id'] = df.index
filtered_df = df[df['ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)'].isin(arabic_options)]
selected_headers = [headers_mapping[request] for request in arabic_options]

# select interventions
st.markdown("👇 **View past or planned interventions / عرض عمليات المساعدة السابقة أو المخطط لها**")
show_interventions = st.checkbox("Display Interventions عرض التدخلات", value=True)

m = folium.Map(
    location=[31.228674, -7.992047],
    zoom_start=8.5,
    min_zoom=8.5,
    max_lat=35.628674,
    min_lat=29.628674,
    max_lon=-4.992047,
    min_lon=-10.992047,
    max_bounds=True,
)

# Add a search bar to the map
plugins.Geocoder(
    collapsed=False,
    position="topright",
    placeholder="Search | البحث",
).add_to(m)

# Add Fullscreen button to the map
plugins.Fullscreen(
    position='topright',
    title='Expand me | تكبير الخريطة',
    title_cancel='Exit me | تصغير الخريطة',
    force_separate_button=True
).add_to(m)

#Satellite View from Mapbox 
tileurl = 'https://api.mapbox.com/styles/v1/phd2020/clmer2mra01d001pbgjkictpt/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoicGhkMjAyMCIsImEiOiJja29lZzFwZmUwNHkzMm5wMjZnYjVvcGltIn0.tE0ritrelQOyLdKUH6hgOw'

folium.TileLayer(
        tiles = tileurl,
        attr = 'Satellite View',
        name = 'Satellite View | عرض القمر الصناعي',
        overlay = False,
        control = True
       ).add_to(m)

# Add a LayerControl to the map to toggle between layers (Satellite View and Default One)
folium.LayerControl().add_to(m)


if show_interventions:
    for index, row in interventions_df.iterrows():
        status = "Done ✅" if row[interventions_df.columns[5]]!="Intervention prévue dans le futur / Planned future intervention" else "Planned ⌛"
        color_mk = "green" if row[interventions_df.columns[5]]!="Intervention prévue dans le futur / Planned future intervention" else "pink"
        intervention_type = row[interventions_df.columns[6]].split("/")[0].strip()
        org = row[interventions_df.columns[1]]
        city = row[interventions_df.columns[9]]
        date = row[interventions_df.columns[4]]
        intervention_info = f"<b>Status:</b> {status}<br><b>Org:</b> {org}<br><b>Intervention:</b> {intervention_type}<br><b>📅 Date:</b> {date}"
        if row["latlng"] is None:
            continue
        folium.Marker(
            location=row["latlng"],
            tooltip=city,
            popup=folium.Popup(intervention_info, max_width=300),  
            icon=folium.Icon(color=color_mk)  
        ).add_to(m)

for index, row in filtered_df.iterrows():
    request_type = row['ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)']
    long_lat = row["هل يمكنك تقديم الإحداثيات الدقيقة للموقع؟ (ادا كنت لا توجد بعين المكان) متلاً \n31.01837503440344, -6.781405948842175"]
    maps_url = f"https://maps.google.com/?q={long_lat}" 
    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>'
    icon_name = icon_mapping.get(request_type, 'info-sign') 
    if row["latlng"] is None:
        continue

    folium.Marker(
        location=row["latlng"],
        tooltip=row['  لأي  جماعة / قيادة / دوار تنتمون ؟'] if not pd.isna(row['  لأي  جماعة / قيادة / دوار تنتمون ؟']) else None,
        popup=folium.Popup(display_text, max_width=300),  
        icon=folium.Icon(color=colors_mapping.get(request_type, "blue"), icon=icon_name)  
    ).add_to(m)


# Macro to add legend
m.get_root().add_child(legend_macro)

st_data = st_folium(m, use_container_width=True)

# Google Sheet Table
st.subheader("📝 **Table of requests / جدول الطلبات** https://forms.gle/nZNCUVog9ka2Vdqu6")
st.markdown(
    """
    <iframe src="https://docs.google.com/spreadsheets/d/1gYoBBiBo1L18IVakHkf3t1fOGvHWb23loadyFZUeHJs/" width="100%" height="600px"></iframe>
    """,
    unsafe_allow_html=True,
)

# Google Sheet Table
st.subheader("📝 **Table of interventions / جدول التدخلات** https://forms.gle/PsNSuHHjTTgwQMmVA")
st.markdown(
    """
    <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>
    """,
    unsafe_allow_html=True,
)

# Submit an id for review
st.subheader("🔍 Review of requests")
st.markdown("**If a request should be reviewed or dropped submit its id here/ إذا كان يجب مراجعة أو حذف طلب، أدخل رقمه هنا:**")
st.markdown("If you intervened to solve the request, please fill this [form](https://docs.google.com/forms/d/e/1FAIpQLSe8D6T__DJDTVGMrIWMT-H-hQ0qDUWVOncKnrSXgv4NbwHCrQ/viewform)")
st.markdown("[form](https://docs.google.com/forms/d/e/1FAIpQLSe8D6T__DJDTVGMrIWMT-H-hQ0qDUWVOncKnrSXgv4NbwHCrQ/viewform)  إذا تدخلت لحل الطلب، يرجى ملء هذا النموذج الرابط")

id_to_review = st.number_input("Enter id / أدخل الرقم", min_value=0, max_value=len(df), value=0, step=1)
reason_for_review = st.text_area("Explain why / أدخل سبب المراجعة")
if st.button("Submit / أرسل"):
    if reason_for_review == "":
        st.error("Please enter a reason / الرجاء إدخال سبب")
    else:
        filename = f"review_id_{id_to_review}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.txt"
        with open(filename, "w") as f:
            f.write(f"id: {id_to_review}, explanation: {reason_for_review}\n")
        api.upload_file(
            path_or_fileobj=filename,
            path_in_repo=filename,
            repo_id="nt3awnou/review_requests",
            repo_type="dataset",
        ) 
        st.success("Submitted at https://huggingface.co/datasets/nt3awnou/review_requests/ تم الإرسال")



# Credits
st.markdown(
    """
    <hr>
    <div style="text-align: center;">
    <p>By <b>Moroccans</b> for <b>Moroccans</b> 🤝</p>
    <p>Bot powered by <a href="https://www.annarabic.com/">Annarabic</a></p>
    <p>Collaboration made possible thanks to <a href="https://summerschool.morocco.ai/">AI Summer School</a></p>
    """,
    unsafe_allow_html=True,
)
if auto_refresh:
    time.sleep(number)
    st.experimental_rerun()