Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,167 +1,133 @@
|
|
1 |
import gradio as gr
|
2 |
import requests
|
3 |
import os
|
|
|
4 |
|
5 |
# Your Google Pollen API key should be set as a secret in your Hugging Face Space
|
6 |
API_KEY = os.environ.get("GOOGLE_API_KEY")
|
7 |
|
8 |
-
# ---
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
|
|
17 |
def get_pollen_data(latitude, longitude):
|
18 |
"""
|
19 |
Fetches and formats all available pollen data from the Google Pollen API.
|
|
|
20 |
"""
|
21 |
if not API_KEY:
|
22 |
-
error_message = "Error: GOOGLE_API_KEY not found. Please set it as a secret
|
23 |
-
|
24 |
-
return error_message, error_message, error_message
|
25 |
|
26 |
if not latitude or not longitude:
|
27 |
-
|
28 |
-
return "", "", ""
|
29 |
|
30 |
try:
|
31 |
lat = float(latitude)
|
32 |
lon = float(longitude)
|
33 |
except (ValueError, TypeError):
|
34 |
error_message = "Error: Invalid latitude or longitude."
|
35 |
-
return error_message, error_message, error_message
|
36 |
|
37 |
endpoint = "https://pollen.googleapis.com/v1/forecast:lookup"
|
38 |
-
params = {
|
39 |
-
"key": API_KEY,
|
40 |
-
"location.latitude": lat,
|
41 |
-
"location.longitude": lon,
|
42 |
-
"days": 5,
|
43 |
-
"languageCode": "en"
|
44 |
-
}
|
45 |
|
46 |
try:
|
47 |
response = requests.get(endpoint, params=params)
|
48 |
response.raise_for_status()
|
49 |
data = response.json()
|
|
|
50 |
|
51 |
if not data.get('dailyInfo'):
|
52 |
-
no_data_message = "No pollen data found for this location
|
53 |
-
return no_data_message, no_data_message, no_data_message
|
54 |
|
55 |
-
# Initialize strings for each pollen category tab
|
56 |
outputs = {'TREE': "", 'GRASS': "", 'WEED': ""}
|
57 |
-
|
58 |
for day_info in data.get('dailyInfo', []):
|
59 |
date = day_info.get('date', {})
|
60 |
date_str = f"{date.get('year', 'N/A')}-{date.get('month', 'N/A'):02d}-{date.get('day', 'N/A'):02d}"
|
61 |
|
62 |
-
# Add date header to each category for the current day
|
63 |
for cat in outputs.keys():
|
64 |
outputs[cat] += f"## Date: {date_str}\n"
|
65 |
|
66 |
pollen_found_for_day = {'TREE': False, 'GRASS': False, 'WEED': False}
|
67 |
|
68 |
-
# Process every pollen type returned by the API for the day
|
69 |
for pollen in day_info.get('pollenTypeInfo', []):
|
70 |
plant_type = pollen.get('plantType', 'UNKNOWN')
|
71 |
-
if plant_type not in outputs:
|
72 |
-
continue
|
73 |
|
74 |
pollen_found_for_day[plant_type] = True
|
75 |
|
76 |
display_name = pollen.get('displayName', 'N/A')
|
77 |
-
in_season_str = "Yes" if pollen.get('inSeason', False) else "No"
|
78 |
-
|
79 |
-
# Start formatting the detailed output for this pollen type
|
80 |
-
formatted_pollen_info = f"### {display_name}\n"
|
81 |
-
formatted_pollen_info += f"- **In Season:** {in_season_str}\n"
|
82 |
-
|
83 |
-
# Extract and display all details from indexInfo
|
84 |
index_info = pollen.get('indexInfo', {})
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
description = index_info.get('description', '')
|
89 |
-
color = index_info.get('color', '#FFFFFF')
|
90 |
-
color_swatch = f'<span style="display: inline-block; width: 15px; height: 15px; background-color: {color}; border: 1px solid #ccc; border-radius: 3px; vertical-align: middle;"></span>'
|
91 |
-
|
92 |
-
formatted_pollen_info += f"- **Index Value:** {index_value}\n"
|
93 |
-
formatted_pollen_info += f"- **Category:** {color_swatch} {category}\n"
|
94 |
-
if description:
|
95 |
-
formatted_pollen_info += f"- **Description:** *{description}*\n"
|
96 |
|
97 |
-
|
98 |
-
|
99 |
-
if health_recs:
|
100 |
-
formatted_pollen_info += "- **Health Recommendations:**\n"
|
101 |
-
for rec in health_recs:
|
102 |
-
formatted_pollen_info += f" - {rec}\n"
|
103 |
-
|
104 |
-
outputs[plant_type] += formatted_pollen_info + "\n---\n" # Add a separator
|
105 |
|
106 |
-
# If after checking all pollen types, a category had none, add a message
|
107 |
for p_type, found in pollen_found_for_day.items():
|
108 |
if not found:
|
109 |
-
outputs[p_type] += "- No specific pollen data
|
110 |
|
111 |
-
|
112 |
-
return outputs['TREE'].strip(), outputs['GRASS'].strip(), outputs['WEED'].strip()
|
113 |
|
114 |
-
except requests.exceptions.RequestException as e:
|
115 |
-
error_message = f"Error connecting to the API: {e}"
|
116 |
-
return error_message, error_message, error_message
|
117 |
except Exception as e:
|
118 |
-
error_message = f"An
|
119 |
-
return error_message, error_message, error_message
|
120 |
|
121 |
# --- Gradio Interface ---
|
122 |
-
with gr.Blocks(theme=gr.themes.Soft()
|
123 |
-
gr.Markdown("# 🤧
|
124 |
-
gr.Markdown("
|
125 |
|
126 |
with gr.Row():
|
127 |
-
with gr.Column(scale=2):
|
128 |
-
# Use the native Gradio Map component
|
129 |
-
map_component = gr.Map(label="Location Map", value={"latitude": 45.6770, "longitude": -111.0429}, interactive=True)
|
130 |
-
|
131 |
with gr.Column(scale=1):
|
132 |
-
lat_input = gr.Textbox(label="Latitude",
|
133 |
-
lon_input = gr.Textbox(label="Longitude",
|
|
|
134 |
gr.Examples(
|
135 |
-
examples=[
|
136 |
-
["40.7128", "-74.0060"], # New York, NY
|
137 |
-
["34.0522", "-118.2437"], # Los Angeles,CA
|
138 |
-
["51.5074", "-0.1278"], # London, UK
|
139 |
-
],
|
140 |
inputs=[lat_input, lon_input],
|
141 |
label="Example Locations"
|
142 |
)
|
|
|
|
|
|
|
143 |
|
144 |
-
with gr.Tabs()
|
145 |
with gr.TabItem("🌳 Tree"):
|
146 |
tree_output = gr.Markdown()
|
147 |
with gr.TabItem("🌱 Grass"):
|
148 |
grass_output = gr.Markdown()
|
149 |
with gr.TabItem("🌿 Weed"):
|
150 |
weed_output = gr.Markdown()
|
151 |
-
|
152 |
-
# --- Event Listeners ---
|
153 |
-
|
154 |
-
# 1. When a user clicks the map, update the latitude and longitude textboxes.
|
155 |
-
map_component.select(handle_map_select, None, [lat_input, lon_input])
|
156 |
-
|
157 |
-
# 2. When the latitude or longitude textboxes change (either from map click or manual entry),
|
158 |
-
# automatically call the pollen API.
|
159 |
-
lat_input.change(get_pollen_data, [lat_input, lon_input], [tree_output, grass_output, weed_output])
|
160 |
-
lon_input.change(get_pollen_data, [lat_input, lon_input], [tree_output, grass_output, weed_output])
|
161 |
-
|
162 |
-
# 3. When the app loads, get data for the default location.
|
163 |
-
demo.load(get_pollen_data, [lat_input, lon_input], [tree_output, grass_output, weed_output])
|
164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
|
166 |
if __name__ == "__main__":
|
167 |
demo.launch()
|
|
|
1 |
import gradio as gr
|
2 |
import requests
|
3 |
import os
|
4 |
+
import folium
|
5 |
|
6 |
# Your Google Pollen API key should be set as a secret in your Hugging Face Space
|
7 |
API_KEY = os.environ.get("GOOGLE_API_KEY")
|
8 |
|
9 |
+
# --- Map Function ---
|
10 |
+
def create_map_html(latitude, longitude):
|
11 |
+
"""Creates a Folium map and returns its HTML representation."""
|
12 |
+
try:
|
13 |
+
lat = float(latitude)
|
14 |
+
lon = float(longitude)
|
15 |
+
# Create a map centered on the coordinates
|
16 |
+
m = folium.Map(location=[lat, lon], zoom_start=12, tiles="OpenStreetMap")
|
17 |
+
# Add a marker to the map
|
18 |
+
folium.Marker([lat, lon], popup="Selected Location").add_to(m)
|
19 |
+
return m._repr_html_()
|
20 |
+
except (ValueError, TypeError):
|
21 |
+
# Return a default map if inputs are invalid or empty
|
22 |
+
m = folium.Map(location=[40.7128, -74.0060], zoom_start=5, tiles="OpenStreetMap")
|
23 |
+
return m._repr_html_()
|
24 |
|
25 |
+
# --- API Call Function ---
|
26 |
def get_pollen_data(latitude, longitude):
|
27 |
"""
|
28 |
Fetches and formats all available pollen data from the Google Pollen API.
|
29 |
+
Also returns an updated map.
|
30 |
"""
|
31 |
if not API_KEY:
|
32 |
+
error_message = "Error: GOOGLE_API_KEY not found. Please set it as a secret."
|
33 |
+
map_html = create_map_html(latitude, longitude)
|
34 |
+
return error_message, error_message, error_message, map_html
|
35 |
|
36 |
if not latitude or not longitude:
|
37 |
+
return "", "", "", create_map_html(latitude, longitude)
|
|
|
38 |
|
39 |
try:
|
40 |
lat = float(latitude)
|
41 |
lon = float(longitude)
|
42 |
except (ValueError, TypeError):
|
43 |
error_message = "Error: Invalid latitude or longitude."
|
44 |
+
return error_message, error_message, error_message, create_map_html(latitude, longitude)
|
45 |
|
46 |
endpoint = "https://pollen.googleapis.com/v1/forecast:lookup"
|
47 |
+
params = {"key": API_KEY, "location.latitude": lat, "location.longitude": lon, "days": 5, "languageCode": "en"}
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
try:
|
50 |
response = requests.get(endpoint, params=params)
|
51 |
response.raise_for_status()
|
52 |
data = response.json()
|
53 |
+
map_html = create_map_html(latitude, longitude)
|
54 |
|
55 |
if not data.get('dailyInfo'):
|
56 |
+
no_data_message = "No pollen data found for this location."
|
57 |
+
return no_data_message, no_data_message, no_data_message, map_html
|
58 |
|
|
|
59 |
outputs = {'TREE': "", 'GRASS': "", 'WEED': ""}
|
|
|
60 |
for day_info in data.get('dailyInfo', []):
|
61 |
date = day_info.get('date', {})
|
62 |
date_str = f"{date.get('year', 'N/A')}-{date.get('month', 'N/A'):02d}-{date.get('day', 'N/A'):02d}"
|
63 |
|
|
|
64 |
for cat in outputs.keys():
|
65 |
outputs[cat] += f"## Date: {date_str}\n"
|
66 |
|
67 |
pollen_found_for_day = {'TREE': False, 'GRASS': False, 'WEED': False}
|
68 |
|
|
|
69 |
for pollen in day_info.get('pollenTypeInfo', []):
|
70 |
plant_type = pollen.get('plantType', 'UNKNOWN')
|
71 |
+
if plant_type not in outputs: continue
|
|
|
72 |
|
73 |
pollen_found_for_day[plant_type] = True
|
74 |
|
75 |
display_name = pollen.get('displayName', 'N/A')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
index_info = pollen.get('indexInfo', {})
|
77 |
+
category = index_info.get('category', 'N/A')
|
78 |
+
color = index_info.get('color', '#FFFFFF')
|
79 |
+
color_swatch = f'<span style="display: inline-block; width: 15px; height: 15px; background-color: {color}; border: 1px solid #ccc; vertical-align: middle;"></span>'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
+
formatted_pollen_info = f"### {display_name}\n- **Category:** {color_swatch} {category}\n"
|
82 |
+
outputs[plant_type] += formatted_pollen_info + "\n---\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
|
|
|
84 |
for p_type, found in pollen_found_for_day.items():
|
85 |
if not found:
|
86 |
+
outputs[p_type] += "- No specific pollen data returned for this category on this day.\n\n---\n"
|
87 |
|
88 |
+
return outputs['TREE'].strip(), outputs['GRASS'].strip(), outputs['WEED'].strip(), map_html
|
|
|
89 |
|
|
|
|
|
|
|
90 |
except Exception as e:
|
91 |
+
error_message = f"An error occurred: {e}"
|
92 |
+
return error_message, error_message, error_message, create_map_html(latitude, longitude)
|
93 |
|
94 |
# --- Gradio Interface ---
|
95 |
+
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
96 |
+
gr.Markdown("# 🤧 Pollen Forecast Map")
|
97 |
+
gr.Markdown("Enter coordinates and click 'Get Forecast' to see the 5-day pollen forecast and the location on the map.")
|
98 |
|
99 |
with gr.Row():
|
|
|
|
|
|
|
|
|
100 |
with gr.Column(scale=1):
|
101 |
+
lat_input = gr.Textbox(label="Latitude", value="40.7128")
|
102 |
+
lon_input = gr.Textbox(label="Longitude", value="-74.0060")
|
103 |
+
submit_button = gr.Button("Get Forecast", variant="primary")
|
104 |
gr.Examples(
|
105 |
+
examples=[["34.0522", "-118.2437"], ["51.5074", "-0.1278"]],
|
|
|
|
|
|
|
|
|
106 |
inputs=[lat_input, lon_input],
|
107 |
label="Example Locations"
|
108 |
)
|
109 |
+
|
110 |
+
with gr.Column(scale=2):
|
111 |
+
map_output = gr.HTML(label="Location Map")
|
112 |
|
113 |
+
with gr.Tabs():
|
114 |
with gr.TabItem("🌳 Tree"):
|
115 |
tree_output = gr.Markdown()
|
116 |
with gr.TabItem("🌱 Grass"):
|
117 |
grass_output = gr.Markdown()
|
118 |
with gr.TabItem("🌿 Weed"):
|
119 |
weed_output = gr.Markdown()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
+
submit_button.click(
|
122 |
+
fn=get_pollen_data,
|
123 |
+
inputs=[lat_input, lon_input],
|
124 |
+
outputs=[tree_output, grass_output, weed_output, map_output]
|
125 |
+
)
|
126 |
+
demo.load(
|
127 |
+
fn=get_pollen_data,
|
128 |
+
inputs=[lat_input, lon_input],
|
129 |
+
outputs=[tree_output, grass_output, weed_output, map_output]
|
130 |
+
)
|
131 |
|
132 |
if __name__ == "__main__":
|
133 |
demo.launch()
|