uumerrr684 commited on
Commit
c83153b
·
verified ·
1 Parent(s): ed9b147

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -327
app.py CHANGED
@@ -1,33 +1,33 @@
 
 
 
1
  import gradio as gr
2
  import requests
3
  import os
4
- from datetime import datetime
 
 
 
 
5
 
6
- API_KEY = os.getenv("OPENWEATHER_API_KEYY")
7
- BASE_URL = "http://api.openweathermap.org/data/2.5/weather"
8
 
9
  def get_weather(city):
10
  try:
11
  if not API_KEY:
12
  raise ValueError("API key not configured")
13
-
14
- params = {
15
- "q": city,
16
- "appid": API_KEY,
17
- "units": "metric"
18
- }
19
-
20
  res = requests.get(BASE_URL, params=params, timeout=10)
21
  res.raise_for_status()
22
  data = res.json()
23
-
24
  temp = data["main"]["temp"]
25
  condition = data["weather"][0]["description"].capitalize()
26
  humidity = data["main"]["humidity"]
27
  wind_speed = data.get("wind", {}).get("speed", 0)
28
-
29
- # Weather icon mapping
30
- weather_id = data["weather"][0]["icon"]
31
  icon_map = {
32
  "01d": "☀️", "01n": "🌙", "02d": "⛅", "02n": "⛅",
33
  "03d": "☁️", "03n": "☁️", "04d": "☁️", "04n": "☁️",
@@ -35,340 +35,81 @@ def get_weather(city):
35
  "11d": "⛈️", "11n": "⛈️", "13d": "🌨️", "13n": "🌨️",
36
  "50d": "🌫️", "50n": "🌫️"
37
  }
38
- icon = icon_map.get(weather_id, "🌤️")
39
-
40
- # Generate hourly forecast (text only)
41
  hourly = [
42
- f"{datetime.now().strftime('%H:%M')} → {round(temp + (i - 2))}°C"
43
  for i in range(6)
44
  ]
45
-
46
  return temp, condition, humidity, wind_speed, icon, hourly, city
47
-
48
  except Exception as e:
49
- return f"Error: {str(e)}", "", "", "", "❌", [], city
 
 
 
50
 
51
  def create_weather_display(temp, condition, humidity, wind_speed, icon, hourly, city):
