Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
hackathon code for the category and ranking
#29
by
JulesLambert345
- opened
- app.py +22 -0
- src/filter/const.py +45 -0
- src/filter/filter.py +116 -0
- src/ranking/ranking.py +91 -0
app.py
CHANGED
@@ -17,6 +17,9 @@ from src.text_content import (
|
|
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 = (
|
@@ -131,6 +134,7 @@ show_embed_code()
|
|
131 |
show_dataframes_metrics(len_requests, len_interventions, len_solved_verified_requests)
|
132 |
|
133 |
# Verified Requests table
|
|
|
134 |
st.divider()
|
135 |
st.subheader("📝 **Table of verified requests / جدول الطلبات المؤكدة**")
|
136 |
drop_cols = [
|
@@ -147,6 +151,20 @@ display_dataframe(
|
|
147 |
verified_df, drop_cols, VERIFIED_REQUESTS_URL, search_id=True, for_help_requests=True, show_link=False
|
148 |
)
|
149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
# Requests table
|
151 |
st.divider()
|
152 |
st.subheader("📝 **Table of requests / جدول الطلبات**")
|
@@ -161,6 +179,10 @@ drop_cols = [
|
|
161 |
]
|
162 |
display_dataframe(filtered_df, drop_cols, REQUESTS_URL, search_id=True, for_help_requests=True)
|
163 |
|
|
|
|
|
|
|
|
|
164 |
# Interventions table
|
165 |
st.divider()
|
166 |
st.subheader("📝 **Table of interventions / جدول التدخلات**")
|
|
|
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 |
+
from src.filter.filter import add_category
|
21 |
+
from src.filter.filter import HelpCategory
|
22 |
+
from src.ranking.ranking import sort_request
|
23 |
|
24 |
TOKEN = os.environ.get("HF_TOKEN", None)
|
25 |
VERIFIED_REQUESTS_URL = (
|
|
|
134 |
show_dataframes_metrics(len_requests, len_interventions, len_solved_verified_requests)
|
135 |
|
136 |
# Verified Requests table
|
137 |
+
verified_df = add_category(df)
|
138 |
st.divider()
|
139 |
st.subheader("📝 **Table of verified requests / جدول الطلبات المؤكدة**")
|
140 |
drop_cols = [
|
|
|
151 |
verified_df, drop_cols, VERIFIED_REQUESTS_URL, search_id=True, for_help_requests=True, show_link=False
|
152 |
)
|
153 |
|
154 |
+
# Requests table aggregate
|
155 |
+
st.subheader("📝 **Table of aggragate")
|
156 |
+
aggregate = aggregate_locations(verified_df)
|
157 |
+
display_dataframe(
|
158 |
+
aggregate, [], VERIFIED_REQUESTS_URL, search_id=True, for_help_requests=True, show_link=False
|
159 |
+
)
|
160 |
+
|
161 |
+
# Requests table shelter
|
162 |
+
st.subheader("📝 **Table of shelter request")
|
163 |
+
house_request = verified_df[verified_df['Help Details'] == HelpCategory.HOUSE]
|
164 |
+
display_dataframe(
|
165 |
+
house_request, drop_cols, VERIFIED_REQUESTS_URL, search_id=True, for_help_requests=True, show_link=False
|
166 |
+
)
|
167 |
+
|
168 |
# Requests table
|
169 |
st.divider()
|
170 |
st.subheader("📝 **Table of requests / جدول الطلبات**")
|
|
|
179 |
]
|
180 |
display_dataframe(filtered_df, drop_cols, REQUESTS_URL, search_id=True, for_help_requests=True)
|
181 |
|
182 |
+
st.subheader("📝 **Table of sorted requests / جدول الطلبات**")
|
183 |
+
sorted_request = sort_request(filtered_df)
|
184 |
+
display_dataframe(sorted_request, drop_cols, REQUESTS_URL, search_id=True, for_help_requests=True)
|
185 |
+
|
186 |
# Interventions table
|
187 |
st.divider()
|
188 |
st.subheader("📝 **Table of interventions / جدول التدخلات**")
|
src/filter/const.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
PHRASE_NO_PROBLEMS = ['got food',
|
2 |
+
'got food and clothes',
|
3 |
+
'got food and covers']
|
4 |
+
|
5 |
+
KEYS_HOUSE = [
|
6 |
+
"shelters",
|
7 |
+
"mattresses",
|
8 |
+
"pillows",
|
9 |
+
"blankets",
|
10 |
+
"shelter",
|
11 |
+
"tentes",
|
12 |
+
"housing",
|
13 |
+
"couvertures",
|
14 |
+
"tents",
|
15 |
+
"covers",
|
16 |
+
"sdader",
|
17 |
+
"housing_shelter",
|
18 |
+
]
|
19 |
+
KEYS_FOOD = [
|
20 |
+
"groceries",
|
21 |
+
"nouriture",
|
22 |
+
"food",
|
23 |
+
"water",
|
24 |
+
"gaz",
|
25 |
+
"dishes",
|
26 |
+
"oil",
|
27 |
+
"sugar",
|
28 |
+
"tea",
|
29 |
+
"hungry",
|
30 |
+
]
|
31 |
+
KEYS_CLOTHES = [
|
32 |
+
"clothes",
|
33 |
+
"clothing",
|
34 |
+
"hygiene",
|
35 |
+
]
|
36 |
+
KEYS_MEDICAL = [
|
37 |
+
"betadine",
|
38 |
+
"medical",
|
39 |
+
"diabetics",
|
40 |
+
"medicaments",
|
41 |
+
"diabetes",
|
42 |
+
"doliprane",
|
43 |
+
"vitamines",
|
44 |
+
"drugs",
|
45 |
+
]
|
src/filter/filter.py
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from const import KEYS_HOUSE, KEYS_FOOD, KEYS_CLOTHES, KEYS_MEDICAL
|
2 |
+
|
3 |
+
import nltk
|
4 |
+
from nltk.stem import WordNetLemmatizer
|
5 |
+
|
6 |
+
DEGREE_SCORE = {'High': 9, 'Medium': 3, 'Low': 1}
|
7 |
+
|
8 |
+
nltk.download('wordnet')
|
9 |
+
nltk.download('omw-1.4')
|
10 |
+
lemmatizer = WordNetLemmatizer()
|
11 |
+
|
12 |
+
lemmatize_house = [lemmatizer.lemmatize(word) for word in KEYS_HOUSE]
|
13 |
+
lemmatize_food = [lemmatizer.lemmatize(word) for word in KEYS_FOOD]
|
14 |
+
lemmatize_clothes = [lemmatizer.lemmatize(word) for word in KEYS_CLOTHES]
|
15 |
+
lemmatize_medical = [lemmatizer.lemmatize(word) for word in KEYS_MEDICAL]
|
16 |
+
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
from typing import List
|
22 |
+
from enum import Enum
|
23 |
+
|
24 |
+
|
25 |
+
class HelpCategory(Enum):
|
26 |
+
HOUSE = 'house'
|
27 |
+
FOOD = 'food'
|
28 |
+
CLOTHES = 'clothes'
|
29 |
+
MEDICAL = 'medical'
|
30 |
+
UNKNOW = 'unknow'
|
31 |
+
|
32 |
+
|
33 |
+
def to_category(text: str) -> List[HelpCategory]:
|
34 |
+
if text in PHRASE_NO_PROBLEMS:
|
35 |
+
return []
|
36 |
+
|
37 |
+
words = text.split()
|
38 |
+
categories = []
|
39 |
+
for word in words:
|
40 |
+
if word in KEYS_HOUSE:
|
41 |
+
categories.append(HelpCategory.HOUSE)
|
42 |
+
elif word in KEYS_FOOD:
|
43 |
+
categories.append(HelpCategory.FOOD)
|
44 |
+
if word in KEYS_CLOTHES:
|
45 |
+
categories.append(HelpCategory.CLOTHES)
|
46 |
+
if word in KEYS_MEDICAL:
|
47 |
+
categories.append(HelpCategory.MEDICAL)
|
48 |
+
if lemmatizer.lemmatize(word) in lemmatize_house:
|
49 |
+
categories.append(HelpCategory.HOUSE)
|
50 |
+
if lemmatizer.lemmatize(word) in lemmatize_food:
|
51 |
+
categories.append(HelpCategory.FOOD)
|
52 |
+
if lemmatizer.lemmatize(word) in lemmatize_clothes:
|
53 |
+
categories.append(HelpCategory.CLOTHES)
|
54 |
+
if lemmatizer.lemmatize(word) in lemmatize_medical:
|
55 |
+
categories.append(HelpCategory.MEDICAL)
|
56 |
+
if len(categories) == 0:
|
57 |
+
categories = [HelpCategory.UNKNOW]
|
58 |
+
return categories
|
59 |
+
|
60 |
+
|
61 |
+
def clean(text: str) -> str:
|
62 |
+
text = text.replace('Housing/Shelter', 'housing_shelter')
|
63 |
+
text = text.replace('/', ',')
|
64 |
+
text = text.lower()
|
65 |
+
text = text.strip()
|
66 |
+
return text
|
67 |
+
|
68 |
+
|
69 |
+
def to_list(text: str) -> List[str]:
|
70 |
+
helps = text.split(',')
|
71 |
+
helps = [help_string.replace('.', ' ').strip() for help_string in helps]
|
72 |
+
return helps
|
73 |
+
|
74 |
+
|
75 |
+
def help_text_to_help_category(helps: List[str]) -> List[str]:
|
76 |
+
all_categories = set()
|
77 |
+
for help_string in helps:
|
78 |
+
categories = to_category(help_string)
|
79 |
+
all_categories.update(categories)
|
80 |
+
return list(all_categories)
|
81 |
+
|
82 |
+
|
83 |
+
|
84 |
+
|
85 |
+
|
86 |
+
|
87 |
+
def aggregate_degree(degrees):
|
88 |
+
total_score = sum([DEGREE_SCORE[degree] for degree in degrees])
|
89 |
+
if total_score >= 9:
|
90 |
+
return 'High'
|
91 |
+
if total_score >= 3:
|
92 |
+
return 'Medium'
|
93 |
+
else:
|
94 |
+
return 'Low'
|
95 |
+
|
96 |
+
def add_category(df):
|
97 |
+
df['help_category'] = df['Help Details'].apply(clean).apply(to_list).apply(help_text_to_help_category)
|
98 |
+
return df
|
99 |
+
|
100 |
+
|
101 |
+
def aggregate_locations(df):
|
102 |
+
flatten_list = lambda lst: [item for sublist in lst for item in sublist]
|
103 |
+
need = df.groupby('Location Details')['help_category'].apply(list).apply(flatten_list).apply(lambda x: list(set(x)))
|
104 |
+
|
105 |
+
emergency_degree = df.groupby('Location Details')['Emergency Degree'].apply(list).apply(aggregate_degree)
|
106 |
+
|
107 |
+
result = pd.merge(need, emergency_degree, left_index=True, right_index=True)
|
108 |
+
return result
|
109 |
+
|
110 |
+
|
111 |
+
|
112 |
+
|
113 |
+
|
114 |
+
def filter_category(category:HelpCategory, request:pd.DataFrame)-> pd.DataFrame:
|
115 |
+
in_category = request['help_category'].apply(lambda x : category in x)
|
116 |
+
return request[in_category]
|
src/ranking/ranking.py
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import datetime
|
2 |
+
|
3 |
+
def calculate_score(row):
|
4 |
+
current_time = datetime.datetime.now()
|
5 |
+
delta = current_time - row['Horodateur']
|
6 |
+
base_score = delta.total_seconds() / 60
|
7 |
+
|
8 |
+
text_score = get_text_score(row)
|
9 |
+
|
10 |
+
temp_score = get_score_temp(row)
|
11 |
+
|
12 |
+
return base_score + text_score + temp_score
|
13 |
+
|
14 |
+
def get_temp(lat, lon):
|
15 |
+
url = f'https://api.openweathermap.org/data/2.5/forecast?lat={lat}&lon={lon}&appid={API_KEY}'
|
16 |
+
|
17 |
+
response = requests.get(url)
|
18 |
+
|
19 |
+
if response.status_code == 200:
|
20 |
+
data = response.json()
|
21 |
+
temp = sum([single_point['main']['temp_min'] for single_point in data['list']])/40
|
22 |
+
else:
|
23 |
+
print(f'Error: Unable to fetch weather data. Status code: {response.status_code}')
|
24 |
+
return temp
|
25 |
+
|
26 |
+
NEED_COL = 'ما هي احتياجاتك؟ (أضفها إذا لم يتم ذكرها)'
|
27 |
+
COOR_COL = 'هل يمكنك تقديم الإحداثيات الدقيقة للموقع؟ (ادا كنت لا توجد بعين المكان) متلاً \n31.01837503440344, -6.781405948842175'
|
28 |
+
|
29 |
+
def get_text_score(row):
|
30 |
+
score = 0
|
31 |
+
|
32 |
+
need = row[NEED_COL]
|
33 |
+
needs = need.split(' ')
|
34 |
+
if 'وماء' in needs:#water
|
35 |
+
score += 500
|
36 |
+
if 'طعام' in needs:#food
|
37 |
+
score += 500
|
38 |
+
if 'مساعدة طبية' in needs: #medical
|
39 |
+
score += 1000
|
40 |
+
if 'إغاثة' in needs:#secours
|
41 |
+
score+=800
|
42 |
+
if 'لنقود' in needs: #secours
|
43 |
+
score += 800
|
44 |
+
if 'الخيام' in needs: #tent
|
45 |
+
score += 500
|
46 |
+
if 'ولملابس' in needs:#clothes
|
47 |
+
score += 250
|
48 |
+
if 'الأغطية' in needs: #covers
|
49 |
+
score += 250
|
50 |
+
if 'أفرشة' in needs: #matress
|
51 |
+
score+=100
|
52 |
+
|
53 |
+
return score
|
54 |
+
|
55 |
+
def get_score_temp(row):
|
56 |
+
score = 0
|
57 |
+
need = row[NEED_COL]
|
58 |
+
needs = need.split(' ')
|
59 |
+
# tent, clothes or cover
|
60 |
+
if ('الخيام' not in needs) and ('ولملابس' not in needs) and ('الأغطية' not in needs):
|
61 |
+
return score
|
62 |
+
|
63 |
+
|
64 |
+
lat, lon = row[COOR_COL].split(',')
|
65 |
+
lon = lon.strip()
|
66 |
+
lat = lat.strip()
|
67 |
+
|
68 |
+
average_temp = get_temp(lat, lon)
|
69 |
+
if average_temp < 283:
|
70 |
+
score += 1000
|
71 |
+
if average_temp < 273:
|
72 |
+
score += 1000
|
73 |
+
return score
|
74 |
+
|
75 |
+
def sort_request(requests):
|
76 |
+
|
77 |
+
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
78 |
+
requests['Horodateur'].fillna(current_time, inplace=True)
|
79 |
+
|
80 |
+
scores = []
|
81 |
+
for index, row in requests.iterrows():
|
82 |
+
scores.append(calculate_score(row))
|
83 |
+
|
84 |
+
requests['score'] = scores
|
85 |
+
|
86 |
+
requests = requests.sort_values(by='score', ascending=False)
|
87 |
+
|
88 |
+
return requests
|
89 |
+
|
90 |
+
|
91 |
+
|