bluenevus commited on
Commit
b301494
·
verified ·
1 Parent(s): f1faee5

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +218 -0
app.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dash
2
+ from dash import dcc, html, Input, Output, State
3
+ import dash_bootstrap_components as dbc
4
+ import plotly.graph_objs as go
5
+ import requests
6
+ import pandas as pd
7
+ from datetime import datetime
8
+ import os
9
+ from dotenv import load_dotenv
10
+ import threading
11
+
12
+ # Load environment variables
13
+ load_dotenv()
14
+
15
+ # Initialize the Dash app
16
+ app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
17
+ server = app.server
18
+
19
+ # AccuWeather API key
20
+ API_KEY = os.getenv('ACCUWEATHER_API_KEY')
21
+
22
+ # Base URL for AccuWeather API
23
+ BASE_URL = "http://dataservice.accuweather.com"
24
+
25
+ def get_location_key(lat, lon):
26
+ url = f"{BASE_URL}/locations/v1/cities/geoposition/search"
27
+ params = {
28
+ "apikey": API_KEY,
29
+ "q": f"{lat},{lon}",
30
+ }
31
+ response = requests.get(url, params=params)
32
+ data = response.json()
33
+ return data["Key"]
34
+
35
+ def get_current_conditions(location_key):
36
+ url = f"{BASE_URL}/currentconditions/v1/{location_key}"
37
+ params = {
38
+ "apikey": API_KEY,
39
+ "details": "true",
40
+ }
41
+ response = requests.get(url, params=params)
42
+ return response.json()[0]
43
+
44
+ def get_forecast(location_key):
45
+ url = f"{BASE_URL}/forecasts/v1/daily/5day/{location_key}"
46
+ params = {
47
+ "apikey": API_KEY,
48
+ "metric": "true",
49
+ }
50
+ response = requests.get(url, params=params)
51
+ return response.json()
52
+
53
+ def get_indices(location_key):
54
+ url = f"{BASE_URL}/indices/v1/daily/5day/{location_key}"
55
+ params = {
56
+ "apikey": API_KEY,
57
+ }
58
+ response = requests.get(url, params=params)
59
+ return response.json()
60
+
61
+ def get_alerts(location_key):
62
+ url = f"{BASE_URL}/alerts/v1/{location_key}"
63
+ params = {
64
+ "apikey": API_KEY,
65
+ }
66
+ response = requests.get(url, params=params)
67
+ return response.json()
68
+
69
+ # App layout
70
+ app.layout = dbc.Container([
71
+ dbc.Row([
72
+ dbc.Col([
73
+ html.H1("Weather Dashboard", className="text-center mb-4"),
74
+ html.Div(id="loading-output"),
75
+ html.Div(id="alert-output"),
76
+ dbc.Row([
77
+ dbc.Col([
78
+ html.Div(id="current-weather-output"),
79
+ ], width=6),
80
+ dbc.Col([
81
+ html.Div(id="forecast-output"),
82
+ ], width=6),
83
+ ]),
84
+ html.Div(id="indices-output"),
85
+ ], width=12)
86
+ ]),
87
+ dcc.Store(id="location-store"),
88
+ dcc.Interval(id="location-interval", interval=1000, max_intervals=1),
89
+ ], fluid=True, className="mt-4")
90
+
91
+ @app.callback(
92
+ Output("location-store", "data"),
93
+ Input("location-interval", "n_intervals")
94
+ )
95
+ def update_location(n):
96
+ return {"latitude": 0, "longitude": 0} # Replace with actual browser location data
97
+
98
+ @app.callback(
99
+ [Output("loading-output", "children"),
100
+ Output("current-weather-output", "children"),
101
+ Output("forecast-output", "children"),
102
+ Output("indices-output", "children"),
103
+ Output("alert-output", "children")],
104
+ Input("location-store", "data")
105
+ )
106
+ def update_weather(location):
107
+ if not location:
108
+ return "Waiting for location data...", "", "", "", ""
109
+
110
+ lat, lon = location["latitude"], location["longitude"]
111
+
112
+ loading_output = html.Div([
113
+ html.P("Loading weather data...", className="text-center"),
114
+ dbc.Spinner(color="primary", type="grow"),
115
+ ])
116
+
117
+ def fetch_weather_data():
118
+ nonlocal loading_output
119
+ try:
120
+ location_key = get_location_key(lat, lon)
121
+ current = get_current_conditions(location_key)
122
+ forecast = get_forecast(location_key)
123
+ indices = get_indices(location_key)
124
+ alerts = get_alerts(location_key)
125
+
126
+ current_weather = create_current_weather_card(current)
127
+ forecast_output = create_forecast_card(forecast)
128
+ indices_output = create_indices_card(indices)
129
+ alert_output = create_alert_card(alerts)
130
+
131
+ loading_output = ""
132
+
133
+ return current_weather, forecast_output, indices_output, alert_output
134
+
135
+ except Exception as e:
136
+ loading_output = html.Div(f"Error fetching weather data: {str(e)}", className="text-danger")
137
+ return "", "", "", ""
138
+
139
+ # Use threading to fetch data asynchronously
140
+ thread = threading.Thread(target=fetch_weather_data)
141
+ thread.start()
142
+ thread.join(timeout=10) # Wait for up to 10 seconds
143
+
144
+ if thread.is_alive():
145
+ loading_output = html.Div("Weather data fetch timed out. Please try again.", className="text-warning")
146
+ return loading_output, "", "", "", ""
147
+
148
+ current_weather, forecast_output, indices_output, alert_output = fetch_weather_data()
149
+ return loading_output, current_weather, forecast_output, indices_output, alert_output
150
+
151
+ def create_current_weather_card(current):
152
+ return dbc.Card([
153
+ dbc.CardBody([
154
+ html.H4("Current Weather", className="card-title"),
155
+ html.P(f"Temperature: {current['Temperature']['Metric']['Value']}°C"),
156
+ html.P(f"Condition: {current['WeatherText']}"),
157
+ html.P(f"Feels Like: {current['RealFeelTemperature']['Metric']['Value']}°C"),
158
+ html.P(f"Wind: {current['Wind']['Speed']['Metric']['Value']} km/h"),
159
+ html.P(f"Humidity: {current['RelativeHumidity']}%"),
160
+ ])
161
+ ], className="mb-4")
162
+
163
+ def create_forecast_card(forecast):
164
+ daily_forecasts = forecast['DailyForecasts']
165
+
166
+ fig = go.Figure()
167
+
168
+ dates = [datetime.strptime(day['Date'], "%Y-%m-%dT%H:%M:%S%z").strftime("%m-%d") for day in daily_forecasts]
169
+ max_temps = [day['Temperature']['Maximum']['Value'] for day in daily_forecasts]
170
+ min_temps = [day['Temperature']['Minimum']['Value'] for day in daily_forecasts]
171
+
172
+ fig.add_trace(go.Scatter(x=dates, y=max_temps, name="Max Temp", line=dict(color="red")))
173
+ fig.add_trace(go.Scatter(x=dates, y=min_temps, name="Min Temp", line=dict(color="blue")))
174
+
175
+ fig.update_layout(
176
+ title="5-Day Temperature Forecast",
177
+ xaxis_title="Date",
178
+ yaxis_title="Temperature (°C)",
179
+ legend_title="Temperature",
180
+ height=400
181
+ )
182
+
183
+ return dbc.Card([
184
+ dbc.CardBody([
185
+ html.H4("5-Day Forecast", className="card-title"),
186
+ dcc.Graph(figure=fig)
187
+ ])
188
+ ], className="mb-4")
189
+
190
+ def create_indices_card(indices):
191
+ return dbc.Card([
192
+ dbc.CardBody([
193
+ html.H4("Weather Indices", className="card-title"),
194
+ html.Div([
195
+ html.P(f"{index['Name']}: {index['Category']}")
196
+ for index in indices[:5] # Display first 5 indices
197
+ ])
198
+ ])
199
+ ], className="mb-4")
200
+
201
+ def create_alert_card(alerts):
202
+ if not alerts:
203
+ return html.Div()
204
+
205
+ return dbc.Card([
206
+ dbc.CardBody([
207
+ html.H4("Weather Alerts", className="card-title text-danger"),
208
+ html.Div([
209
+ html.P(alert['Text'])
210
+ for alert in alerts
211
+ ])
212
+ ])
213
+ ], className="mb-4")
214
+
215
+ if __name__ == '__main__':
216
+ print("Starting the Dash application...")
217
+ app.run(debug=True, host='0.0.0.0', port=7860)
218
+ print("Dash application has finished running.")