chirfort commited on
Commit
87e4413
·
1 Parent(s): 3813579

Enhance WeatherAppProEnhanced with new charting methods for temperature, precipitation, wind, and humidity; improve data handling for forecast formats and error logging.

Browse files
Files changed (1) hide show
  1. app.py +211 -158
app.py CHANGED
@@ -267,8 +267,7 @@ class WeatherAppProEnhanced:
267
  <h3>🗺️ Weather Map</h3>
268
  <p>Ask about weather in a city to see it on the map!</p>
269
  </div>
270
- </div>
271
- """
272
 
273
  def _create_default_chart(self) -> go.Figure:
274
  """Create default empty chart with professional dark styling"""
@@ -313,6 +312,198 @@ class WeatherAppProEnhanced:
313
  )
314
 
315
  return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
 
317
  def _get_weather_emoji(self, condition: str) -> str:
318
  """Get appropriate emoji for weather condition"""
@@ -1278,14 +1469,13 @@ class WeatherAppProEnhanced:
1278
 
1279
  cities = result.get('cities', [])
1280
  forecast_city_sync = cities[0] if cities else ""
1281
-
1282
- # 🔄 Auto-sync forecast with MCP enhancements
1283
  synced_forecast_text = gr.update()
1284
  synced_temp_chart = gr.update()
1285
  synced_precip_chart = gr.update()
1286
  synced_wind_chart = gr.update()
1287
  synced_humidity_chart = gr.update()
1288
-
1289
  if forecast_city_sync:
1290
  try:
1291
  # 🚀 Enhanced forecast with MCP data
@@ -1338,12 +1528,17 @@ class WeatherAppProEnhanced:
1338
 
1339
  lat, lon = coords
1340
  forecast_data = self.weather_client.get_forecast(lat, lon)
1341
- hourly_data = self.weather_client.get_hourly_forecast(lat, lon, hours=24) # For precip, wind, humidity
1342
 
 
 
 
 
 
 
1343
  temp_fig = self._create_temperature_chart(forecast_data) if forecast_data else self._create_default_chart()
1344
- precip_fig = self._create_precipitation_chart(hourly_data) if hourly_data else self._create_default_chart()
1345
- wind_fig = self._create_wind_chart(hourly_data) if hourly_data else self._create_default_chart() # New
1346
- humidity_fig = self._create_humidity_chart(hourly_data) if hourly_data else self._create_default_chart() # New
1347
 
1348
  return forecast_text, temp_fig, precip_fig, wind_fig, humidity_fig, "" # Clear input
1349
 
@@ -1422,8 +1617,7 @@ class WeatherAppProEnhanced:
1422
  'forecast': city_data.get('forecast', []),
1423
  'current': city_data.get('current', {})
1424
  }
1425
-
1426
- # Add MCP enhancements if available
1427
  if mcp_data and city in mcp_data:
1428
  city_info['mcp_enhancements'] = mcp_data[city]
1429
 
@@ -1437,7 +1631,7 @@ class WeatherAppProEnhanced:
1437
  except Exception as e:
1438
  logger.error(f"Error updating enhanced map: {e}")
1439
  return self._get_current_map()
1440
-
1441
  def _handle_enhanced_forecast(self, city_name: str, mcp_data: dict = None):
1442
  """Handle forecast with MCP enhancements"""
1443
  try:
@@ -1467,12 +1661,12 @@ class WeatherAppProEnhanced:
1467
  if coords:
1468
  lat, lon = coords
1469
  forecast_data = self.weather_client.get_forecast(lat, lon)
1470
- hourly_data = self.weather_client.get_hourly_forecast(lat, lon, hours=24)
1471
 
 
1472
  temp_fig = self._create_temperature_chart(forecast_data) if forecast_data else self._create_default_chart()
1473
- precip_fig = self._create_precipitation_chart(hourly_data) if hourly_data else self._create_default_chart()
1474
- wind_fig = self._create_wind_chart(hourly_data) if hourly_data else self._create_default_chart()
1475
- humidity_fig = self._create_humidity_chart(hourly_data) if hourly_data else self._create_default_chart()
1476
 
1477
  return enhanced_forecast, temp_fig, precip_fig, wind_fig, humidity_fig, ""
1478
  else:
@@ -1480,148 +1674,7 @@ class WeatherAppProEnhanced:
1480
 
1481
  except Exception as e:
1482
  logger.error(f"Error in enhanced forecast: {e}")
1483
- return f"❌ Error getting enhanced forecast: {str(e)}", self._create_default_chart(), self._create_default_chart(), self._create_default_chart(), self._create_default_chart(), ""
1484
-
1485
- def _create_temperature_chart(self, forecast_data: Dict) -> go.Figure:
1486
- """Create temperature chart from forecast data"""
1487
- try:
1488
- periods = forecast_data.get('periods', [])[:7] # 7 day forecast
1489
-
1490
- times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
1491
- temps = [p.get('temperature', 0) for p in periods]
1492
-
1493
- fig = go.Figure()
1494
- fig.add_trace(go.Scatter(
1495
- x=times, y=temps,
1496
- mode='lines+markers',
1497
- name='Temperature',
1498
- line=dict(color='#3b82f6', width=3),
1499
- marker=dict(size=8)
1500
- ))
1501
-
1502
- fig.update_layout(
1503
- title="🌡️ 7-Day Temperature Forecast",
1504
- xaxis_title="Time Period",
1505
- yaxis_title="Temperature (°F)",
1506
- template="plotly_dark",
1507
- height=300,
1508
- paper_bgcolor='rgba(0,0,0,0)',
1509
- plot_bgcolor='rgba(0,0,0,0)',
1510
- font=dict(color='white')
1511
- )
1512
-
1513
- return fig
1514
-
1515
- except Exception as e:
1516
- logger.error(f"Error creating temperature chart: {e}")
1517
- return self._create_default_chart()
1518
-
1519
- def _create_precipitation_chart(self, forecast_data: Dict) -> go.Figure:
1520
- """Create precipitation chart"""
1521
- try:
1522
- periods = forecast_data.get('periods', [])[:7]
1523
-
1524
- times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
1525
- precip = [p.get('precipitationProbability', 0) or 0 for p in periods]
1526
-
1527
- fig = go.Figure()
1528
- fig.add_trace(go.Bar(
1529
- x=times, y=precip,
1530
- name='Precipitation Chance',
1531
- marker_color='#06b6d4'
1532
- ))
1533
-
1534
- fig.update_layout(
1535
- title="🌧️ Precipitation Probability",
1536
- xaxis_title="Time Period",
1537
- yaxis_title="Chance of Rain (%)",
1538
- template="plotly_dark",
1539
- height=300,
1540
- paper_bgcolor='rgba(0,0,0,0)',
1541
- plot_bgcolor='rgba(0,0,0,0)',
1542
- font=dict(color='white')
1543
- )
1544
-
1545
- return fig
1546
-
1547
- except Exception as e:
1548
- logger.error(f"Error creating precipitation chart: {e}")
1549
- return self._create_default_chart()
1550
-
1551
- def _create_wind_chart(self, forecast_data: Dict) -> go.Figure:
1552
- """Create wind speed chart"""
1553
- try:
1554
- periods = forecast_data.get('periods', [])[:7]
1555
-
1556
- times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
1557
- # Extract wind speed from wind string (e.g., "SW 10 mph")
1558
- winds = []
1559
- for p in periods:
1560
- wind_str = p.get('windSpeed', '0 mph')
1561
- try:
1562
- wind_val = int(''.join(filter(str.isdigit, wind_str.split()[0])))
1563
- winds.append(wind_val)
1564
- except:
1565
- winds.append(0)
1566
-
1567
- fig = go.Figure()
1568
- fig.add_trace(go.Scatter(
1569
- x=times, y=winds,
1570
- mode='lines+markers',
1571
- name='Wind Speed',
1572
- line=dict(color='#10b981', width=3),
1573
- marker=dict(size=8)
1574
- ))
1575
-
1576
- fig.update_layout(
1577
- title="🌬️ Wind Speed Forecast",
1578
- xaxis_title="Time Period",
1579
- yaxis_title="Wind Speed (mph)",
1580
- template="plotly_dark",
1581
- height=300,
1582
- paper_bgcolor='rgba(0,0,0,0)',
1583
- plot_bgcolor='rgba(0,0,0,0)',
1584
- font=dict(color='white')
1585
- )
1586
-
1587
- return fig
1588
-
1589
- except Exception as e:
1590
- logger.error(f"Error creating wind chart: {e}")
1591
- return self._create_default_chart()
1592
-
1593
- def _create_humidity_chart(self, forecast_data: Dict) -> go.Figure:
1594
- """Create humidity chart"""
1595
- try:
1596
- periods = forecast_data.get('periods', [])[:7]
1597
-
1598
- times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
1599
- # Simulate humidity data (real API might have this)
1600
- humidity = [60 + (i * 5) % 40 for i in range(len(periods))]
1601
-
1602
- fig = go.Figure()
1603
- fig.add_trace(go.Bar(
1604
- x=times, y=humidity,
1605
- name='Relative Humidity',
1606
- marker_color='#8b5cf6'
1607
- ))
1608
-
1609
- fig.update_layout(
1610
- title="💧 Humidity Levels",
1611
- xaxis_title="Time Period",
1612
- yaxis_title="Relative Humidity (%)",
1613
- template="plotly_dark",
1614
- height=300,
1615
- paper_bgcolor='rgba(0,0,0,0)',
1616
- plot_bgcolor='rgba(0,0,0,0)',
1617
- font=dict(color='white')
1618
- )
1619
-
1620
- return fig
1621
-
1622
- except Exception as e:
1623
- logger.error(f"Error creating humidity chart: {e}")
1624
- return self._create_default_chart()
1625
 
1626
  # ...existing code...
1627
  def main():
 
267
  <h3>🗺️ Weather Map</h3>
268
  <p>Ask about weather in a city to see it on the map!</p>
269
  </div>
270
+ </div> """
 