52
- """Create beautiful weather display HTML"""
53
- if isinstance(temp, str) and "Error" in temp:
54
- # Error case
55
- return f"""
56
- <div style="
57
- background: linear-gradient(135deg, #2b2b2b 0%, #3a3a3a 100%);
58
- padding: 40px;
59
- border-radius: 24px;
60
- box-shadow: 0 0 40px rgba(203,77,11,0.2);
61
- color: white;
62
- font-family: 'Inter', 'SF Pro Display', sans-serif;
63
- text-align: center;
64
- border: 1px solid rgba(203,77,11,0.2);
65
- ">
66
- <div style="font-size: 80px; margin-bottom: 20px;"></div>
67
- <h2 style="color: rgb(203,77,11); margin: 0;">{temp}</h2>
68
- <p style="color: #ccc; margin-top: 10px;">Please check your city name and API key</p>
69
- </div>
70
- """
71
-
72
- # Format temperature
73
- temp_display = f"{round(temp)}" if isinstance(temp, (int, float)) else temp
74
-
75
- # Create main weather display
76
- main_display = f"""
77
- <div style="
78
- background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%);
79
- padding: 48px;
80
- border-radius: 24px;
81
- box-shadow: 0 0 50px rgba(203,77,11,0.15), 0 20px 40px rgba(0,0,0,0.3);
82
- color: white;
83
- font-family: 'Inter', 'SF Pro Display', sans-serif;
84
- margin: 24px 0;
85
- border: 1px solid rgba(203,77,11,0.2);
86
- backdrop-filter: blur(20px);
87
- ">
88
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 36px;">
89
- <h2 style="color: rgb(203,77,11); font-size: 32px; margin: 0; font-weight: 700; letter-spacing: -0.5px;">
90
- 🌦 Weather Wizard
91
- </h2>
92
- <div style="
93
- color: white;
94
- font-size: 28px;
95
- font-weight: 600;
96
- background: linear-gradient(135deg, rgba(203,77,11,0.2) 0%, rgba(255,140,60,0.1) 100%);
97
- padding: 12px 24px;
98
- border-radius: 16px;
99
- border: 1px solid rgba(203,77,11,0.3);
100
- ">
101
- 📍 {city.title()}
102
- </div>
103
- </div>
104
-
105
- <div style="display: flex; justify-content: space-between; align-items: center;">
106
- <div style="flex: 1;">
107
- <h1 style="
108
- font-size: 84px;
109
- margin: 0;
110
- font-weight: 200;
111
- background: linear-gradient(135deg, white 0%, rgba(203,77,11,0.8) 100%);
112
- -webkit-background-clip: text;
113
- -webkit-text-fill-color: transparent;
114
- background-clip: text;
115
- letter-spacing: -2px;
116
- ">{temp_display}°C</h1>
117
- <p style="font-size: 28px; margin: 12px 0 0 0; color: #e0e0e0; font-weight: 500;">{condition}</p>
118
- <div style="margin-top: 32px; display: flex; gap: 48px; font-size: 20px;">
119
- <div style="
120
- display: flex;
121
- align-items: center;
122
- gap: 12px;
123
- background: rgba(203,77,11,0.1);
124
- padding: 12px 20px;
125
- border-radius: 12px;
126
- border: 1px solid rgba(203,77,11,0.2);
127
- ">
128
- <span style="font-size: 24px;">💨</span>
129
- <span style="font-weight: 600;">{wind_speed} m/s</span>
130
- </div>
131
- <div style="
132
- display: flex;
133
- align-items: center;
134
- gap: 12px;
135
- background: rgba(203,77,11,0.1);
136
- padding: 12px 20px;
137
- border-radius: 12px;
138
- border: 1px solid rgba(203,77,11,0.2);
139
- ">
140
- <span style="font-size: 24px;">💧</span>
141
- <span style="font-weight: 600;">{humidity}%</span>
142
- </div>
143
- </div>
144
- </div>
145
- <div style="flex: 1; text-align: center;">
146
- <div style="
147
- font-size: 140px;
148
- margin: 20px 0;
149
- filter: drop-shadow(0 0 20px rgba(203,77,11,0.3));
150
- ">{icon}</div>
151
- </div>
152
- </div>
153
  </div>
154
  """
155
-
156
- # Create hourly forecast
157
- hourly_html = ""
158
  if hourly:
159
  hourly_items = ""
160
  for forecast in hourly:
161
- # Extract temp and time from the format "HH:MM XXX°C"
162
- parts = forecast.split(' ')
163
- time_part = parts[0] if len(parts) > 0 else ""
164
- temp_part = parts[1].replace('°C', '°') if len(parts) > 1 else ""
165
-
166
- hourly_items += f"""
167
- <div style="
168
- text-align: center;
169
- flex: 1;
170
- padding: 20px 10px;
171
- background: linear-gradient(135deg, rgba(203,77,11,0.1) 0%, rgba(255,140,60,0.05) 100%);
172
- border-radius: 16px;
173
- margin: 0 4px;
174
- border: 1px solid rgba(203,77,11,0.2);
175
- transition: all 0.3s ease;
176
- backdrop-filter: blur(10px);
177
- ">
178
- <div style="
179
- font-size: 22px;
180
- font-weight: 700;
181
- margin-bottom: 12px;
182
- color: white;
183
- background: linear-gradient(135deg, white 0%, rgb(203,77,11) 100%);
184
- -webkit-background-clip: text;
185
- -webkit-text-fill-color: transparent;
186
- background-clip: text;
187
- ">
188
- {temp_part}
189
- </div>
190
- <div style="font-size: 16px; color: #ccc; font-weight: 500;">
191
- {time_part}
192
- </div>
193
- </div>
194
- """
195
-
196
- hourly_html = f"""
197
- <div style="
198
- background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%);
199
- padding: 36px;
200
- border-radius: 24px;
201
- box-shadow: 0 0 50px rgba(203,77,11,0.15), 0 20px 40px rgba(0,0,0,0.3);
202
- color: white;
203
- font-family: 'Inter', 'SF Pro Display', sans-serif;
204
- margin-top: 24px;
205
- border: 1px solid rgba(203,77,11,0.2);
206
- backdrop-filter: blur(20px);
207
- ">
208
- <h3 style="
209
- margin: 0 0 24px 0;
210
- color: rgb(203,77,11);
211
- font-size: 24px;
212
- font-weight: 700;
213
- letter-spacing: -0.5px;
214
- ">📊 Hourly Forecast</h3>
215
- <div style="display: flex; gap: 8px; justify-content: space-between;">
216
- {hourly_items}
217
- </div>
218
- </div>
219
- """
220
-
221
- return main_display + hourly_html
222
 
