Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -4,9 +4,7 @@ from datetime import datetime
|
|
4 |
|
5 |
import folium
|
6 |
import pandas as pd
|
7 |
-
import requests
|
8 |
import streamlit as st
|
9 |
-
from folium import plugins
|
10 |
from huggingface_hub import HfApi
|
11 |
from streamlit_folium import st_folium
|
12 |
|
@@ -20,10 +18,9 @@ from src.text_content import (
|
|
20 |
INTRO_TEXT_FR,
|
21 |
LOGO,
|
22 |
REVIEW_TEXT,
|
23 |
-
REVIEW_TEXT_2,
|
24 |
SLOGAN,
|
25 |
)
|
26 |
-
from src.utils import init_map, parse_gg_sheet
|
27 |
|
28 |
TOKEN = os.environ.get("HF_TOKEN", None)
|
29 |
REQUESTS_URL = "https://docs.google.com/spreadsheets/d/1gYoBBiBo1L18IVakHkf3t1fOGvHWb23loadyFZUeHJs/edit#gid=966953708"
|
@@ -32,7 +29,12 @@ api = HfApi(TOKEN)
|
|
32 |
|
33 |
|
34 |
# Initialize Streamlit Config
|
35 |
-
st.set_page_config(
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
# Initialize States
|
38 |
if "sleep_time" not in st.session_state:
|
@@ -40,9 +42,6 @@ if "sleep_time" not in st.session_state:
|
|
40 |
if "auto_refresh" not in st.session_state:
|
41 |
st.session_state.auto_refresh = False
|
42 |
|
43 |
-
# Session for Requests
|
44 |
-
session = requests.Session()
|
45 |
-
|
46 |
auto_refresh = st.sidebar.checkbox("Auto Refresh?", st.session_state.auto_refresh)
|
47 |
if auto_refresh:
|
48 |
number = st.sidebar.number_input(
|
@@ -51,48 +50,42 @@ if auto_refresh:
|
|
51 |
st.session_state.sleep_time = number
|
52 |
|
53 |
|
54 |
-
# Utility functions
|
55 |
-
@st.cache_data(persist=True)
|
56 |
-
def parse_latlng_from_link(url):
|
57 |
-
try:
|
58 |
-
# extract latitude and longitude from gmaps link
|
59 |
-
if "@" not in url:
|
60 |
-
resp = session.head(url, allow_redirects=True)
|
61 |
-
url = resp.url
|
62 |
-
latlng = url.split("@")[1].split(",")[0:2]
|
63 |
-
return [float(latlng[0]), float(latlng[1])]
|
64 |
-
except Exception as 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 |
-
|
86 |
-
|
87 |
-
if row[interventions_df.columns[5]]
|
88 |
!= "Intervention prévue dans le futur / Planned future intervention"
|
89 |
-
|
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 |
-
|
|
|
96 |
if row["latlng"] is None:
|
97 |
continue
|
98 |
folium.Marker(
|
@@ -128,7 +121,6 @@ def show_requests(filtered_df, m):
|
|
128 |
).add_to(m)
|
129 |
|
130 |
|
131 |
-
|
132 |
def display_google_sheet_tables(data_url):
|
133 |
"""Display the google sheet tables for requests and interventions"""
|
134 |
st.markdown(
|
@@ -190,13 +182,25 @@ def display_dataframe(df, drop_cols, data_url, search_id=True, status=False):
|
|
190 |
st.markdown(
|
191 |
f"To view the full Google Sheet for advanced filtering go to: {data_url} **لعرض الورقة كاملة، اذهب إلى**"
|
192 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
|
194 |
|
195 |
def id_review_submission():
|
196 |
"""Id review submission form"""
|
197 |
st.subheader("🔍 Review of requests")
|
198 |
st.markdown(REVIEW_TEXT)
|
199 |
-
st.markdown(REVIEW_TEXT_2)
|
200 |
|
201 |
id_to_review = st.number_input(
|
202 |
"Enter id / أدخل الرقم", min_value=0, max_value=len(df), value=0, step=1
|
@@ -222,24 +226,14 @@ def id_review_submission():
|
|
222 |
|
223 |
# Logo and Title
|
224 |
st.markdown(LOGO, unsafe_allow_html=True)
|
225 |
-
st.title("Nt3awnou نتعاونو
|
226 |
st.markdown(SLOGAN, unsafe_allow_html=True)
|
227 |
|
228 |
-
# Language tabs
|
229 |
-
st.sidebar.title("Language / اللغة")
|
230 |
-
tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
|
231 |
-
|
232 |
-
with tab_en:
|
233 |
-
st.markdown(INTRO_TEXT_EN, unsafe_allow_html=True)
|
234 |
-
with tab_ar:
|
235 |
-
st.markdown(INTRO_TEXT_AR, unsafe_allow_html=True)
|
236 |
-
with tab_fr:
|
237 |
-
st.markdown(INTRO_TEXT_FR, unsafe_allow_html=True)
|
238 |
-
|
239 |
-
|
240 |
# Load data and initialize map with plugins
|
241 |
df = parse_gg_sheet(REQUESTS_URL)
|
242 |
-
|
|
|
|
|
243 |
m = init_map()
|
244 |
|
245 |
# Selection of requests
|
@@ -252,13 +246,10 @@ options = [
|
|
252 |
]
|
253 |
selected_options = []
|
254 |
|
255 |
-
with tab_en:
|
256 |
-
st.markdown("👉 **Choose request type**")
|
257 |
-
with tab_ar:
|
258 |
-
st.markdown("👉 **اختر نوع الطلب**")
|
259 |
-
with tab_fr:
|
260 |
-
st.markdown("👉 **Choisissez le type de demande**")
|
261 |
|
|
|
|
|
|
|
262 |
col1, col2, col3, col4, col5 = st.columns([2, 3, 2, 3, 4])
|
263 |
cols = [col1, col2, col3, col4, col5]
|
264 |
|
@@ -277,16 +268,76 @@ show_interventions = st.checkbox(
|
|
277 |
value=True,
|
278 |
)
|
279 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
if show_interventions:
|
|
|
|
|
|
|
|
|
|
|
281 |
display_interventions(interventions_df, m)
|
282 |
|
283 |
# Show requests
|
284 |
show_requests(filtered_df, m)
|
285 |
|
286 |
st_data = st_folium(m, use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
|
288 |
-
st.subheader("📝 **Table of requests / جدول الطلبات**")
|
289 |
# Requests table
|
|
|
|
|
290 |
drop_cols = [
|
291 |
"(عند الامكان) رقم هاتف شخص موجود في عين المكان",
|
292 |
"الرجاء الضغط على الرابط التالي لمعرفة موقعك إذا كان متاحا",
|
@@ -294,19 +345,23 @@ drop_cols = [
|
|
294 |
"GeoCode",
|
295 |
"GeoAddress",
|
296 |
"Status",
|
|
|
297 |
]
|
298 |
display_dataframe(filtered_df, drop_cols, REQUESTS_URL, search_id=True)
|
299 |
|
300 |
# Interventions table
|
|
|
301 |
st.subheader("📝 **Table of interventions / جدول التدخلات**")
|
302 |
display_dataframe(
|
303 |
interventions_df,
|
304 |
-
[
|
305 |
INTERVENTIONS_URL,
|
306 |
search_id=False,
|
307 |
status=True,
|
308 |
)
|
|
|
309 |
# Submit an id for review
|
|
|
310 |
id_review_submission()
|
311 |
|
312 |
|
|
|
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 |
|
|
|
18 |
INTRO_TEXT_FR,
|
19 |
LOGO,
|
20 |
REVIEW_TEXT,
|
|
|
21 |
SLOGAN,
|
22 |
)
|
23 |
+
from src.utils import add_latlng_col, init_map, parse_gg_sheet
|
24 |
|
25 |
TOKEN = os.environ.get("HF_TOKEN", None)
|
26 |
REQUESTS_URL = "https://docs.google.com/spreadsheets/d/1gYoBBiBo1L18IVakHkf3t1fOGvHWb23loadyFZUeHJs/edit#gid=966953708"
|
|
|
29 |
|
30 |
|
31 |
# Initialize Streamlit Config
|
32 |
+
st.set_page_config(
|
33 |
+
layout="wide",
|
34 |
+
initial_sidebar_state="collapsed",
|
35 |
+
page_icon="🤝",
|
36 |
+
page_title="Nt3awnou نتعاونو",
|
37 |
+
)
|
38 |
|
39 |
# Initialize States
|
40 |
if "sleep_time" not in st.session_state:
|
|
|
42 |
if "auto_refresh" not in st.session_state:
|
43 |
st.session_state.auto_refresh = False
|
44 |
|
|
|
|
|
|
|
45 |
auto_refresh = st.sidebar.checkbox("Auto Refresh?", st.session_state.auto_refresh)
|
46 |
if auto_refresh:
|
47 |
number = st.sidebar.number_input(
|
|
|
50 |
st.session_state.sleep_time = number
|
51 |
|
52 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
# Streamlit functions
|
54 |
def display_interventions(interventions_df, m):
|
55 |
"""Display NGO interventions on the map"""
|
56 |
for index, row in interventions_df.iterrows():
|
57 |
+
village_status = row[interventions_df.columns[7]]
|
58 |
status = (
|
59 |
"Done ✅"
|
60 |
if row[interventions_df.columns[5]]
|
61 |
!= "Intervention prévue dans le futur / Planned future intervention"
|
62 |
+
and village_status
|
63 |
+
!= "Critique, Besoin d'aide en urgence / Critical, in urgent need of help"
|
64 |
else "Planned ⌛"
|
65 |
)
|
66 |
+
if (
|
67 |
+
row[interventions_df.columns[5]]
|
|
|
68 |
!= "Intervention prévue dans le futur / Planned future intervention"
|
69 |
+
and village_status
|
70 |
+
!= "Critique, Besoin d'aide en urgence / Critical, in urgent need of help"
|
71 |
+
):
|
72 |
+
color_mk = "green"
|
73 |
+
elif (
|
74 |
+
row[interventions_df.columns[5]]
|
75 |
+
!= "Intervention prévue dans le futur / Planned future intervention"
|
76 |
+
and village_status
|
77 |
+
== "Critique, Besoin d'aide en urgence / Critical, in urgent need of help"
|
78 |
+
):
|
79 |
+
color_mk = "darkgreen"
|
80 |
+
else:
|
81 |
+
color_mk = "pink"
|
82 |
+
|
83 |
intervention_type = row[interventions_df.columns[6]].split("/")[0].strip()
|
84 |
org = row[interventions_df.columns[1]]
|
85 |
city = row[interventions_df.columns[9]]
|
86 |
date = row[interventions_df.columns[4]]
|
87 |
+
population = row[interventions_df.columns[11]]
|
88 |
+
intervention_info = f"<b>Intervention Status:</b> {status}<br><b>Village Status:</b> {village_status.split('/')[0]}<br><b>Org:</b> {org}<br><b>Intervention:</b> {intervention_type}<br><b>📅 Date:</b> {date}<br><b>📅 Population:</b> {population}"
|
89 |
if row["latlng"] is None:
|
90 |
continue
|
91 |
folium.Marker(
|
|
|
121 |
).add_to(m)
|
122 |
|
123 |
|
|
|
124 |
def display_google_sheet_tables(data_url):
|
125 |
"""Display the google sheet tables for requests and interventions"""
|
126 |
st.markdown(
|
|
|
182 |
st.markdown(
|
183 |
f"To view the full Google Sheet for advanced filtering go to: {data_url} **لعرض الورقة كاملة، اذهب إلى**"
|
184 |
)
|
185 |
+
# if we want to check hidden contact information
|
186 |
+
st.markdown(
|
187 |
+
f"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]",
|
188 |
+
)
|
189 |
+
# arabic needs rtl
|
190 |
+
st.markdown(
|
191 |
+
f"""
|
192 |
+
<div style="text-align: left;">
|
193 |
+
<a href="mailto:[email protected]">[email protected]</a> نحن نخفي معلومات الاتصال لحماية خصوصية الضحايا. إذا كنت جمعية وتريد الاتصال بالضحايا، يرجى الاتصال بنا على
|
194 |
+
</div>
|
195 |
+
""",
|
196 |
+
unsafe_allow_html=True,
|
197 |
+
)
|
198 |
|
199 |
|
200 |
def id_review_submission():
|
201 |
"""Id review submission form"""
|
202 |
st.subheader("🔍 Review of requests")
|
203 |
st.markdown(REVIEW_TEXT)
|
|
|
204 |
|
205 |
id_to_review = st.number_input(
|
206 |
"Enter id / أدخل الرقم", min_value=0, max_value=len(df), value=0, step=1
|
|
|
226 |
|
227 |
# Logo and Title
|
228 |
st.markdown(LOGO, unsafe_allow_html=True)
|
229 |
+
# st.title("Nt3awnou نتعاونو")
|
230 |
st.markdown(SLOGAN, unsafe_allow_html=True)
|
231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
# Load data and initialize map with plugins
|
233 |
df = parse_gg_sheet(REQUESTS_URL)
|
234 |
+
df = add_latlng_col(df, process_column=15)
|
235 |
+
interventions_df = parse_gg_sheet(INTERVENTIONS_URL)
|
236 |
+
interventions_df = add_latlng_col(interventions_df, process_column=12)
|
237 |
m = init_map()
|
238 |
|
239 |
# Selection of requests
|
|
|
246 |
]
|
247 |
selected_options = []
|
248 |
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
|
250 |
+
st.markdown(
|
251 |
+
"👉 **Choose request type | Choissisez le type de demande | اختر نوع الطلب**"
|
252 |
+
)
|
253 |
col1, col2, col3, col4, col5 = st.columns([2, 3, 2, 3, 4])
|
254 |
cols = [col1, col2, col3, col4, col5]
|
255 |
|
|
|
268 |
value=True,
|
269 |
)
|
270 |
|
271 |
+
# Categories of villages
|
272 |
+
|
273 |
+
st.markdown(
|
274 |
+
"👉 **State of villages visited by NGOs| Etat de villages visités par les ONGs | اختر نوع القرى التي زارتها الجمعيات**",
|
275 |
+
unsafe_allow_html=True,
|
276 |
+
)
|
277 |
+
|
278 |
+
|
279 |
+
# use checkboxes
|
280 |
+
col_1, col_2, col_3 = st.columns([1, 1, 1])
|
281 |
+
|
282 |
+
critical_villages = col_1.checkbox(
|
283 |
+
"Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة",
|
284 |
+
value=True,
|
285 |
+
)
|
286 |
+
partially_satisfied_villages = col_2.checkbox(
|
287 |
+
"Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات",
|
288 |
+
value=True,
|
289 |
+
)
|
290 |
+
fully_satisfied_villages = col_3.checkbox(
|
291 |
+
"Fully served / تمت المساعدة بشكل كامل",
|
292 |
+
value=True,
|
293 |
+
)
|
294 |
+
selected_village_types = []
|
295 |
+
|
296 |
+
if critical_villages:
|
297 |
+
selected_village_types.append(
|
298 |
+
"Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة"
|
299 |
+
)
|
300 |
+
|
301 |
+
if partially_satisfied_villages:
|
302 |
+
selected_village_types.append(
|
303 |
+
"Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات"
|
304 |
+
)
|
305 |
+
|
306 |
+
if fully_satisfied_villages:
|
307 |
+
selected_village_types.append("Fully served / تمت المساعدة بشكل كامل")
|
308 |
+
|
309 |
+
status_mapping = {
|
310 |
+
"Critical, in urgent need of help / وضع حرج، في حاجة عاجلة للمساعدة": "Critique, Besoin d'aide en urgence / Critical, in urgent need of help",
|
311 |
+
"Partially served / مساعدة جزئية، بحاجة للمزيد من التدخلات": "Partiellement satisfait / Partially Served",
|
312 |
+
"Fully served / تمت المساعدة بشكل كامل": "Entièrement satisfait / Fully served",
|
313 |
+
}
|
314 |
+
selected_statuses = [status_mapping[status] for status in selected_village_types]
|
315 |
+
|
316 |
if show_interventions:
|
317 |
+
interventions_df = interventions_df.loc[
|
318 |
+
interventions_df[
|
319 |
+
"Etat de la région actuel | Current situation of the area "
|
320 |
+
].isin(selected_statuses)
|
321 |
+
]
|
322 |
display_interventions(interventions_df, m)
|
323 |
|
324 |
# Show requests
|
325 |
show_requests(filtered_df, m)
|
326 |
|
327 |
st_data = st_folium(m, use_container_width=True)
|
328 |
+
tab_ar, tab_en, tab_fr = st.tabs(["العربية", "English", "Français"])
|
329 |
+
|
330 |
+
|
331 |
+
with tab_en:
|
332 |
+
st.markdown(INTRO_TEXT_EN, unsafe_allow_html=True)
|
333 |
+
with tab_ar:
|
334 |
+
st.markdown(INTRO_TEXT_AR, unsafe_allow_html=True)
|
335 |
+
with tab_fr:
|
336 |
+
st.markdown(INTRO_TEXT_FR, unsafe_allow_html=True)
|
337 |
|
|
|
338 |
# Requests table
|
339 |
+
st.divider()
|
340 |
+
st.subheader("📝 **Table of requests / جدول الطلبات**")
|
341 |
drop_cols = [
|
342 |
"(عند الامكان) رقم هاتف شخص موجود في عين المكان",
|
343 |
"الرجاء الضغط على الرابط التالي لمعرفة موقعك إذا كان متاحا",
|
|
|
345 |
"GeoCode",
|
346 |
"GeoAddress",
|
347 |
"Status",
|
348 |
+
"id",
|
349 |
]
|
350 |
display_dataframe(filtered_df, drop_cols, REQUESTS_URL, search_id=True)
|
351 |
|
352 |
# Interventions table
|
353 |
+
st.divider()
|
354 |
st.subheader("📝 **Table of interventions / جدول التدخلات**")
|
355 |
display_dataframe(
|
356 |
interventions_df,
|
357 |
+
[], # We show NGOs contact information
|
358 |
INTERVENTIONS_URL,
|
359 |
search_id=False,
|
360 |
status=True,
|
361 |
)
|
362 |
+
|
363 |
# Submit an id for review
|
364 |
+
st.divider()
|
365 |
id_review_submission()
|
366 |
|
367 |
|