271
 
272
  def _create_default_chart(self) -> go.Figure:
273
  """Create default empty chart with professional dark styling"""
 
312
  )
313
 
314
  return fig
315
+
316
+ def _create_temperature_chart(self, forecast_data) -> go.Figure:
317
+ """Create temperature chart from forecast data"""
318
+ try:
319
+ # Handle both list and dict formats
320
+ if isinstance(forecast_data, list):
321
+ periods = forecast_data[:7] # Direct list of periods
322
+ elif isinstance(forecast_data, dict):
323
+ periods = forecast_data.get('periods', [])[:7] # Dict with periods key
324
+ else:
325
+ periods = []
326
+
327
+ if not periods:
328
+ return self._create_default_chart()
329
+
330
+ times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
331
+ temps = [p.get('temperature', 0) for p in periods]
332
+
333
+ fig = go.Figure()
334
+ fig.add_trace(go.Scatter(
335
+ x=times, y=temps,
336
+ mode='lines+markers',
337
+ name='Temperature',
338
+ line=dict(color='#3b82f6', width=3),
339
+ marker=dict(size=8)
340
+ ))
341
+
342
+ fig.update_layout(
343
+ title="🌡️ 7-Day Temperature Forecast",
344
+ xaxis_title="Time Period",
345
+ yaxis_title="Temperature (°F)",
346
+ template="plotly_dark",
347
+ height=300,
348
+ paper_bgcolor='rgba(0,0,0,0)',
349
+ plot_bgcolor='rgba(0,0,0,0)',
350
+ font=dict(color='white')
351
+ )
352
+
353
+ return fig
354
+
355
+ except Exception as e:
356
+ logger.error(f"Error creating temperature chart: {e}")
357
+ return self._create_default_chart()
358
+
359
+ def _create_precipitation_chart(self, forecast_data) -> go.Figure:
360
+ """Create precipitation chart"""
361
+ try:
362
+ # Handle both list and dict formats
363
+ if isinstance(forecast_data, list):
364
+ periods = forecast_data[:7] # Direct list of periods
365
+ elif isinstance(forecast_data, dict):
366
+ periods = forecast_data.get('periods', [])[:7] # Dict with periods key
367
+ else:
368
+ periods = []
369
+
370
+ if not periods:
371
+ return self._create_default_chart()
372
+
373
+ times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
374
+ precip = [p.get('precipitationProbability', 0) or 0 for p in periods]
375
+
376
+ fig = go.Figure()
377
+ fig.add_trace(go.Bar(
378
+ x=times, y=precip,
379
+ name='Precipitation Chance',
380
+ marker_color='#06b6d4'
381
+ ))
382
+
383
+ fig.update_layout(
384
+ title="🌧️ Precipitation Probability",
385
+ xaxis_title="Time Period",
386
+ yaxis_title="Chance of Rain (%)",
387
+ template="plotly_dark",
388
+ height=300,
389
+ paper_bgcolor='rgba(0,0,0,0)',
390
+ plot_bgcolor='rgba(0,0,0,0)',
391
+ font=dict(color='white')
392
+ )
393
+
394
+ return fig
395
+
396
+ except Exception as e:
397
+ logger.error(f"Error creating precipitation chart: {e}")
398
+ return self._create_default_chart()
399
+
400
+ def _create_wind_chart(self, forecast_data) -> go.Figure:
401
+ """Create wind speed chart"""
402
+ try:
403
+ # Handle both list and dict formats
404
+ if isinstance(forecast_data, list):
405
+ periods = forecast_data[:7] # Direct list of periods
406
+ elif isinstance(forecast_data, dict):
407
+ periods = forecast_data.get('periods', [])[:7] # Dict with periods key
408
+ else:
409
+ periods = []
410
+
411
+ if not periods:
412
+ return self._create_default_chart()
413
+
414
+ times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
415
+ # Extract wind speed from wind string (e.g., "SW 10 mph")
416
+ winds = []
417
+ for p in periods:
418
+ wind_str = p.get('windSpeed', '0 mph')
419
+ try:
420
+ # Extract numeric part from wind speed string
421
+ import re
422
+ wind_match = re.search(r'\d+', str(wind_str))
423
+ wind_val = int(wind_match.group()) if wind_match else 0
424
+ winds.append(wind_val)
425
+ except:
426
+ winds.append(0)
427
+
428
+ fig = go.Figure()
429
+ fig.add_trace(go.Scatter(
430
+ x=times, y=winds,
431
+ mode='lines+markers',
432
+ name='Wind Speed',
433
+ line=dict(color='#10b981', width=3),
434
+ marker=dict(size=8)
435
+ ))
436
+
437
+ fig.update_layout(
438
+ title="🌬️ Wind Speed Forecast",
439
+ xaxis_title="Time Period",
440
+ yaxis_title="Wind Speed (mph)",
441
+ template="plotly_dark",
442
+ height=300,
443
+ paper_bgcolor='rgba(0,0,0,0)',
444
+ plot_bgcolor='rgba(0,0,0,0)',
445
+ font=dict(color='white')
446
+ )
447
+
448
+ return fig
449
+
450
+ except Exception as e:
451
+ logger.error(f"Error creating wind chart: {e}")
452
+ return self._create_default_chart()
453
+
454
+ def _create_humidity_chart(self, forecast_data) -> go.Figure:
455
+ """Create humidity chart"""
456
+ try:
457
+ # Handle both list and dict formats
458
+ if isinstance(forecast_data, list):
459
+ periods = forecast_data[:7] # Direct list of periods
460
+ elif isinstance(forecast_data, dict):
461
+ periods = forecast_data.get('periods', [])[:7] # Dict with periods key
462
+ else:
463
+ periods = []
464
+
465
+ if not periods:
466
+ return self._create_default_chart()
467
+
468
+ times = [p.get('name', f'Day {i+1}') for i, p in enumerate(periods)]
469
+
470
+ # Try to get real humidity data, or simulate if not available
471
+ humidity = []
472
+ for i, p in enumerate(periods):
473
+ # Check if humidity data exists
474
+ rel_humidity = p.get('relativeHumidity')
475
+ if rel_humidity and isinstance(rel_humidity, dict):
476
+ humidity_val = rel_humidity.get('value', 60 + (i * 5) % 40)
477
+ elif rel_humidity and isinstance(rel_humidity, (int, float)):
478
+ humidity_val = rel_humidity
479
+ else:
480
+ # Simulate realistic humidity values (50-90%)
481
+ humidity_val = 60 + (i * 5) % 40
482
+ humidity.append(humidity_val)
483
+
484
+ fig = go.Figure()
485
+ fig.add_trace(go.Bar(
486
+ x=times, y=humidity,
487
+ name='Relative Humidity',
488
+ marker_color='#8b5cf6'
489
+ ))
490
+
491
+ fig.update_layout(
492
+ title="💧 Humidity Levels",
493
+ xaxis_title="Time Period",
494
+ yaxis_title="Relative Humidity (%)",
495
+ template="plotly_dark",
496
+ height=300,
497
+ paper_bgcolor='rgba(0,0,0,0)',
498
+ plot_bgcolor='rgba(0,0,0,0)',
499
+ font=dict(color='white')
500
+ )
501
+
502
+ return fig
503
+
504
+ except Exception as e:
505
+ logger.error(f"Error creating humidity chart: {e}")
506
+ return self._create_default_chart()
507
 
