Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -32,22 +32,6 @@ def get_current_time_in_timezone(timezone: str = "UTC") -> str:
|
|
| 32 |
|
| 33 |
@tool
|
| 34 |
def get_weather_forecast(city: str = "New York", days: int = 7) -> str:
|
| 35 |
-
"""
|
| 36 |
-
A tool to fetch a weekly weather forecast for a specified city.
|
| 37 |
-
|
| 38 |
-
This function first checks for a cached forecast for the given city. If the cached
|
| 39 |
-
data is older than 10 minutes, it attempts to fetch new data from OpenWeatherMap.
|
| 40 |
-
|
| 41 |
-
If a valid API key is not provided or an error occurs during the API call,
|
| 42 |
-
a mock forecast is generated.
|
| 43 |
-
|
| 44 |
-
Args:
|
| 45 |
-
city (str): The city name for which to get the weather.
|
| 46 |
-
days (int): Number of days to forecast (maximum of 7).
|
| 47 |
-
|
| 48 |
-
Returns:
|
| 49 |
-
str: A formatted summary forecast with daily averages.
|
| 50 |
-
"""
|
| 51 |
global cached_forecasts
|
| 52 |
now_ms = int(time.time() * 1000)
|
| 53 |
|
|
@@ -55,100 +39,61 @@ def get_weather_forecast(city: str = "New York", days: int = 7) -> str:
|
|
| 55 |
if city in cached_forecasts and now_ms - cached_forecasts[city]["timestamp"] < CACHE_DURATION_MS:
|
| 56 |
return cached_forecasts[city]["data"]
|
| 57 |
|
| 58 |
-
#
|
| 59 |
api_key = "OPENWEATHER_API"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
day_name = date_obj.strftime("%A")
|
| 70 |
date_display = date_obj.strftime("%b %d")
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
)
|
| 80 |
-
forecast_data = "\n".join(
|
| 81 |
-
|
| 82 |
-
#
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
response = requests.get(url)
|
| 86 |
-
data = response.json()
|
| 87 |
-
if data.get("cod") != "200":
|
| 88 |
-
raise ValueError(data.get("message", "Error fetching weather data"))
|
| 89 |
-
|
| 90 |
-
# Group forecast items by day (format: YYYY-MM-DD)
|
| 91 |
-
forecast_by_day = {}
|
| 92 |
-
for item in data.get("list", []):
|
| 93 |
-
dt = datetime.datetime.utcfromtimestamp(item["dt"])
|
| 94 |
-
day_str = dt.strftime("%Y-%m-%d")
|
| 95 |
-
forecast_by_day.setdefault(day_str, []).append(item)
|
| 96 |
-
|
| 97 |
-
# Get forecast for up to 'days' days (maximum 7)
|
| 98 |
-
sorted_days = sorted(forecast_by_day.keys())[:min(days, 7)]
|
| 99 |
-
daily_forecasts = []
|
| 100 |
-
for day_str in sorted_days:
|
| 101 |
-
day_items = forecast_by_day[day_str]
|
| 102 |
-
# Convert the day string to a date to extract day name and formatted date.
|
| 103 |
-
date_obj = datetime.datetime.strptime(day_str, "%Y-%m-%d")
|
| 104 |
-
day_name = date_obj.strftime("%A")
|
| 105 |
-
date_display = date_obj.strftime("%b %d")
|
| 106 |
-
|
| 107 |
-
total_temp = 0
|
| 108 |
-
total_humidity = 0
|
| 109 |
-
total_pressure = 0
|
| 110 |
-
total_wind = 0
|
| 111 |
-
condition_counts = {}
|
| 112 |
-
|
| 113 |
-
for item in day_items:
|
| 114 |
-
total_temp += item["main"]["temp"]
|
| 115 |
-
total_humidity += item["main"]["humidity"]
|
| 116 |
-
total_pressure += item["main"]["pressure"]
|
| 117 |
-
total_wind += item["wind"]["speed"]
|
| 118 |
-
condition = item["weather"][0]["description"]
|
| 119 |
-
condition_counts[condition] = condition_counts.get(condition, 0) + 1
|
| 120 |
-
|
| 121 |
-
count = len(day_items)
|
| 122 |
-
avg_temp = round(total_temp / count)
|
| 123 |
-
avg_humidity = round(total_humidity / count)
|
| 124 |
-
avg_pressure = round(total_pressure / count)
|
| 125 |
-
# Convert wind speed from m/s to km/h (approximately).
|
| 126 |
-
avg_wind = round((total_wind / count) * 3.6)
|
| 127 |
-
most_common_condition = max(condition_counts.items(), key=lambda x: x[1])[0]
|
| 128 |
-
|
| 129 |
-
daily_forecasts.append(
|
| 130 |
-
f"{day_name}, {date_display}: {avg_temp}°C, {most_common_condition} | Humidity: {avg_humidity}% | Pressure: {avg_pressure} hPa | Wind: {avg_wind} km/h"
|
| 131 |
-
)
|
| 132 |
-
forecast_data = "\n".join(daily_forecasts)
|
| 133 |
-
except Exception as error:
|
| 134 |
-
print("Error fetching forecast from API:", error)
|
| 135 |
-
# Fallback to generating mock forecast data in case of error
|
| 136 |
-
forecast_lines = []
|
| 137 |
-
today = datetime.datetime.now()
|
| 138 |
-
for i in range(min(days, 7)):
|
| 139 |
-
date_obj = today + datetime.timedelta(days=i)
|
| 140 |
-
day_name = date_obj.strftime("%A")
|
| 141 |
-
date_display = date_obj.strftime("%b %d")
|
| 142 |
-
temp = 15 + random.randint(0, 5)
|
| 143 |
-
humidity = 65 + random.randint(0, 15)
|
| 144 |
-
pressure = 1010 + random.randint(0, 10)
|
| 145 |
-
wind_speed = 8 + random.randint(0, 7)
|
| 146 |
-
conditions = ['partly cloudy', 'sunny', 'rain', 'overcast', 'light showers', 'clear skies', 'scattered clouds']
|
| 147 |
-
condition = conditions[i % len(conditions)]
|
| 148 |
-
forecast_lines.append(
|
| 149 |
-
f"{day_name}, {date_display}: {temp}°C, {condition} | Humidity: {humidity}% | Pressure: {pressure} hPa | Wind: {wind_speed} km/h"
|
| 150 |
-
)
|
| 151 |
-
forecast_data = "\n".join(forecast_lines)
|
| 152 |
|
| 153 |
# Cache the forecast data
|
| 154 |
cached_forecasts[city] = {
|
|
|
|
| 32 |
|
| 33 |
@tool
|
| 34 |
def get_weather_forecast(city: str = "New York", days: int = 7) -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
global cached_forecasts
|
| 36 |
now_ms = int(time.time() * 1000)
|
| 37 |
|
|
|
|
| 39 |
if city in cached_forecasts and now_ms - cached_forecasts[city]["timestamp"] < CACHE_DURATION_MS:
|
| 40 |
return cached_forecasts[city]["data"]
|
| 41 |
|
| 42 |
+
# Use a real API key in production
|
| 43 |
api_key = "OPENWEATHER_API"
|
| 44 |
+
|
| 45 |
+
# Validate API key before proceeding
|
| 46 |
+
if not api_key or api_key == "OPENWEATHER_API":
|
| 47 |
+
return "Error: Invalid or missing OpenWeather API key. Please configure a valid API key."
|
| 48 |
|
| 49 |
+
url = f"http://api.openweathermap.org/data/2.5/forecast?q={city}&appid={api_key}&units=metric"
|
| 50 |
+
try:
|
| 51 |
+
response = requests.get(url)
|
| 52 |
+
data = response.json()
|
| 53 |
+
if data.get("cod") != "200":
|
| 54 |
+
raise ValueError(data.get("message", "Error fetching weather data"))
|
| 55 |
+
|
| 56 |
+
# Process and group forecast items by day (format: YYYY-MM-DD)
|
| 57 |
+
forecast_by_day = {}
|
| 58 |
+
for item in data.get("list", []):
|
| 59 |
+
dt = datetime.datetime.utcfromtimestamp(item["dt"])
|
| 60 |
+
day_str = dt.strftime("%Y-%m-%d")
|
| 61 |
+
forecast_by_day.setdefault(day_str, []).append(item)
|
| 62 |
+
|
| 63 |
+
# Build forecast for up to 'days' days
|
| 64 |
+
sorted_days = sorted(forecast_by_day.keys())[:min(days, 7)]
|
| 65 |
+
daily_forecasts = []
|
| 66 |
+
for day_str in sorted_days:
|
| 67 |
+
day_items = forecast_by_day[day_str]
|
| 68 |
+
date_obj = datetime.datetime.strptime(day_str, "%Y-%m-%d")
|
| 69 |
day_name = date_obj.strftime("%A")
|
| 70 |
date_display = date_obj.strftime("%b %d")
|
| 71 |
+
|
| 72 |
+
total_temp = total_humidity = total_pressure = total_wind = 0
|
| 73 |
+
condition_counts = {}
|
| 74 |
+
for item in day_items:
|
| 75 |
+
total_temp += item["main"]["temp"]
|
| 76 |
+
total_humidity += item["main"]["humidity"]
|
| 77 |
+
total_pressure += item["main"]["pressure"]
|
| 78 |
+
total_wind += item["wind"]["speed"]
|
| 79 |
+
condition = item["weather"][0]["description"]
|
| 80 |
+
condition_counts[condition] = condition_counts.get(condition, 0) + 1
|
| 81 |
+
|
| 82 |
+
count = len(day_items)
|
| 83 |
+
avg_temp = round(total_temp / count)
|
| 84 |
+
avg_humidity = round(total_humidity / count)
|
| 85 |
+
avg_pressure = round(total_pressure / count)
|
| 86 |
+
avg_wind = round((total_wind / count) * 3.6) # Convert m/s to km/h
|
| 87 |
+
most_common_condition = max(condition_counts.items(), key=lambda x: x[1])[0]
|
| 88 |
+
|
| 89 |
+
daily_forecasts.append(
|
| 90 |
+
f"{day_name}, {date_display}: {avg_temp}°C, {most_common_condition} | Humidity: {avg_humidity}% | Pressure: {avg_pressure} hPa | Wind: {avg_wind} km/h"
|
| 91 |
)
|
| 92 |
+
forecast_data = "\n".join(daily_forecasts)
|
| 93 |
+
except Exception as error:
|
| 94 |
+
# Log the error and return an error message
|
| 95 |
+
print("Error fetching forecast from API:", error)
|
| 96 |
+
return f"Error: Unable to fetch weather data. Reason: {error}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
# Cache the forecast data
|
| 99 |
cached_forecasts[city] = {
|