223
- # Custom CSS for 2025 orange theme
224
  custom_css = """
225
- body, .gradio-container {
226
- background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%) !important;
227
- color: white !important;
228
- font-family: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif !important;
229
- }
230
-
231
- /* Modern search bar styling */
232
- .search-container input {
233
- background: linear-gradient(135deg, rgba(203,77,11,0.1) 0%, rgba(255,140,60,0.05) 100%) !important;
234
- color: white !important;
235
- border: 2px solid rgba(203,77,11,0.3) !important;
236
- border-radius: 16px !important;
237
- padding: 16px 24px !important;
238
- font-size: 18px !important;
239
- font-weight: 500 !important;
240
- backdrop-filter: blur(10px) !important;
241
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
242
- box-shadow: 0 8px 32px rgba(203,77,11,0.1) !important;
243
- }
244
-
245
- .search-container input:focus {
246
- border-color: rgb(203,77,11) !important;
247
- box-shadow: 0 0 0 4px rgba(203,77,11,0.2), 0 12px 40px rgba(203,77,11,0.15) !important;
248
- background: linear-gradient(135deg, rgba(203,77,11,0.15) 0%, rgba(255,140,60,0.08) 100%) !important;
249
- transform: translateY(-1px) !important;
250
- }
251
-
252
- .search-container input::placeholder {
253
- color: rgba(255,255,255,0.6) !important;
254
- font-weight: 400 !important;
255
- }
256
-
257
- /* 2025 Modern Button */
258
- .modern-button {
259
- background: linear-gradient(135deg, rgb(203,77,11) 0%, #ff6b35 100%) !important;
260
- border: none !important;
261
- padding: 16px 32px !important;
262
- border-radius: 16px !important;
263
- font-weight: 600 !important;
264
- font-size: 16px !important;
265
- letter-spacing: 0.5px !important;
266
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
267
- box-shadow: 0 8px 32px rgba(203,77,11,0.25) !important;
268
- position: relative !important;
269
- overflow: hidden !important;
270
- color: white !important;
271
- }
272
-
273
- .modern-button:hover {
274
- transform: translateY(-3px) !important;
275
- box-shadow: 0 16px 40px rgba(203,77,11,0.4) !important;
276
- background: linear-gradient(135deg, #e8550d 0%, #ff7c47 100%) !important;
277
- }
278
-
279
- .modern-button:active {
280
- transform: translateY(-1px) !important;
281
- }
282
-
283
- .gradio-html {
284
- background: transparent !important;
285
- }
286
-
287
- /* Enhanced container styling */
288
- .gradio-container {
289
- background: radial-gradient(ellipse at top, rgba(203,77,11,0.1) 0%, transparent 70%) !important;
290
- }
291
  """
292
 
293
- # Create Gradio interface
294
  with gr.Blocks(css=custom_css, title="Weather Wizard", theme=gr.themes.Glass()) as app:
295
  gr.HTML("""
296
- <div style="
297
- text-align: center;
298
- padding: 32px;
299
- background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
300
- border-bottom: 1px solid rgba(203,77,11,0.2);
301
- ">
302
- <h1 style="
303
- color: rgb(203,77,11);
304
- font-size: 42px;
305
- margin: 0;
306
- font-family: 'Inter', 'SF Pro Display', sans-serif;
307
- font-weight: 800;
308
- letter-spacing: -1px;
309
- background: linear-gradient(135deg, rgb(203,77,11) 0%, #ff8c3c 100%);
310
- -webkit-background-clip: text;
311
- -webkit-text-fill-color: transparent;
312
- background-clip: text;
313
- ">
314
- 🌦️ Weather Wizard
315
- </h1>
316
- <p style="
317
- color: rgba(255,255,255,0.7);
318
- font-size: 20px;
319
- margin: 12px 0 0 0;
320
- font-weight: 400;
321
- letter-spacing: 0.5px;
322
- ">
323
- AI-powered weather forecasts for the modern world
324
- </p>
325
  </div>
326
  """)
