import dash
from dash import dcc, html, Input, Output
import plotly.graph_objs as go
import requests
import os
from datetime import datetime
# Inline weather_model.py with fixes
def get_weather_data(city, days, api_key):
try:
# Fallback to coordinates if city name fails
city_coords = {
"Hyderabad": {"lat": 17.3850, "lon": 78.4867},
"Gadwal": {"lat": 16.2350, "lon": 77.8050},
"Bengaluru": {"lat": 12.9716, "lon": 77.5946}
}
coords = city_coords.get(city)
if not coords:
geo_url = f"http://api.openweathermap.org/geo/1.0/direct?q={city}&limit=1&appid={api_key}"
geo_response = requests.get(geo_url).json()
if not geo_response:
return None
coords = {"lat": geo_response[0]['lat'], "lon": geo_response[0]['lon']}
url = f"http://api.openweathermap.org/data/2.5/onecall?lat={coords['lat']}&lon={coords['lon']}&exclude=minutely,hourly&units=metric&appid={api_key}"
response = requests.get(url, timeout=10).json()
current = {
'temp': response['current']['temp'],
'weather': response['current']['weather'][0]['description'],
'humidity': response['current']['humidity'],
'wind_speed': response['current']['wind_speed']
}
forecast = []
for i in range(min(days, len(response['daily']))):
day = response['daily'][i]
forecast.append({
'date': datetime.fromtimestamp(day['dt']).strftime('%Y-%m-%d'),
'temp': day['temp']['day'],
'precipitation': day.get('rain', 0) + day.get('snow', 0),
'wind_speed': day['wind_speed'],
'weather': day['weather'][0]['main']
})
return {'current': current, 'forecast': forecast}
except requests.exceptions.RequestException as e:
print(f"Network error for {city}: {e}")
return None
except KeyError as e:
print(f"API response error for {city}: {e}")
return None
except Exception as e:
print(f"Unexpected error for {city}: {e}")
return None
# Initialize Dash app
app = dash.Dash(__name__)
app.title = "Weather Forecast Dashboard"
# Use environment variable for API key
API_KEY = os.getenv("OPENWEATHERMAP_API_KEY", "53d50455f91b6bc3c920959e2954576d")
# Fixed locations
LOCATIONS = ["Hyderabad", "Gadwal", "Bengaluru"]
DAYS = 5 # Fixed 5-day forecast
# Layout
app.layout = html.Div([
html.Div([
html.H1("Weather Forecast Dashboard", style={'textAlign': 'center', 'color': '#FFFFFF'}),
html.P("Current weather for Hyderabad, Gadwal, and Bengaluru (Karnataka).",
style={'textAlign': 'center', 'color': '#D3D9D4'})
], style={'backgroundColor': '#212A31', 'padding': '20px'}),
html.Div([
html.H2("Weather Overview", style={'color': '#FFFFFF', 'padding': '10px'}),
html.Div(id='weather-display', style={'display': 'flex', 'flexWrap': 'wrap', 'justifyContent': 'space-around'})
], style={'backgroundColor': '#2E3944', 'padding': '20px', 'borderRadius': '10px'}),
], style={'backgroundColor': '#1A2329', 'fontFamily': 'Arial', 'minHeight': '100vh'})
# Callback to update dashboard
@app.callback(
Output('weather-display', 'children'),
Input('weather-display', 'id') # Dummy input to trigger on load
)
def update_dashboard(_):
weather_components = []
for city in LOCATIONS:
weather_data = get_weather_data(city, DAYS, API_KEY)
if not weather_data:
weather_components.append(
html.Div(f"Error: Could not fetch data for {city}", style={'color': '#FF5555', 'padding': '10px'})
)
continue
current = weather_data['current']
forecast = weather_data['forecast']
# Text Summary
summary = html.Div([
html.H3(f"{city}", style={'color': '#FFFFFF'}),
html.P(f"Current Temp: {current['temp']}°C", style={'color': '#D3D9D4'}),
html.P(f"Condition: {current['weather']}", style={'color': '#D3D9D4'}),
html.P(f"Humidity: {current['humidity']}%", style={'color': '#D3D9D4'}),
html.P(f"Wind Speed: {current['wind_speed']} km/h", style={'color': '#D3D9D4'}),
], style={'width': '30%', 'padding': '10px'})
# Donut Charts
temp_values = [f['temp'] for f in forecast]
temp_fig = go.Figure(data=[go.Pie(labels=[f['date'] for f in forecast], values=temp_values, hole=.3)])
temp_fig.update_layout(title=f"{city} - Temperature (°C)", template='plotly_dark')
precip_values = [f['precipitation'] for f in forecast]
precip_fig = go.Figure(data=[go.Pie(labels=[f['date'] for f in forecast], values=precip_values, hole=.3)])
precip_fig.update_layout(title=f"{city} - Precipitation (mm)", template='plotly_dark')
wind_values = [f['wind_speed'] for f in forecast]
wind_fig = go.Figure(data=[go.Pie(labels=[f['date'] for f in forecast], values=wind_values, hole=.3)])
wind_fig.update_layout(title=f"{city} - Wind Speed (km/h)", template='plotly_dark')
# Combine into a city section
city_section = html.Div([
summary,
dcc.Graph(figure=temp_fig, style={'width': '20%', 'display': 'inline-block'}),
dcc.Graph(figure=precip_fig, style={'width': '20%', 'display': 'inline-block'}),
dcc.Graph(figure=wind_fig, style={'width': '20%', 'display': 'inline-block'}),
], style={'margin': '20px', 'backgroundColor': '#2E3944', 'borderRadius': '10px', 'padding': '10px'})
weather_components.append(city_section)
return weather_components
# Run server on port 7860 for Hugging Face Spaces
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0', port=7860)