# app.py import streamlit as st import pandas as pd import requests import urllib3 import base64 import requests from pathlib import Path from datetime import datetime from requests.exceptions import RequestException from urllib.parse import quote urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # ----------------------------- # App Config # ----------------------------- st.set_page_config( page_title="Weather Wear", page_icon="☀️", layout="wide" ) # ----------------------------- # Navbar / Header # ----------------------------- st.markdown( """ """, unsafe_allow_html=True ) # ----------------------------- # Nav-bar # ----------------------------- nav_left, nav_right = st.columns([5, 1]) def get_base64_image(image_path): image_bytes = Path(image_path).read_bytes() return base64.b64encode(image_bytes).decode() logo_base64 = get_base64_image("ww_logo.png") nav_left, nav_right = st.columns([5, 1]) with nav_left: st.markdown( f"""
Weather Wear Logo
Weather Wear
""", unsafe_allow_html=True ) # -------------------------- # OPEN BUTTON # -------------------------- col1, col2 = st.columns([10, 1]) with nav_right: if "chat_open" not in st.session_state: st.session_state.chat_open = False if st.button("💬 Chat Assistant"): st.session_state.chat_open = not st.session_state.chat_open # ----------------------------- # Weather Code Mapping # ----------------------------- WEATHER_CODES = { 0: "Sunny", 1: "Mostly Sunny", 2: "Partly Cloudy", 3: "Cloudy", 45: "Foggy", 48: "Foggy", 51: "Light Rain", 53: "Rainy", 55: "Rainy", 61: "Light Rain", 63: "Rainy", 65: "Heavy Rain", 71: "Snowy", 73: "Snowy", 75: "Heavy Snow", 80: "Rainy", 81: "Rainy", 82: "Heavy Rain", 95: "Stormy", 96: "Stormy", 99: "Stormy" } # ----------------------------- # API Transformer Class # ----------------------------- class WeatherTransformer: def __init__(self): self.api_key = st.secrets["OPENWEATHER_API_KEY"] def get_coordinates(self, location): geo_url = "https://api.openweathermap.org/geo/1.0/direct" params = { "q": location, "limit": 1, "appid": self.api_key } try: response = requests.get(geo_url, params=params, timeout=15) response.raise_for_status() data = response.json() if not data: return None result = data[0] return { "name": result.get("name", location), "country": result.get("country", ""), "latitude": result["lat"], "longitude": result["lon"] } except RequestException as error: st.error("Could not fetch location data.") st.caption(f"Technical details: {error}") return None def fetch_weather(self, latitude, longitude): weather_url = "https://api.openweathermap.org/data/2.5/weather" params = { "lat": latitude, "lon": longitude, "appid": self.api_key, "units": "metric" } try: response = requests.get(weather_url, params=params, timeout=15) response.raise_for_status() return response.json() except RequestException as error: st.error("Could not fetch weather data.") st.caption(f"Technical details: {error}") return None def transform_weather_data(self, location_info, weather_data): weather_main = weather_data["weather"][0]["main"] weather_description = weather_data["weather"][0]["description"] main = weather_data["main"] wind = weather_data.get("wind", {}) df = pd.DataFrame([{ "location": location_info["name"], "country": location_info["country"], "latitude": location_info["latitude"], "longitude": location_info["longitude"], "temperature": main["temp"], "feels_like": main["feels_like"], "humidity": main["humidity"], "weather_condition": normalize_weather(weather_main).title(), "weather_description": weather_description.title(), "wind_speed": wind.get("speed", 0), "fetched_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") }]) return df def get_weather_dataframe(self, location): location_info = self.get_coordinates(location) if location_info is None: return None weather_data = self.fetch_weather( location_info["latitude"], location_info["longitude"] ) if weather_data is None: return None weather_df = self.transform_weather_data(location_info, weather_data) weather_df.to_csv("weather_data.csv", index=False) return weather_df # ----------------------------- # Helper Functions # ----------------------------- def normalize_weather(condition): condition = str(condition).lower() if "thunderstorm" in condition or "storm" in condition: return "stormy" if "rain" in condition or "drizzle" in condition: return "rainy" if "clear" in condition or "sun" in condition: return "sunny" if "cloud" in condition: return "cloudy" if "snow" in condition: return "snowy" if "mist" in condition or "fog" in condition or "haze" in condition: return "foggy" return condition def load_outfit_dataset(file_path): df = pd.read_csv(file_path) df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_") return df def recommend_outfit(outfit_df, weather_condition, style): weather_key = normalize_weather(weather_condition) df = outfit_df.copy() df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_") required_columns = [ "weather_condition", "style", "top", "bottom", "footwear", "accessory", "outerwear", "notes" ] missing_columns = [col for col in required_columns if col not in df.columns] if missing_columns: st.error(f"Missing columns in dataset: {missing_columns}") return pd.DataFrame() df["weather_condition"] = df["weather_condition"].astype(str).str.lower() df["style"] = df["style"].astype(str).str.lower() filtered = df[ (df["weather_condition"].str.contains(weather_key, na=False)) & (df["style"] == style.lower()) ] return filtered # ----------------------------- # Main App # ----------------------------- # Weather consoles input_col, style_col = st.columns([1, 1]) with input_col: location = st.text_input("Enter Location", value="Delhi") with style_col: style = st.selectbox( "Choose Outfit Style", ["Casual", "Formal", "Sporty", "Party", "Traditional"] ) left_space, button_col, right_space = st.columns([2, 1, 2]) with button_col: search_button = st.button("Fetch Weather", use_container_width=True) st.subheader("Weather Based Outfit Recommender") outfit_file = "outfit_recommendations.csv" try: outfit_df = load_outfit_dataset(outfit_file) except FileNotFoundError: st.error("Could not find outfit_recommendations.csv. Place it in the same folder as app.py.") st.stop() if search_button: st.session_state.weather_loaded = True st.session_state["weather_api_failed"] = False transformer = WeatherTransformer() with st.spinner("Fetching weather data..."): weather_df = transformer.get_weather_dataframe(location) if weather_df is None: if st.session_state.get("weather_api_failed"): st.stop() st.error("Location not found. Please enter a valid city or place name.") st.stop() weather = weather_df.iloc[0] if "weather_data" not in st.session_state: st.session_state.weather_data = None if "weather_loaded" not in st.session_state: st.session_state.weather_loaded = False st.session_state.weather_data = weather.to_dict() st.session_state.weather_loaded = True st.session_state["style"] = style current_temperature = float(weather["temperature"]) col1, col2, col3, col4 = st.columns(4) col1.metric("Location", f"{weather['location']}, {weather['country']}") col2.metric("Weather", weather["weather_condition"]) col3.metric("Temperature", f"{current_temperature} °C") col4.metric("Humidity", f"{weather['humidity']}%") temp_chart_df = pd.DataFrame({ "Weather Info": ["Current Temperature"], "Temperature °C": [current_temperature] }) # Create recommendations before trying to display them recommendations = recommend_outfit( outfit_df=outfit_df, weather_condition=weather["weather_condition"], style=style ) st.write("### Outfit Suggestions") if recommendations.empty: st.warning("No exact outfit match found for this weather, temperature, and style.") else: for _, row in recommendations.head(1).iterrows(): st.session_state["recommended_outfit"] = { "top": row["top"], "bottom": row["bottom"], "footwear": row["footwear"], "accessory": row["accessory"], "outerwear": row["outerwear"], "notes": row["notes"] } st.success("Recommended Outfit") st.write(f"**Top:** {row['top']}") st.write(f"**Bottom:** {row['bottom']}") st.write(f"**Footwear:** {row['footwear']}") st.write(f"**Accessory:** {row['accessory']}") st.write(f"**Outerwear:** {row['outerwear']}") st.write(f"**Notes:** {row['notes']}") st.divider() else: st.info("Enter a location, choose your style, and click Get Recommendation.") if st.session_state.get("weather_loaded", False): weather = st.session_state.weather_data if "weather" not in st.session_state: st.session_state.weather = None weather = st.session_state.weather if st.session_state.weather: st.write(st.session_state.weather) # show metrics # ------------------ # ------------------ # AI Chat-bot # ------------------ import streamlit as st import requests from openai import OpenAI from google import genai client = OpenAI( base_url="http://localhost:11434/v1", api_key="ollama" ) # -------------------------- # SESSION STATES # -------------------------- if "chat_open" not in st.session_state: st.session_state.chat_open = False if "messages" not in st.session_state: st.session_state.messages = [] if "provider" not in st.session_state: st.session_state.provider = "Ollama" # -------------------------- # AI FUNCTIONS # -------------------------- st.markdown(""" """, unsafe_allow_html=True) # ------------------------ def ask_ollama(prompt, model): try: r = requests.post( "http://localhost:11434/api/generate", json={ "model": model, "prompt": prompt, "stream": False } ) return r.json()["response"] except Exception as e: return str(e) def ask_openai(prompt, api_key): try: client = OpenAI(api_key=api_key) response = client.chat.completions.create( model="gpt-4.1-mini", messages=[ {"role": "user", "content": prompt} ] ) return response.choices[0].message.content except Exception as e: return str(e) def ask_gemini(prompt, api_key): client = genai.Client(api_key=api_key) response = client.models.generate_content( model="gemini-2.5-flash", contents=prompt ) return response.text # -------------------------- # CHAT POPUP # -------------------------- if st.session_state.chat_open: with st.container(border=True, key="mobile_chat_box"): top1, top2 = st.columns([8, 1]) with top1: st.markdown("### AI Assistant") with top2: if st.button("✕"): st.session_state.chat_open = False st.rerun() provider = st.selectbox( "Provider", ["Ollama", "Gemini", "OpenAI"], key="provider" ) if provider == "Ollama": model = st.text_input( "Model", "llama3", key="ollama_model" ) elif provider == "Gemini": st.text_input( "Gemini Key", type="password", key="api_key" ) else: st.text_input( "OpenAI Key", type="password", key="api_key" ) st.divider() for msg in st.session_state.messages: with st.chat_message(msg["role"]): st.write(msg["content"]) prompt = st.chat_input( "Ask anything..." ) if prompt: st.session_state.messages.append( { "role": "user", "content": prompt } ) with st.chat_message("user"): st.write(prompt) with st.spinner("Thinking..."): if provider == "Ollama": answer = ask_ollama( prompt, st.session_state.ollama_model ) elif provider == "Gemini": answer = ask_gemini( prompt, st.session_state.api_key ) else: answer = ask_openai( prompt, st.session_state.api_key ) st.session_state.messages.append( { "role": "assistant", "content": answer } ) st.rerun()