Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
@@ -23,7 +23,6 @@ API_KEY = os.getenv('ACCUWEATHER_API_KEY')
|
|
23 |
# Base URL for AccuWeather API
|
24 |
BASE_URL = "http://dataservice.accuweather.com"
|
25 |
|
26 |
-
# Define all the necessary functions
|
27 |
def get_location_key(lat, lon):
|
28 |
url = f"{BASE_URL}/locations/v1/cities/geoposition/search"
|
29 |
params = {
|
@@ -42,20 +41,133 @@ def get_location_key(lat, lon):
|
|
42 |
return None
|
43 |
|
44 |
def get_current_conditions(location_key):
|
45 |
-
|
46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
def get_forecast(location_key):
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
def get_indices(location_key):
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
def get_alerts(location_key):
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
# App layout
|
61 |
app.layout = dbc.Container([
|
@@ -121,10 +233,48 @@ def update_weather(location):
|
|
121 |
|
122 |
lat, lon = location["latitude"], location["longitude"]
|
123 |
|
124 |
-
|
125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
|
127 |
-
|
|
|
128 |
|
129 |
if __name__ == '__main__':
|
130 |
print("Starting the Dash application...")
|
|
|
23 |
# Base URL for AccuWeather API
|
24 |
BASE_URL = "http://dataservice.accuweather.com"
|
25 |
|
|
|
26 |
def get_location_key(lat, lon):
|
27 |
url = f"{BASE_URL}/locations/v1/cities/geoposition/search"
|
28 |
params = {
|
|
|
41 |
return None
|
42 |
|
43 |
def get_current_conditions(location_key):
|
44 |
+
if location_key is None:
|
45 |
+
return None
|
46 |
+
url = f"{BASE_URL}/currentconditions/v1/{location_key}"
|
47 |
+
params = {
|
48 |
+
"apikey": API_KEY,
|
49 |
+
"details": "true",
|
50 |
+
}
|
51 |
+
try:
|
52 |
+
response = requests.get(url, params=params)
|
53 |
+
response.raise_for_status()
|
54 |
+
data = response.json()
|
55 |
+
if not data:
|
56 |
+
raise ValueError("No current conditions data in API response")
|
57 |
+
return data[0]
|
58 |
+
except requests.RequestException as e:
|
59 |
+
print(f"Error in get_current_conditions: {e}")
|
60 |
+
return None
|
61 |
|
62 |
def get_forecast(location_key):
|
63 |
+
if location_key is None:
|
64 |
+
return None
|
65 |
+
url = f"{BASE_URL}/forecasts/v1/daily/5day/{location_key}"
|
66 |
+
params = {
|
67 |
+
"apikey": API_KEY,
|
68 |
+
"metric": "true",
|
69 |
+
}
|
70 |
+
try:
|
71 |
+
response = requests.get(url, params=params)
|
72 |
+
response.raise_for_status()
|
73 |
+
return response.json()
|
74 |
+
except requests.RequestException as e:
|
75 |
+
print(f"Error in get_forecast: {e}")
|
76 |
+
return None
|
77 |
|
78 |
def get_indices(location_key):
|
79 |
+
if location_key is None:
|
80 |
+
return None
|
81 |
+
url = f"{BASE_URL}/indices/v1/daily/5day/{location_key}"
|
82 |
+
params = {
|
83 |
+
"apikey": API_KEY,
|
84 |
+
}
|
85 |
+
try:
|
86 |
+
response = requests.get(url, params=params)
|
87 |
+
response.raise_for_status()
|
88 |
+
return response.json()
|
89 |
+
except requests.RequestException as e:
|
90 |
+
print(f"Error in get_indices: {e}")
|
91 |
+
return None
|
92 |
|
93 |
def get_alerts(location_key):
|
94 |
+
if location_key is None:
|
95 |
+
return None
|
96 |
+
url = f"{BASE_URL}/alerts/v1/{location_key}"
|
97 |
+
params = {
|
98 |
+
"apikey": API_KEY,
|
99 |
+
}
|
100 |
+
try:
|
101 |
+
response = requests.get(url, params=params)
|
102 |
+
response.raise_for_status()
|
103 |
+
return response.json()
|
104 |
+
except requests.RequestException as e:
|
105 |
+
print(f"Error in get_alerts: {e}")
|
106 |
+
return None
|
107 |
+
|
108 |
+
def create_current_weather_card(current):
|
109 |
+
return dbc.Card([
|
110 |
+
dbc.CardBody([
|
111 |
+
html.H4("Current Weather", className="card-title"),
|
112 |
+
html.P(f"Temperature: {current['Temperature']['Metric']['Value']}°C"),
|
113 |
+
html.P(f"Condition: {current['WeatherText']}"),
|
114 |
+
html.P(f"Feels Like: {current['RealFeelTemperature']['Metric']['Value']}°C"),
|
115 |
+
html.P(f"Wind: {current['Wind']['Speed']['Metric']['Value']} km/h"),
|
116 |
+
html.P(f"Humidity: {current['RelativeHumidity']}%"),
|
117 |
+
])
|
118 |
+
], className="mb-4")
|
119 |
+
|
120 |
+
def create_forecast_card(forecast):
|
121 |
+
daily_forecasts = forecast['DailyForecasts']
|
122 |
+
|
123 |
+
fig = go.Figure()
|
124 |
+
|
125 |
+
dates = [datetime.strptime(day['Date'], "%Y-%m-%dT%H:%M:%S%z").strftime("%m-%d") for day in daily_forecasts]
|
126 |
+
max_temps = [day['Temperature']['Maximum']['Value'] for day in daily_forecasts]
|
127 |
+
min_temps = [day['Temperature']['Minimum']['Value'] for day in daily_forecasts]
|
128 |
+
|
129 |
+
fig.add_trace(go.Scatter(x=dates, y=max_temps, name="Max Temp", line=dict(color="red")))
|
130 |
+
fig.add_trace(go.Scatter(x=dates, y=min_temps, name="Min Temp", line=dict(color="blue")))
|
131 |
+
|
132 |
+
fig.update_layout(
|
133 |
+
title="5-Day Temperature Forecast",
|
134 |
+
xaxis_title="Date",
|
135 |
+
yaxis_title="Temperature (°C)",
|
136 |
+
legend_title="Temperature",
|
137 |
+
height=400
|
138 |
+
)
|
139 |
+
|
140 |
+
return dbc.Card([
|
141 |
+
dbc.CardBody([
|
142 |
+
html.H4("5-Day Forecast", className="card-title"),
|
143 |
+
dcc.Graph(figure=fig)
|
144 |
+
])
|
145 |
+
], className="mb-4")
|
146 |
+
|
147 |
+
def create_indices_card(indices):
|
148 |
+
return dbc.Card([
|
149 |
+
dbc.CardBody([
|
150 |
+
html.H4("Weather Indices", className="card-title"),
|
151 |
+
html.Div([
|
152 |
+
html.P(f"{index['Name']}: {index['Category']}")
|
153 |
+
for index in indices[:5] # Display first 5 indices
|
154 |
+
])
|
155 |
+
])
|
156 |
+
], className="mb-4")
|
157 |
+
|
158 |
+
def create_alert_card(alerts):
|
159 |
+
if not alerts:
|
160 |
+
return html.Div()
|
161 |
+
|
162 |
+
return dbc.Card([
|
163 |
+
dbc.CardBody([
|
164 |
+
html.H4("Weather Alerts", className="card-title text-danger"),
|
165 |
+
html.Div([
|
166 |
+
html.P(alert['Text'])
|
167 |
+
for alert in alerts
|
168 |
+
])
|
169 |
+
])
|
170 |
+
], className="mb-4")
|
171 |
|
172 |
# App layout
|
173 |
app.layout = dbc.Container([
|
|
|
233 |
|
234 |
lat, lon = location["latitude"], location["longitude"]
|
235 |
|
236 |
+
loading_output = html.Div([
|
237 |
+
html.P("Loading weather data...", className="text-center"),
|
238 |
+
dbc.Spinner(color="primary", type="grow"),
|
239 |
+
])
|
240 |
+
|
241 |
+
def fetch_weather_data():
|
242 |
+
try:
|
243 |
+
location_key = get_location_key(lat, lon)
|
244 |
+
if location_key is None:
|
245 |
+
raise ValueError("Failed to get location key")
|
246 |
+
|
247 |
+
current = get_current_conditions(location_key)
|
248 |
+
forecast = get_forecast(location_key)
|
249 |
+
indices = get_indices(location_key)
|
250 |
+
alerts = get_alerts(location_key)
|
251 |
+
|
252 |
+
if current is None or forecast is None or indices is None:
|
253 |
+
raise ValueError("Failed to fetch weather data")
|
254 |
+
|
255 |
+
current_weather = create_current_weather_card(current)
|
256 |
+
forecast_output = create_forecast_card(forecast)
|
257 |
+
indices_output = create_indices_card(indices)
|
258 |
+
alert_output = create_alert_card(alerts)
|
259 |
+
|
260 |
+
return current_weather, forecast_output, indices_output, alert_output
|
261 |
+
|
262 |
+
except Exception as e:
|
263 |
+
error_message = f"Error fetching weather data: {str(e)}"
|
264 |
+
print(error_message) # Log the error
|
265 |
+
return "", "", "", html.Div(error_message, className="text-danger")
|
266 |
+
|
267 |
+
# Use threading to fetch data asynchronously
|
268 |
+
thread = threading.Thread(target=fetch_weather_data)
|
269 |
+
thread.start()
|
270 |
+
thread.join(timeout=10) # Wait for up to 10 seconds
|
271 |
+
|
272 |
+
if thread.is_alive():
|
273 |
+
error_message = "Weather data fetch timed out. Please try again."
|
274 |
+
return html.Div(error_message, className="text-warning"), "", "", "", ""
|
275 |
|
276 |
+
current_weather, forecast_output, indices_output, alert_output = fetch_weather_data()
|
277 |
+
return "", current_weather, forecast_output, indices_output, alert_output
|
278 |
|
279 |
if __name__ == '__main__':
|
280 |
print("Starting the Dash application...")
|