Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -53,7 +53,21 @@ def geocode_address(address):
|
|
53 |
except Exception as e:
|
54 |
return None, None, f"Geocoding error: {str(e)}"
|
55 |
|
56 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
"""Fetch pollen data from Google Pollen API"""
|
58 |
if not GOOGLE_API_KEY:
|
59 |
return "Error: Google API key not found. Please set GOOGLE_API_KEY as a secret."
|
@@ -83,6 +97,16 @@ def get_pollen_data(lat, lon, days=5):
|
|
83 |
if "dailyInfo" in data and len(data["dailyInfo"]) > 0:
|
84 |
print(f"First day info keys: {data['dailyInfo'][0].keys()}")
|
85 |
print(f"Date structure: {data['dailyInfo'][0].get('date', 'No date field')}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
return data
|
88 |
except requests.exceptions.RequestException as e:
|
@@ -177,7 +201,18 @@ def format_pollen_data(data):
|
|
177 |
pollen_type = pollen["code"].replace("_", " ").title()
|
178 |
index_info = pollen.get("indexInfo", {})
|
179 |
index_value = index_info.get("value", 0)
|
180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
|
182 |
if isinstance(index_value, (int, float)) and index_value > max_index:
|
183 |
max_index = index_value
|
@@ -189,10 +224,11 @@ def format_pollen_data(data):
|
|
189 |
"LOW": {"emoji": "🟡", "description": "Good", "advice": "Most people will be fine outdoors"},
|
190 |
"MEDIUM": {"emoji": "🟠", "description": "Moderate", "advice": "Consider taking allergy medication"},
|
191 |
"HIGH": {"emoji": "🔴", "description": "Poor", "advice": "Limit outdoor activities if allergic"},
|
192 |
-
"VERY_HIGH": {"emoji": "🟣", "description": "Very Poor", "advice": "Stay indoors if possible"}
|
|
|
193 |
}
|
194 |
|
195 |
-
severity = severity_map.get(category,
|
196 |
|
197 |
# More specific pollen type descriptions
|
198 |
pollen_descriptions = {
|
@@ -203,11 +239,26 @@ def format_pollen_data(data):
|
|
203 |
|
204 |
pollen_desc = pollen_descriptions.get(pollen_type, f"🌸 {pollen_type}")
|
205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
output.append(f"### {pollen_desc}")
|
207 |
output.append(f"**Level:** {severity['emoji']} {severity['description']} (Index: {index_value}/10)")
|
|
|
208 |
output.append(f"**What this means:** {severity['advice']}")
|
209 |
|
210 |
-
row_data[pollen_type] = f"{severity['description']} ({index_value})"
|
211 |
|
212 |
# Add plant descriptions if available
|
213 |
if "plantDescription" in pollen:
|
@@ -244,15 +295,22 @@ def format_pollen_data(data):
|
|
244 |
|
245 |
# Add comprehensive advice section
|
246 |
output.append("\n## 💡 Practical Tips for Pollen Season")
|
247 |
-
|
248 |
-
output.append("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
output.append("- Use air conditioning with clean HEPA filters")
|
250 |
output.append("- Consider an air purifier for your bedroom")
|
251 |
|
252 |
output.append("\n### 🚶 **When Going Outside:**")
|
253 |
output.append("- Check this forecast before planning outdoor activities")
|
254 |
output.append("- Wear wraparound sunglasses to protect your eyes")
|
255 |
-
output.append("- Consider wearing a mask during very high pollen days")
|
256 |
output.append("- Plan outdoor activities for late evening when pollen counts are lower")
|
257 |
|
258 |
output.append("\n### 🚿 **After Being Outdoors:**")
|
@@ -286,8 +344,14 @@ with gr.Blocks(title="🌸 Pollen Forecast Map", theme=gr.themes.Soft()) as app:
|
|
286 |
gr.HTML("""
|
287 |
<div style="text-align: center; padding: 20px;">
|
288 |
<h1>🌸 Pollen Forecast Map</h1>
|
289 |
-
<p>Get detailed,
|
290 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
</div>
|
292 |
""")
|
293 |
|
@@ -335,9 +399,17 @@ with gr.Blocks(title="🌸 Pollen Forecast Map", theme=gr.themes.Soft()) as app:
|
|
335 |
|
336 |
with gr.Column(scale=2):
|
337 |
# Map display
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
map_html = gr.HTML(
|
339 |
value=create_map(),
|
340 |
-
label="
|
341 |
)
|
342 |
|
343 |
# Location info display
|
|
|
53 |
except Exception as e:
|
54 |
return None, None, f"Geocoding error: {str(e)}"
|
55 |
|
56 |
+
def get_pollen_category_from_index(index_value):
|
57 |
+
"""Convert index value to category when API doesn't provide it"""
|
58 |
+
if not isinstance(index_value, (int, float)):
|
59 |
+
return "UNKNOWN"
|
60 |
+
|
61 |
+
if index_value <= 2.4:
|
62 |
+
return "VERY_LOW"
|
63 |
+
elif index_value <= 4.8:
|
64 |
+
return "LOW"
|
65 |
+
elif index_value <= 7.2:
|
66 |
+
return "MEDIUM"
|
67 |
+
elif index_value <= 9.6:
|
68 |
+
return "HIGH"
|
69 |
+
else:
|
70 |
+
return "VERY_HIGH"
|
71 |
"""Fetch pollen data from Google Pollen API"""
|
72 |
if not GOOGLE_API_KEY:
|
73 |
return "Error: Google API key not found. Please set GOOGLE_API_KEY as a secret."
|
|
|
97 |
if "dailyInfo" in data and len(data["dailyInfo"]) > 0:
|
98 |
print(f"First day info keys: {data['dailyInfo'][0].keys()}")
|
99 |
print(f"Date structure: {data['dailyInfo'][0].get('date', 'No date field')}")
|
100 |
+
|
101 |
+
# Debug pollen info structure
|
102 |
+
if "pollenTypeInfo" in data["dailyInfo"][0]:
|
103 |
+
for pollen in data["dailyInfo"][0]["pollenTypeInfo"]:
|
104 |
+
print(f"Pollen type: {pollen.get('code', 'Unknown')}")
|
105 |
+
if "indexInfo" in pollen:
|
106 |
+
index_info = pollen["indexInfo"]
|
107 |
+
print(f" Index info: {index_info}")
|
108 |
+
print(f" Category: '{index_info.get('category', 'Missing')}'")
|
109 |
+
print(f" Value: {index_info.get('value', 'Missing')}")
|
110 |
|
111 |
return data
|
112 |
except requests.exceptions.RequestException as e:
|
|
|
201 |
pollen_type = pollen["code"].replace("_", " ").title()
|
202 |
index_info = pollen.get("indexInfo", {})
|
203 |
index_value = index_info.get("value", 0)
|
204 |
+
api_category = index_info.get("category", "")
|
205 |
+
|
206 |
+
# Debug: Print what we're getting from the API
|
207 |
+
print(f"Processing {pollen_type}: index={index_value}, api_category='{api_category}'")
|
208 |
+
|
209 |
+
# Use fallback if API category is missing or unknown
|
210 |
+
if api_category and api_category in ["VERY_LOW", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"]:
|
211 |
+
category = api_category
|
212 |
+
else:
|
213 |
+
# Use our fallback function
|
214 |
+
category = get_pollen_category_from_index(index_value)
|
215 |
+
print(f" Using fallback category: {category}")
|
216 |
|
217 |
if isinstance(index_value, (int, float)) and index_value > max_index:
|
218 |
max_index = index_value
|
|
|
224 |
"LOW": {"emoji": "🟡", "description": "Good", "advice": "Most people will be fine outdoors"},
|
225 |
"MEDIUM": {"emoji": "🟠", "description": "Moderate", "advice": "Consider taking allergy medication"},
|
226 |
"HIGH": {"emoji": "🔴", "description": "Poor", "advice": "Limit outdoor activities if allergic"},
|
227 |
+
"VERY_HIGH": {"emoji": "🟣", "description": "Very Poor", "advice": "Stay indoors if possible"},
|
228 |
+
"UNKNOWN": {"emoji": "⚪", "description": "Data Unavailable", "advice": "Monitor symptoms and check again later"}
|
229 |
}
|
230 |
|
231 |
+
severity = severity_map.get(category, severity_map["UNKNOWN"])
|
232 |
|
233 |
# More specific pollen type descriptions
|
234 |
pollen_descriptions = {
|
|
|
239 |
|
240 |
pollen_desc = pollen_descriptions.get(pollen_type, f"🌸 {pollen_type}")
|
241 |
|
242 |
+
# Convert index to approximate grains per cubic meter
|
243 |
+
grains_per_m3 = "Unknown"
|
244 |
+
if isinstance(index_value, (int, float)):
|
245 |
+
if index_value <= 2:
|
246 |
+
grains_per_m3 = f"~{int(index_value * 25)} grains/m³"
|
247 |
+
elif index_value <= 5:
|
248 |
+
grains_per_m3 = f"~{int(50 + (index_value-2) * 33)} grains/m³"
|
249 |
+
elif index_value <= 7:
|
250 |
+
grains_per_m3 = f"~{int(150 + (index_value-5) * 175)} grains/m³"
|
251 |
+
elif index_value <= 9:
|
252 |
+
grains_per_m3 = f"~{int(500 + (index_value-7) * 250)} grains/m³"
|
253 |
+
else:
|
254 |
+
grains_per_m3 = f"~{int(1000 + (index_value-10) * 500)}+ grains/m³"
|
255 |
+
|
256 |
output.append(f"### {pollen_desc}")
|
257 |
output.append(f"**Level:** {severity['emoji']} {severity['description']} (Index: {index_value}/10)")
|
258 |
+
output.append(f"**Scientific Measurement:** {grains_per_m3}")
|
259 |
output.append(f"**What this means:** {severity['advice']}")
|
260 |
|
261 |
+
row_data[pollen_type] = f"{severity['description']} ({index_value}) - {grains_per_m3}"
|
262 |
|
263 |
# Add plant descriptions if available
|
264 |
if "plantDescription" in pollen:
|
|
|
295 |
|
296 |
# Add comprehensive advice section
|
297 |
output.append("\n## 💡 Practical Tips for Pollen Season")
|
298 |
+
|
299 |
+
output.append("### 🔬 **Understanding the Numbers:**")
|
300 |
+
output.append("- **Under 100 grains/m³:** Like having a few specks of dust in a large room")
|
301 |
+
output.append("- **100-500 grains/m³:** Similar to light sawdust in the air - noticeable to sensitive people")
|
302 |
+
output.append("- **500-1000 grains/m³:** Like fine powder in the air - most people will feel it")
|
303 |
+
output.append("- **Over 1000 grains/m³:** Heavy particulate load - breathing through a pollen cloud")
|
304 |
+
|
305 |
+
output.append("\n### 🏠 **Indoor Protection:**")
|
306 |
+
output.append("- Keep windows and doors closed during high pollen days (500+ grains/m³)")
|
307 |
output.append("- Use air conditioning with clean HEPA filters")
|
308 |
output.append("- Consider an air purifier for your bedroom")
|
309 |
|
310 |
output.append("\n### 🚶 **When Going Outside:**")
|
311 |
output.append("- Check this forecast before planning outdoor activities")
|
312 |
output.append("- Wear wraparound sunglasses to protect your eyes")
|
313 |
+
output.append("- Consider wearing a mask during very high pollen days (1000+ grains/m³)")
|
314 |
output.append("- Plan outdoor activities for late evening when pollen counts are lower")
|
315 |
|
316 |
output.append("\n### 🚿 **After Being Outdoors:**")
|
|
|
344 |
gr.HTML("""
|
345 |
<div style="text-align: center; padding: 20px;">
|
346 |
<h1>🌸 Pollen Forecast Map</h1>
|
347 |
+
<p>Get detailed, scientifically-accurate pollen forecasts with actual particle concentrations!</p>
|
348 |
+
<div style="background-color: #e8f5e8; padding: 15px; border-radius: 10px; margin: 15px 0;">
|
349 |
+
<strong>🎯 How to Use:</strong>
|
350 |
+
<br>• <strong>Search by Address:</strong> Type any city, address, or landmark in the search box
|
351 |
+
<br>• <strong>Use Quick Cities:</strong> Click preset buttons for major cities worldwide
|
352 |
+
<br>• <strong>Enter Coordinates:</strong> Input precise latitude/longitude values
|
353 |
+
<br>• <strong>Map Note:</strong> The map displays your location but doesn't support clicking to select new points
|
354 |
+
</div>
|
355 |
</div>
|
356 |
""")
|
357 |
|
|
|
399 |
|
400 |
with gr.Column(scale=2):
|
401 |
# Map display
|
402 |
+
gr.HTML("<h3>🗺️ Location Map</h3>")
|
403 |
+
gr.HTML("""
|
404 |
+
<div style="background-color: #f0f8ff; padding: 10px; border-radius: 5px; margin-bottom: 10px;">
|
405 |
+
<strong>📍 Note:</strong> The map shows your selected location but doesn't support clicking to select new points.
|
406 |
+
Use the address search or coordinate inputs on the left to change locations.
|
407 |
+
</div>
|
408 |
+
""")
|
409 |
+
|
410 |
map_html = gr.HTML(
|
411 |
value=create_map(),
|
412 |
+
label="Current Location"
|
413 |
)
|
414 |
|
415 |
# Location info display
|