508
  def _get_weather_emoji(self, condition: str) -> str:
509
  """Get appropriate emoji for weather condition"""
 
1469
 
1470
  cities = result.get('cities', [])
1471
  forecast_city_sync = cities[0] if cities else ""
1472
+ # 🔄 Auto-sync forecast with MCP enhancements
 
1473
  synced_forecast_text = gr.update()
1474
  synced_temp_chart = gr.update()
1475
  synced_precip_chart = gr.update()
1476
  synced_wind_chart = gr.update()
1477
  synced_humidity_chart = gr.update()
1478
+
1479
  if forecast_city_sync:
1480
  try:
1481
  # 🚀 Enhanced forecast with MCP data
 
1528
 
1529
  lat, lon = coords
1530
  forecast_data = self.weather_client.get_forecast(lat, lon)
 
1531
 
1532
+ # Debug: Check what format forecast_data is
1533
+ logger.info(f"Forecast data type: {type(forecast_data)}")
1534
+ if forecast_data:
1535
+ logger.info(f"Forecast data sample: {forecast_data[:1] if isinstance(forecast_data, list) else list(forecast_data.keys()) if isinstance(forecast_data, dict) else 'Unknown format'}")
1536
+
1537
+ # Use the same forecast data for all charts since they now handle both formats
1538
  temp_fig = self._create_temperature_chart(forecast_data) if forecast_data else self._create_default_chart()