327
-
328
  with gr.Column(elem_classes=["search-section"]):
329
- city = gr.Textbox(
330
- label="",
331
- placeholder="Search any city worldwide... (e.g. New York, Tokyo, London)",
332
- container=False,
333
- elem_classes=["search-container"],
334
- show_label=False
335
- )
336
- btn = gr.Button(
337
- "✨ Discover Weather",
338
- variant="primary",
339
- size="lg",
340
- elem_classes=["modern-button"]
341
- )
342
-
343
- # Weather Display
344
  weather_display = gr.HTML()
345
-
346
- def update_weather_display(city):
347
- if not city.strip():
348
- city = "London" # Default city
349
-
350
- temp, condition, humidity, wind_speed, icon, hourly, city_name = get_weather(city.strip())
351
- weather_html = create_weather_display(temp, condition, humidity, wind_speed, icon, hourly, city_name)
352
- return weather_html
353
-
354
- # Event handlers
355
- btn.click(
356
- fn=update_weather_display,
357
- inputs=city,
358
- outputs=weather_display
359
- )
360
-
361
- city.submit(
362
- fn=update_weather_display,
363
- inputs=city,
364
- outputs=weather_display
365
- )
366
-
367
- # Load default weather on startup
368
- app.load(
369
- fn=lambda: update_weather_display("London"),
370
- outputs=weather_display
371
- )
372
 
373
  if __name__ == "__main__":
374
- app.launch()
 
1
+ # weather_wizard_app.py
2
+ # A fully responsive Gradio Weather Wizard app using OpenWeatherMap API
3
+
4
  import gradio as gr
5
  import requests
6
  import os
7
+ from datetime import datetime, timedelta
8
+
9
+ # Environment variables
10
+ API_KEY = os.getenv("OPENWEATHER_API_KEYY") # ensure your key name matches exactly
11
+ BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
12
 
13
+ # Function to fetch weather data
 
14
 
15
  def get_weather(city):
16
  try:
17
  if not API_KEY:
18
  raise ValueError("API key not configured")
19
+ params = {"q": city, "appid": API_KEY, "units": "metric"}
 
 
 
 
 
 
20
  res = requests.get(BASE_URL, params=params, timeout=10)
21
  res.raise_for_status()
22
  data = res.json()
23
+
24
  temp = data["main"]["temp"]
25
  condition = data["weather"][0]["description"].capitalize()
26
  humidity = data["main"]["humidity"]
27
  wind_speed = data.get("wind", {}).get("speed", 0)
28
+ icon_code = data["weather"][0]["icon"]
29
+
30
+ # Map OpenWeatherMap icon codes to emojis
31
  icon_map = {
32
  "01d": "☀️", "01n": "🌙", "02d": "⛅", "02n": "⛅",
33
  "03d": "☁️", "03n": "☁️", "04d": "☁️", "04n": "☁️",
 
35
  "11d": "⛈️", "11n": "⛈️", "13d": "🌨️", "13n": "🌨️",
36
  "50d": "🌫️", "50n": "🌫️"
37
  }
38
+ icon = icon_map.get(icon_code, "🌤️")
39
+
40
+ # Generate 6-hour forecast with exact hour steps
41
  hourly = [
42
+ f"{(datetime.now().replace(minute=0, second=0) + timedelta(hours=i)).strftime('%H:%M')} → {round(temp + (i - 2))}°C"
43
  for i in range(6)
44
  ]
45
+
46
  return temp, condition, humidity, wind_speed, icon, hourly, city
 
47
  except Exception as e:
48
+ return f"Error: {e}", "", "", "", "❌", [], city
49
+
50
+
51
+ # Function to create HTML display
52
 
53
  def create_weather_display(temp, condition, humidity, wind_speed, icon, hourly, city):
