File size: 5,629 Bytes
18d57bd
9b5b26a
18d57bd
9b5b26a
 
c19d193
18d57bd
6aae614
9b5b26a
e0373a0
9b5b26a
18d57bd
 
 
9b5b26a
 
b6d734e
 
 
18d57bd
9b5b26a
b6d734e
 
 
 
9b5b26a
 
 
b6d734e
 
 
 
8c01ffb
0fda2d7
18d57bd
bf7cbcc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18d57bd
 
 
7401736
18d57bd
 
 
6086f1e
3525044
e0373a0
 
 
 
6086f1e
0d1d031
6086f1e
18d57bd
6086f1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18d57bd
 
6086f1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7401736
6086f1e
 
 
 
 
18d57bd
 
 
 
 
 
 
 
 
 
3b3ac4f
18d57bd
 
 
 
3b3ac4f
8c01ffb
7401736
9b5b26a
8c01ffb
861422e
 
18d57bd
8c01ffb
8fe992b
18d57bd
8c01ffb
 
 
 
 
 
861422e
8fe992b
 
8c01ffb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool
import datetime
import time
import requests
import pytz
import yaml
import random
from tools.final_answer import FinalAnswerTool
from Gradio_UI import GradioUI
import os

# Global cache for forecasts per city to avoid refetching within a certain duration (10 minutes)
cached_forecasts = {}  # Dictionary mapping city name -> { "data": str, "timestamp": int }
CACHE_DURATION_MS = 10 * 60 * 1000  # 10 minutes in milliseconds

@tool
def get_current_time_in_timezone(timezone: str = "UTC") -> str:
    """
    A tool to get the current time in a specific timezone.
    
    Args:
        timezone (str): The timezone string. E.g., 'America/New_York'
    
    Returns:
        str: The local time in the specified timezone.
    """
    try:
        tz = pytz.timezone(timezone)
        now = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
        return f"Local time in {timezone}: {now}"
    except Exception:
        return "Invalid timezone"

@tool
def get_weather_forecast(city: str = "New York", days: int = 7) -> str:
    """
    A tool to fetch a weekly weather forecast for a specified city.
    
    This function first checks for a cached forecast for the given city. If the cached
    data is older than 10 minutes, it attempts to fetch new data from OpenWeatherMap.
    
    If a valid API key is not provided or an error occurs during the API call,
    a mock forecast is generated.
    
    Args:
        city (str): The city name for which to get the weather.
        days (int): Number of days to forecast (maximum of 7).
    
    Returns:
        str: A formatted summary forecast with daily averages.
    """
    global cached_forecasts
    now_ms = int(time.time() * 1000)

    # Check for a valid cache
    if city in cached_forecasts and now_ms - cached_forecasts[city]["timestamp"] < CACHE_DURATION_MS:
        return cached_forecasts[city]["data"]

    # Use a real API key in production
    api_key = os.environ.get("OPENWEATHER_API", None)  # This should be defined/assigned earlier

    # For debugging: print the API key value (remove or secure in production)
    print("DEBUG: API key used =", api_key)

    # Validate API key before proceeding
    if not api_key:
        return "Error: Invalid or missing OpenWeather API key. Please configure a valid API key."

    url = f"http://api.openweathermap.org/data/2.5/forecast?q={city}&appid={api_key}&units=metric"
    try:
        response = requests.get(url)
        data = response.json()
        if data.get("cod") != "200":
            raise ValueError(data.get("message", "Error fetching weather data"))

        # Process and group forecast items by day (format: YYYY-MM-DD)
        forecast_by_day = {}
        for item in data.get("list", []):
            dt = datetime.datetime.utcfromtimestamp(item["dt"])
            day_str = dt.strftime("%Y-%m-%d")
            forecast_by_day.setdefault(day_str, []).append(item)

        # Build forecast for up to 'days' days
        sorted_days = sorted(forecast_by_day.keys())[:min(days, 7)]
        daily_forecasts = []
        for day_str in sorted_days:
            day_items = forecast_by_day[day_str]
            date_obj = datetime.datetime.strptime(day_str, "%Y-%m-%d")
            day_name = date_obj.strftime("%A")
            date_display = date_obj.strftime("%b %d")

            total_temp = total_humidity = total_pressure = total_wind = 0
            condition_counts = {}
            for item in day_items:
                total_temp += item["main"]["temp"]
                total_humidity += item["main"]["humidity"]
                total_pressure += item["main"]["pressure"]
                total_wind += item["wind"]["speed"]
                condition = item["weather"][0]["description"]
                condition_counts[condition] = condition_counts.get(condition, 0) + 1

            count = len(day_items)
            avg_temp = round(total_temp / count)
            avg_humidity = round(total_humidity / count)
            avg_pressure = round(total_pressure / count)
            avg_wind = round((total_wind / count) * 3.6)  # Convert m/s to km/h
            most_common_condition = max(condition_counts.items(), key=lambda x: x[1])[0]

            daily_forecasts.append(
                f"{day_name}, {date_display}: {avg_temp}°C, {most_common_condition} | Humidity: {avg_humidity}% | Pressure: {avg_pressure} hPa | Wind: {avg_wind} km/h"
            )
        forecast_data = "\n".join(daily_forecasts)
    except Exception as error:
        # Log the error and return an error message
        print("Error fetching forecast from API:", error)
        return f"Error: Unable to fetch weather data. Reason: {error}"

    # Cache the forecast data
    cached_forecasts[city] = {
        "data": forecast_data,
        "timestamp": now_ms
    }
    return forecast_data

final_answer = FinalAnswerTool()

model = HfApiModel(
    max_tokens=2096,
    temperature=0.5,
    model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
    custom_role_conversions=None,
)

# Import a text-to-image tool from the hub, if desired.
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)

with open("prompts.yaml", 'r') as stream:
    prompt_templates = yaml.safe_load(stream)

agent = CodeAgent(
    model=model,
    tools=[final_answer, get_current_time_in_timezone, get_weather_forecast],
    max_steps=6,
    verbosity_level=1,
    grammar=None,
    planning_interval=None,
    name=None,
    description=None,
    prompt_templates=prompt_templates
)

GradioUI(agent).launch()