1539
+ precip_fig = self._create_precipitation_chart(forecast_data) if forecast_data else self._create_default_chart()
1540
+ wind_fig = self._create_wind_chart(forecast_data) if forecast_data else self._create_default_chart()
1541
+ humidity_fig = self._create_humidity_chart(forecast_data) if forecast_data else self._create_default_chart()
1542
 
1543
  return forecast_text, temp_fig, precip_fig, wind_fig, humidity_fig, "" # Clear input
1544
 
 
1617
  'forecast': city_data.get('forecast', []),
1618
  'current': city_data.get('current', {})
1619
  }
1620
+ # Add MCP enhancements if available
 
1621
  if mcp_data and city in mcp_data:
1622
  city_info['mcp_enhancements'] = mcp_data[city]
1623
 
 
1631
  except Exception as e:
1632
  logger.error(f"Error updating enhanced map: {e}")
1633
  return self._get_current_map()
1634
+
1635
  def _handle_enhanced_forecast(self, city_name: str, mcp_data: dict = None):
1636
  """Handle forecast with MCP enhancements"""
1637
  try:
 
1661
  if coords:
1662
  lat, lon = coords
1663
  forecast_data = self.weather_client.get_forecast(lat, lon)
 
1664
 
1665
+ # Use the same forecast data for all charts (they handle the format internally)
1666
  temp_fig = self._create_temperature_chart(forecast_data) if forecast_data else self._create_default_chart()
1667
+ precip_fig = self._create_precipitation_chart(forecast_data) if forecast_data else self._create_default_chart()
1668
+ wind_fig = self._create_wind_chart(forecast_data) if forecast_data else self._create_default_chart()
1669
+ humidity_fig = self._create_humidity_chart(forecast_data) if forecast_data else self._create_default_chart()
1670
 
1671
  return enhanced_forecast, temp_fig, precip_fig, wind_fig, humidity_fig, ""
1672
  else:
 
1674
 
1675
  except Exception as e:
1676
  logger.error(f"Error in enhanced forecast: {e}")
1677
+ return f"❌ Error getting enhanced forecast: {str(e)}", self._create_default_chart(), self._create_default_chart(), self._create_default_chart(), self._create_default_chart(), "" # Chart creation methods are defined above in the main class
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1678
 
1679
  # ...existing code...
1680
  def main():