Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,16 +1,17 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
import os
|
| 3 |
import requests
|
| 4 |
-
from datetime import datetime
|
|
|
|
| 5 |
|
| 6 |
# 1. Page Setup
|
| 7 |
st.set_page_config(page_title="SkyCast Pro", page_icon="☁️", layout="centered")
|
| 8 |
|
| 9 |
-
# 2. Styling (Glassmorphism
|
| 10 |
st.markdown("""
|
| 11 |
<style>
|
| 12 |
.stApp { background-color: #0f172a; }
|
| 13 |
-
h1 { color: white !important; text-align: center; font-weight: 200; letter-spacing: 4px; padding-bottom:
|
| 14 |
.weather-card {
|
| 15 |
background: rgba(255, 255, 255, 0.05);
|
| 16 |
backdrop-filter: blur(10px);
|
|
@@ -21,48 +22,60 @@ st.markdown("""
|
|
| 21 |
text-align: center;
|
| 22 |
margin-top: 20px;
|
| 23 |
}
|
| 24 |
-
.temp-large { font-size: 80px; font-weight: bold; margin:
|
| 25 |
-
.city-name { font-size: 24px; opacity: 0.8; }
|
| 26 |
.details-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 20px; }
|
| 27 |
.detail-item { font-size: 14px; opacity: 0.7; }
|
| 28 |
-
.stTextInput>div>div>input { background: rgba(255,255,255,0.05) !important; color: white !important; border-radius: 12px !important; border: 1px solid rgba(255,255,255,0.2) !important; }
|
| 29 |
</style>
|
| 30 |
""", unsafe_allow_html=True)
|
| 31 |
|
| 32 |
st.title("SKYCAST PRO")
|
| 33 |
|
| 34 |
-
# 3.
|
| 35 |
API_KEY = os.environ.get('Api_key')
|
| 36 |
|
| 37 |
-
@st.cache_data(ttl=300) # 5 minute cache to make it faster
|
| 38 |
def get_weather(city_name):
|
| 39 |
-
if not API_KEY:
|
| 40 |
-
return {"error": "API Key missing in Secrets!"}
|
| 41 |
-
|
| 42 |
-
# solving duplicate city issue: specifying units and limit
|
| 43 |
url = f"https://api.openweathermap.org/data/2.5/weather?q={city_name}&appid={API_KEY}&units=metric"
|
| 44 |
-
|
| 45 |
try:
|
| 46 |
-
|
| 47 |
-
if
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
except:
|
| 54 |
-
return {"error": "Connection Timeout. Please check your internet."}
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
|
|
| 62 |
|
| 63 |
if "error" in data:
|
| 64 |
st.error(data["error"])
|
| 65 |
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
# Extracting Details
|
| 67 |
city = data['name']
|
| 68 |
country = data['sys']['country']
|
|
@@ -72,11 +85,11 @@ if city_query:
|
|
| 72 |
humidity = data['main']['humidity']
|
| 73 |
wind = data['wind']['speed']
|
| 74 |
icon = data['weather'][0]['icon']
|
| 75 |
-
|
| 76 |
-
# Weather Display Card
|
| 77 |
st.markdown(f"""
|
| 78 |
<div class="weather-card">
|
| 79 |
<div class="city-name">{city}, {country}</div>
|
|
|
|
| 80 |
<img src="http://openweathermap.org/img/wn/{icon}@2x.png" alt="icon">
|
| 81 |
<div class="temp-large">{temp}°C</div>
|
| 82 |
<div style="font-size: 18px; margin-bottom: 10px;">{desc}</div>
|
|
@@ -94,13 +107,13 @@ if city_query:
|
|
| 94 |
<div style="color: white; font-size: 18px;">{wind} m/s</div>
|
| 95 |
</div>
|
| 96 |
<div class="detail-item">
|
| 97 |
-
<div>
|
| 98 |
-
<div style="color: white; font-size: 18px;">
|
| 99 |
</div>
|
| 100 |
</div>
|
| 101 |
</div>
|
| 102 |
""", unsafe_allow_html=True)
|
| 103 |
else:
|
| 104 |
-
st.info("
|
| 105 |
|
| 106 |
-
st.markdown("<
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import os
|
| 3 |
import requests
|
| 4 |
+
from datetime import datetime, timedelta
|
| 5 |
+
import pytz
|
| 6 |
|
| 7 |
# 1. Page Setup
|
| 8 |
st.set_page_config(page_title="SkyCast Pro", page_icon="☁️", layout="centered")
|
| 9 |
|
| 10 |
+
# 2. Styling (Glassmorphism)
|
| 11 |
st.markdown("""
|
| 12 |
<style>
|
| 13 |
.stApp { background-color: #0f172a; }
|
| 14 |
+
h1 { color: white !important; text-align: center; font-weight: 200; letter-spacing: 4px; padding-bottom: 10px; }
|
| 15 |
.weather-card {
|
| 16 |
background: rgba(255, 255, 255, 0.05);
|
| 17 |
backdrop-filter: blur(10px);
|
|
|
|
| 22 |
text-align: center;
|
| 23 |
margin-top: 20px;
|
| 24 |
}
|
| 25 |
+
.temp-large { font-size: 80px; font-weight: bold; margin: 5px 0; color: #38bdf8; }
|
| 26 |
+
.city-name { font-size: 24px; opacity: 0.8; margin-bottom: 5px; }
|
| 27 |
.details-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 20px; }
|
| 28 |
.detail-item { font-size: 14px; opacity: 0.7; }
|
|
|
|
| 29 |
</style>
|
| 30 |
""", unsafe_allow_html=True)
|
| 31 |
|
| 32 |
st.title("SKYCAST PRO")
|
| 33 |
|
| 34 |
+
# 3. API Logic
|
| 35 |
API_KEY = os.environ.get('Api_key')
|
| 36 |
|
|
|
|
| 37 |
def get_weather(city_name):
|
| 38 |
+
if not API_KEY: return {"error": "API Key missing!"}
|
|
|
|
|
|
|
|
|
|
| 39 |
url = f"https://api.openweathermap.org/data/2.5/weather?q={city_name}&appid={API_KEY}&units=metric"
|
|
|
|
| 40 |
try:
|
| 41 |
+
r = requests.get(url, timeout=10)
|
| 42 |
+
return r.json() if r.status_code == 200 else {"error": "City not found"}
|
| 43 |
+
except: return {"error": "Connection error"}
|
| 44 |
+
|
| 45 |
+
# 4. Search & Dropdown (Duplicate City Fix)
|
| 46 |
+
# Humne common cities ke options de diye hain taaki confusion na ho
|
| 47 |
+
search_mode = st.radio("Search Method", ["Direct Search", "Quick Select"], horizontal=True)
|
|
|
|
|
|
|
| 48 |
|
| 49 |
+
selected_city = ""
|
| 50 |
+
if search_mode == "Quick Select":
|
| 51 |
+
city_options = {
|
| 52 |
+
"Hyderabad, Pakistan": "Hyderabad,PK",
|
| 53 |
+
"Hyderabad, India": "Hyderabad,IN",
|
| 54 |
+
"Karachi, Pakistan": "Karachi,PK",
|
| 55 |
+
"Mumbai, India": "Mumbai,IN",
|
| 56 |
+
"London, UK": "London,GB",
|
| 57 |
+
"New York, USA": "New York,US"
|
| 58 |
+
}
|
| 59 |
+
choice = st.selectbox("Choose a City:", list(city_options.keys()))
|
| 60 |
+
selected_city = city_options[choice]
|
| 61 |
+
else:
|
| 62 |
+
selected_city = st.text_input("Search Location", placeholder="e.g. Hyderabad,PK")
|
| 63 |
|
| 64 |
+
# 5. Result Display
|
| 65 |
+
if selected_city:
|
| 66 |
+
with st.spinner("Fetching data..."):
|
| 67 |
+
data = get_weather(selected_city)
|
| 68 |
|
| 69 |
if "error" in data:
|
| 70 |
st.error(data["error"])
|
| 71 |
else:
|
| 72 |
+
# 6. CALCULATING LOCAL TIME
|
| 73 |
+
# OpenWeather gives timezone offset in seconds from UTC
|
| 74 |
+
timezone_offset = data['timezone']
|
| 75 |
+
utc_now = datetime.now(pytz.utc)
|
| 76 |
+
local_time = utc_now + timedelta(seconds=timezone_offset)
|
| 77 |
+
formatted_time = local_time.strftime('%H:%M | %A')
|
| 78 |
+
|
| 79 |
# Extracting Details
|
| 80 |
city = data['name']
|
| 81 |
country = data['sys']['country']
|
|
|
|
| 85 |
humidity = data['main']['humidity']
|
| 86 |
wind = data['wind']['speed']
|
| 87 |
icon = data['weather'][0]['icon']
|
| 88 |
+
|
|
|
|
| 89 |
st.markdown(f"""
|
| 90 |
<div class="weather-card">
|
| 91 |
<div class="city-name">{city}, {country}</div>
|
| 92 |
+
<div style="font-size: 14px; color: #38bdf8;">Local Time: {formatted_time}</div>
|
| 93 |
<img src="http://openweathermap.org/img/wn/{icon}@2x.png" alt="icon">
|
| 94 |
<div class="temp-large">{temp}°C</div>
|
| 95 |
<div style="font-size: 18px; margin-bottom: 10px;">{desc}</div>
|
|
|
|
| 107 |
<div style="color: white; font-size: 18px;">{wind} m/s</div>
|
| 108 |
</div>
|
| 109 |
<div class="detail-item">
|
| 110 |
+
<div>STATUS</div>
|
| 111 |
+
<div style="color: white; font-size: 18px;">Live Sync</div>
|
| 112 |
</div>
|
| 113 |
</div>
|
| 114 |
</div>
|
| 115 |
""", unsafe_allow_html=True)
|
| 116 |
else:
|
| 117 |
+
st.info("Search bar mein city aur country code likhen (e.g. Hyderabad,PK)")
|
| 118 |
|
| 119 |
+
st.markdown("<p style='text-align:center; opacity:0.3; margin-top:50px;'>SkyCast Pro | Powered by OpenWeather</p>", unsafe_allow_html=True)
|