54
+ # Error case
55
+ if isinstance(temp, str) and temp.startswith("Error"):
56
+ return f"<div style='text-align:center;padding:32px;background:#2b2b2b;border-radius:24px;color:#f66;font-family:Inter;'>❌ {temp}</div>"
57
+
58
+ temp_disp = f"{round(temp)}°C" if isinstance(temp, (int, float)) else temp
59
+
60
+ # Main weather card
61
+ html = f"""
62
+ <div style="background:linear-gradient(135deg,#1a1a1a 0%,#2a2a2a 100%);padding:24px;border-radius:24px;box-shadow:0 0 50px rgba(203,77,11,0.15);color:white;font-family:'Inter',sans-serif;">
63
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:24px;flex-wrap:wrap;">
64
+ <h2 style="color:rgb(203,77,11);margin:0;font-size:24px;">🌦️ Weather Wizard</h2>
65
+ <div style="background:rgba(203,77,11,0.2);padding:8px 16px;border-radius:16px;">📍 {city.title()}</div>
66
+ </div>
67
+ <div style="display:flex;align-items:center;gap:32px;flex-wrap:wrap;">
68
+ <div><div style="font-size:64px;font-weight:200;background:linear-gradient(135deg,white,rgba(203,77,11,0.8));-webkit-background-clip:text;-webkit-text-fill-color:transparent;">{temp_disp}</div><p style="margin:8px 0;color:#ccc;">{condition}</p></div>
69
+ <div style="font-size:96px;filter:drop-shadow(0 0 20px rgba(203,77,11,0.3));">{icon}</div>
70
+ </div>
71
+ <div style="display:flex;gap:24px;margin-top:24px;">
72
+ <div style="display:flex;align-items:center;gap:8px;">💨 {wind_speed} m/s</div>
73
+ <div style="display:flex;align-items:center;gap:8px;">💧 {humidity}%</div>
74
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  </div>
76
  """
77
+ # Hourly forecast
 
 
78
  if hourly:
79
  hourly_items = ""
80
  for forecast in hourly:
81
+ time_part, temp_part = forecast.split('')
82
+ hourly_items += f"<div style='flex:1;min-width:60px;padding:12px;background:rgba(255,140,60,0.05);border-radius:16px;text-align:center;'><div style='font-weight:700;'>{temp_part}</div><div style='font-size:12px;color:#ccc;'>{time_part}</div></div>"
83
+ html += f"<div style='display:flex;gap:8px;margin-top:16px;overflow-x:auto;'>{hourly_items}</div>"
84
+ return html
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
+ # Custom CSS overrides
87
  custom_css = """
88
+ body, .gradio-container { background:linear-gradient(135deg,#0a0a0a,#1a1a1a) !important; color:white !important; }
89
+ .search-container input { background:rgba(203,77,11,0.1) !important; border:2px solid rgba(203,77,11,0.3) !important; border-radius:16px !important; padding:16px !important; }
90
+ .modern-button { background:linear-gradient(135deg, rgb(203,77,11), #ff6b35) !important; border:none !important; padding:16px 32px !important; border-radius:16px !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  """
92
 
93
+ # Build Gradio interface
94
  with gr.Blocks(css=custom_css, title="Weather Wizard", theme=gr.themes.Glass()) as app:
95
  gr.HTML("""
96
+ <div style='text-align:center;padding:32px;background:linear-gradient(135deg,#0a0a0a,#1a1a1a);'>
97
+ <h1 style='color:rgb(203,77,11);font-size:42px;margin:0;background:linear-gradient(135deg,rgb(203,77,11),#ff8c3c);-webkit-background-clip:text;-webkit-text-fill-color:transparent;'>🌦️ Weather Wizard</h1>
98
+ <p style='color:rgba(255,255,255,0.7);margin-top:8px;'>AI-powered weather forecasts for the modern world</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  </div>
100
  """)
 
101
  with gr.Column(elem_classes=["search-section"]):
102
+ city = gr.Textbox(label="", placeholder="Search any city worldwide...", show_label=False, elem_classes=["search-container"])
103
+ btn = gr.Button("✨ Discover Weather", variant="primary", size="lg", elem_classes=["modern-button"])
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  weather_display = gr.HTML()
105
+
106
+ def update(city):
107
+ temp, condition, humidity, wind_speed, icon, hourly, name = get_weather(city.strip() or "London")
108
+ return create_weather_display(temp, condition, humidity, wind_speed, icon, hourly, name)
109
+
110
+ btn.click(fn=update, inputs=city, outputs=weather_display)
111
+ city.submit(fn=update, inputs=city, outputs=weather_display)
112
+ app.load(fn=lambda: update("London"), outputs=weather_display)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  if __name__ == "__main__":
115
+ app.launch()