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)