File size: 6,792 Bytes
74a1494
9b5b26a
 
 
c19d193
6aae614
9b5b26a
 
 
74a1494
9b5b26a
 
 
 
 
 
 
 
 
 
 
 
8c01ffb
 
74a1494
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae7a494
74a1494
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae7a494
e121372
74a1494
 
 
 
13d500a
8c01ffb
74a1494
9b5b26a
8c01ffb
74a1494
861422e
 
74a1494
8c01ffb
8fe992b
74a1494
 
 
 
 
 
 
 
 
 
8c01ffb
 
 
 
 
 
74a1494
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
153
154
155
156
157
158
159
160
161
162
163
164
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool
import datetime
import requests
import pytz
import yaml
from tools.final_answer import FinalAnswerTool
from Gradio_UI import GradioUI


# ── Tool 1: Timezone checker ──────────────────────────────────────────────────
@tool
def get_current_time_in_timezone(timezone: str) -> str:
    """A tool that fetches the current local time in a specified timezone.
    Args:
        timezone: A string representing a valid timezone (e.g., 'America/New_York').
    """
    try:
        tz = pytz.timezone(timezone)
        local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
        return f"The current local time in {timezone} is: {local_time}"
    except Exception as e:
        return f"Error fetching time for timezone '{timezone}': {str(e)}"


# ── Tool 2: Weather checker ───────────────────────────────────────────────────
@tool
def get_weather(city: str) -> str:
    """Fetches the current weather for a given city using the Open-Meteo API.
    Args:
        city: The name of the city to get weather for (e.g., 'London').
    """
    try:
        # Step 1: Geocode the city name to lat/lon
        geo_url = f"https://geocoding-api.open-meteo.com/v1/search?name={city}&count=1"
        geo_resp = requests.get(geo_url, timeout=10).json()
        if not geo_resp.get("results"):
            return f"Could not find location for city: {city}"
        loc = geo_resp["results"][0]
        lat, lon, name = loc["latitude"], loc["longitude"], loc["name"]

        # Step 2: Fetch weather
        weather_url = (
            f"https://api.open-meteo.com/v1/forecast"
            f"?latitude={lat}&longitude={lon}"
            f"¤t_weather=true&hourly=relative_humidity_2m"
        )
        weather_resp = requests.get(weather_url, timeout=10).json()
        cw = weather_resp.get("current_weather", {})
        temp   = cw.get("temperature", "N/A")
        wind   = cw.get("windspeed", "N/A")
        code   = cw.get("weathercode", "N/A")
        return (
            f"Weather in {name}:\n"
            f"  Temperature : {temp} °C\n"
            f"  Wind speed  : {wind} km/h\n"
            f"  Weather code: {code} (WMO standard)"
        )
    except Exception as e:
        return f"Error fetching weather: {str(e)}"


# ── Tool 3: Unit converter ────────────────────────────────────────────────────
@tool
def convert_units(value: float, from_unit: str, to_unit: str) -> str:
    """Converts a value between common units (length, weight, temperature).
    Args:
        value: The numeric value to convert.
        from_unit: The source unit (e.g., 'km', 'kg', 'celsius', 'miles', 'pounds', 'fahrenheit').
        to_unit: The target unit (e.g., 'miles', 'pounds', 'fahrenheit').
    """
    conversions = {
        ("km", "miles"): lambda x: x * 0.621371,
        ("miles", "km"): lambda x: x * 1.60934,
        ("kg", "pounds"): lambda x: x * 2.20462,
        ("pounds", "kg"): lambda x: x * 0.453592,
        ("meters", "feet"): lambda x: x * 3.28084,
        ("feet", "meters"): lambda x: x * 0.3048,
        ("celsius", "fahrenheit"): lambda x: x * 9 / 5 + 32,
        ("fahrenheit", "celsius"): lambda x: (x - 32) * 5 / 9,
        ("celsius", "kelvin"): lambda x: x + 273.15,
        ("kelvin", "celsius"): lambda x: x - 273.15,
        ("liters", "gallons"): lambda x: x * 0.264172,
        ("gallons", "liters"): lambda x: x * 3.78541,
    }
    key = (from_unit.lower(), to_unit.lower())
    if key in conversions:
        result = conversions[key](value)
        return f"{value} {from_unit} = {round(result, 4)} {to_unit}"
    return f"Conversion from '{from_unit}' to '{to_unit}' is not supported."


# ── Tool 4: Day-of-week calculator ───────────────────────────────────────────
@tool
def get_day_of_week(date_str: str) -> str:
    """Returns the day of the week for a given date.
    Args:
        date_str: A date string in YYYY-MM-DD format (e.g., '2025-12-25').
    """
    try:
        date_obj = datetime.datetime.strptime(date_str, "%Y-%m-%d")
        day_name = date_obj.strftime("%A")
        return f"{date_str} falls on a {day_name}."
    except ValueError:
        return "Invalid date format. Please use YYYY-MM-DD (e.g., '2025-07-04')."


# ── Tool 5: Random joke fetcher ───────────────────────────────────────────────
@tool
def get_random_joke(category: str) -> str:
    """Fetches a random joke from the JokeAPI.
    Args:
        category: Joke category — one of 'Programming', 'Misc', 'Dark', 'Pun', 'Spooky', 'Christmas'.
    """
    try:
        url = f"https://v2.jokeapi.dev/joke/{category}?blacklistFlags=nsfw,racist,sexist"
        resp = requests.get(url, timeout=10).json()
        if resp.get("type") == "single":
            return resp["joke"]
        elif resp.get("type") == "twopart":
            return f"{resp['setup']}\n... {resp['delivery']}"
        return "Couldn't fetch a joke right now."
    except Exception as e:
        return f"Error fetching joke: {str(e)}"


# ── Model & agent setup ───────────────────────────────────────────────────────
final_answer = FinalAnswerTool()

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

# Load image generation tool from the Hub
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)

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

agent = CodeAgent(
    model=model,
    tools=[
        final_answer,
        DuckDuckGoSearchTool(),       # Web search
        image_generation_tool,        # Text-to-image
        get_current_time_in_timezone, # Timezone lookup
        get_weather,                  # Live weather
        convert_units,                # Unit converter
        get_day_of_week,              # Date → weekday
        get_random_joke,              # Joke fetcher
    ],
    max_steps=6,
    verbosity_level=1,
    grammar=None,
    planning_interval=None,
    name=None,
    description=None,
    prompt_templates=prompt_templates,
)

GradioUI(agent).launch()