File size: 4,733 Bytes
3b4ba4d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
923c3da
78f0195
 
 
3b4ba4d
 
78f0195
 
d5f7c74
 
b0ad9cd
d5f7c74
3b4ba4d
b0ad9cd
 
 
d5f7c74
3b4ba4d
d5f7c74
 
 
 
 
 
 
3b4ba4d
 
d5f7c74
 
3b4ba4d
 
 
78f0195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import json
import requests
from typing import Any, Optional
from smolagents.tools import Tool


class WeatherForecast(Tool):
    name = "weather_forecast"
    description = "Performs a weather search via open-mateo with openstreetmaps to get latlon then returns the weather results."
    inputs = {'city': {'type': 'string', 'description': 'The name of the city required for weather gathering.'}}
    output_type = "string"

    def __init__(self, max_results=10, **kwargs):
        super().__init__()

    def forward(self, city) -> str:
        weather = self.get_weather_forecast(city)
        results = self.format_weather_for_agent(city, weather)
        print(results)
        if len(results) == 0:
            raise Exception("No results found! Try a less restrictive/shorter query.")
        
        return f"## Search Results\n\n{results}"

    def get_coordinates(self, city_name: str) -> [float, float]: 
        headers = {
            'User-Agent': 'MyGeocodingApp/1.0 (youremail@example.com)'  # Replace with your actual email
        }
        city_name = city_name.replace(" ", "+")
        base_url = "https://nominatim.openstreetmap.org/search"
        full_url = f"{base_url}?q={requests.utils.quote(city_name)}&format=json&limit=5"
    
        try:
            response = requests.get(full_url, headers=headers)
            response.raise_for_status()  # Raise an exception for bad status codes (4xx or 5xx)
            data = response.json()
    
            if data:  # Check if the response contains any results
                latitude = data[0]['lat']
                longitude = data[0]['lon']
                return latitude, longitude
            else:
                return None, None  # Return None if no results are found
    
        except requests.exceptions.RequestException as e:
            print(f"Error during geocoding: {e}")
            return None, None

    def get_weather_forecast(self, city: str) -> Optional[dict[str, Any]]:
        """
        Retrieves a 7-day weather forecast for a given city using the Open-Meteo API.

        Args:
            city: The name of the city.

        Returns:
            A dictionary containing the weather forecast data, or None if an error occurs
            or if the city's coordinates cannot be found.
        """
        latitude, longitude = self.get_coordinates(city)
        if latitude is None or longitude is None:
            print(f"Could not get coordinates for {city}.  Cannot retrieve weather forecast.")
            return None

        base_url = "https://api.open-meteo.com/v1/forecast"
        params = {
            "latitude": latitude,
            "longitude": longitude,
            "hourly": "temperature_2m",
            "daily": "temperature_2m_max,temperature_2m_min,precipitation_sum",
            "forecast_days": 7,
            "timezone": "auto"
        }

        try:
            response = requests.get(base_url, params=params)
            response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
            weather_data = response.json()
            return weather_data

        except requests.exceptions.RequestException as e:
            print(f"Error getting weather forecast: {e}")
            return None


    def format_weather_for_agent(self, city: str, weather_data: dict[str, Any]) -> str:
        """Formats the weather data into a string suitable for an agent's response."""

        if weather_data is None:
            return f"Could not retrieve weather forecast for {city}."

        daily = weather_data.get("daily", {})  # Use .get to handle missing data gracefully
        hourly = weather_data.get("hourly", {})

        # Example formatting (customize as needed)
        response_str = f"Weather forecast for {city}:\n"

        if daily:
            response_str += "Daily Forecast:\n"
            for i in range(len(daily.get("temperature_2m_max", []))): # Handle missing data
                max_temp = daily.get("temperature_2m_max", [None])[i]  # Use .get with default
                min_temp = daily.get("temperature_2m_min", [None])[i]
                precipitation = daily.get("precipitation_sum", [None])[i]
                response_str += (
                    f"Day {i+1}: Max: {max_temp}°C, Min: {min_temp}°C, Precipitation: {precipitation} mm\n"
                )

        if hourly:
            response_str += "\nHourly Forecast (Example):\n"
            # ... (Add hourly data formatting as needed) ...
            hourly_temps = hourly.get("temperature_2m", [])[:3] # Show first 3 hours
            for i, temp in enumerate(hourly_temps):
                response_str += f"Hour {i+1}: {temp}°C\n"
            # ...

        return response_str