Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import requests | |
| from datetime import datetime, timedelta | |
| import pandas as pd | |
| from dotenv import load_dotenv | |
| import os | |
| from PIL import Image | |
| from io import BytesIO | |
| # Load environment variables | |
| load_dotenv() | |
| API_KEY = os.getenv('WEATHER_API_KEY') | |
| BASE_URL = "http://api.weatherapi.com/v1" | |
| # Configure the app | |
| st.set_page_config( | |
| page_title="Weather Dashboard", | |
| page_icon="🌤️", | |
| layout="wide" | |
| ) | |
| # Custom CSS | |
| st.markdown(""" | |
| <style> | |
| .weather-icon { | |
| width: 64px; | |
| height: 64px; | |
| margin: 10px auto; | |
| } | |
| .stMetric { | |
| background-color: rgba(255, 255, 255, 0.1); | |
| padding: 10px; | |
| border-radius: 5px; | |
| } | |
| .main-header { | |
| text-align: center; | |
| color: #1E88E5; | |
| padding: 20px; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| def load_weather_icon(icon_url): | |
| """Load and display weather icon from URL""" | |
| try: | |
| response = requests.get(icon_url) | |
| img = Image.open(BytesIO(response.content)) | |
| return img | |
| except Exception as e: | |
| st.warning(f"Could not load weather icon: {e}") | |
| return None | |
| def get_weather_data(location, is_historical=False, date=None): | |
| """Fetch weather data from the API""" | |
| try: | |
| if is_historical: | |
| endpoint = f"{BASE_URL}/history.json" | |
| params = { | |
| 'key': API_KEY, | |
| 'q': location, | |
| 'dt': date.strftime('%Y-%m-%d') | |
| } | |
| else: | |
| endpoint = f"{BASE_URL}/forecast.json" | |
| params = { | |
| 'key': API_KEY, | |
| 'q': location, | |
| 'days': 1, | |
| 'aqi': 'no' | |
| } | |
| response = requests.get(endpoint, params=params) | |
| response.raise_for_status() | |
| return response.json() | |
| except requests.exceptions.RequestException as e: | |
| st.error(f"Error fetching weather data: {e}") | |
| return None | |
| def display_weather_data(weather_data, selected_datetime, container): | |
| """Display weather data in the specified container""" | |
| if not weather_data: | |
| container.error("No weather data available") | |
| return | |
| container.subheader(f"Date: {selected_datetime.strftime('%Y-%m-%d %H:%M')}") | |
| # Handle both historical and forecast data structure | |
| if 'current' in weather_data: | |
| current_data = weather_data['current'] | |
| else: | |
| historical_hour = min( | |
| weather_data['forecast']['forecastday'][0]['hour'], | |
| key=lambda x: abs(datetime.strptime(x['time'], '%Y-%m-%d %H:%M').time().hour - | |
| selected_datetime.time().hour) | |
| ) | |
| current_data = historical_hour | |
| # Display current weather icon and condition | |
| icon_url = f"https:{current_data['condition']['icon']}" | |
| weather_icon = load_weather_icon(icon_url) | |
| if weather_icon: | |
| col1, col2, col3 = container.columns([1, 2, 1]) | |
| with col2: | |
| st.image(weather_icon, caption=current_data['condition']['text'], use_container_width=True) | |
| # Create metrics in a grid | |
| metric_col1, metric_col2 = container.columns(2) | |
| with metric_col1: | |
| st.metric("Temperature", f"{current_data['temp_c']}°C", | |
| f"Feels like {current_data['feelslike_c']}°C") | |
| st.metric("Wind", f"{current_data['wind_kph']} km/h", | |
| f"Direction: {current_data['wind_dir']}") | |
| with metric_col2: | |
| st.metric("Humidity", f"{current_data['humidity']}%") | |
| st.metric("Pressure", f"{current_data['pressure_mb']} mb") | |
| # Display hourly forecast | |
| container.subheader("Hourly Forecast") | |
| hourly_data = weather_data['forecast']['forecastday'][0]['hour'] | |
| # Create a more visual hourly forecast | |
| hours_to_show = 6 | |
| current_hour = selected_datetime.hour | |
| relevant_hours = [h for h in hourly_data if datetime.strptime(h['time'], '%Y-%m-%d %H:%M').hour >= current_hour][:hours_to_show] | |
| hour_cols = container.columns(min(hours_to_show, len(relevant_hours))) | |
| for hour, col in zip(relevant_hours, hour_cols): | |
| with col: | |
| hour_time = datetime.strptime(hour['time'], '%Y-%m-%d %H:%M').strftime('%I %p') | |
| st.markdown(f"**{hour_time}**") | |
| hour_icon_url = f"https:{hour['condition']['icon']}" | |
| hour_icon = load_weather_icon(hour_icon_url) | |
| if hour_icon: | |
| st.image(hour_icon, use_container_width=True) | |
| st.markdown(f"🌡️ {hour['temp_c']}°C") | |
| st.markdown(f"💧 {hour['chance_of_rain']}%") | |
| st.markdown(f"💨 {hour['wind_kph']} km/h") | |
| # Display detailed hourly data | |
| with container.expander("Detailed Hourly Forecast"): | |
| hourly_df = pd.DataFrame([ | |
| { | |
| 'Time': datetime.strptime(hour['time'], '%Y-%m-%d %H:%M').strftime('%I:%M %p'), | |
| 'Temperature': f"{hour['temp_c']}°C", | |
| 'Condition': hour['condition']['text'], | |
| 'Chance of Rain': f"{hour['chance_of_rain']}%", | |
| 'Wind Speed': f"{hour['wind_kph']} km/h", | |
| 'Humidity': f"{hour['humidity']}%" | |
| } | |
| for hour in hourly_data | |
| ]) | |
| st.dataframe( | |
| hourly_df, | |
| hide_index=True, | |
| use_container_width=True | |
| ) | |
| def main(): | |
| """Main function to run the Streamlit app""" | |
| st.markdown("<h1 class='main-header'>🌤️ Weather Forecast Dashboard</h1>", unsafe_allow_html=True) | |
| # Sidebar inputs | |
| with st.sidebar: | |
| st.header("Settings") | |
| location = st.text_input("Enter Location", "London") | |
| # Date selection | |
| view_type = st.radio("Select View", ["Current & Forecast", "Historical"]) | |
| if view_type == "Historical": | |
| max_date = datetime.now() - timedelta(days=1) | |
| min_date = max_date - timedelta(days=7) | |
| selected_date = st.date_input( | |
| "Select Date", | |
| value=max_date, | |
| min_value=min_date, | |
| max_value=max_date | |
| ) | |
| selected_time = st.time_input("Select Time", datetime.now().time()) | |
| selected_datetime = datetime.combine(selected_date, selected_time) | |
| is_historical = True | |
| else: | |
| selected_datetime = datetime.now() | |
| is_historical = False | |
| if st.button("Get Weather Data"): | |
| with st.spinner("Fetching weather data..."): | |
| weather_data = get_weather_data( | |
| location, | |
| is_historical=is_historical, | |
| date=selected_datetime if is_historical else None | |
| ) | |
| if weather_data: | |
| st.session_state.weather_data = weather_data | |
| st.session_state.selected_datetime = selected_datetime | |
| # Main content area | |
| if 'weather_data' in st.session_state: | |
| display_weather_data( | |
| st.session_state.weather_data, | |
| st.session_state.selected_datetime, | |
| st | |
| ) | |
| else: | |
| st.info("Enter a location and click 'Get Weather Data' to start") | |
| if __name__ == "__main__": | |
| main() |