|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
from typing import List, Literal |
|
|
|
from camel.toolkits.base import BaseToolkit |
|
from camel.toolkits.function_tool import FunctionTool |
|
|
|
|
|
class WeatherToolkit(BaseToolkit): |
|
r"""A class representing a toolkit for interacting with weather data. |
|
|
|
This class provides methods for fetching weather data for a given city |
|
using the OpenWeatherMap API. |
|
""" |
|
|
|
def get_openweathermap_api_key(self) -> str: |
|
r"""Retrieve the OpenWeatherMap API key from environment variables. |
|
|
|
Returns: |
|
str: The OpenWeatherMap API key. |
|
|
|
Raises: |
|
ValueError: If the API key is not found in the environment |
|
variables. |
|
""" |
|
|
|
OPENWEATHERMAP_API_KEY = os.environ.get('OPENWEATHERMAP_API_KEY') |
|
if not OPENWEATHERMAP_API_KEY: |
|
raise ValueError( |
|
"`OPENWEATHERMAP_API_KEY` not found in environment " |
|
"variables. Get `OPENWEATHERMAP_API_KEY` here: " |
|
"`https://openweathermap.org`." |
|
) |
|
return OPENWEATHERMAP_API_KEY |
|
|
|
def get_weather_data( |
|
self, |
|
city: str, |
|
temp_units: Literal['kelvin', 'celsius', 'fahrenheit'] = 'kelvin', |
|
wind_units: Literal[ |
|
'meters_sec', 'miles_hour', 'knots', 'beaufort' |
|
] = 'meters_sec', |
|
visibility_units: Literal['meters', 'miles'] = 'meters', |
|
time_units: Literal['unix', 'iso', 'date'] = 'unix', |
|
) -> str: |
|
r"""Fetch and return a comprehensive weather report for a given city |
|
as a string. The report includes current weather conditions, |
|
temperature, wind details, visibility, and sunrise/sunset times, |
|
all formatted as a readable string. |
|
|
|
The function interacts with the OpenWeatherMap API to |
|
retrieve the data. |
|
|
|
Args: |
|
city (str): The name of the city for which the weather information |
|
is desired. Format "City, CountryCode" (e.g., "Paris, FR" |
|
for Paris, France). If the country code is not provided, |
|
the API will search for the city in all countries, which |
|
may yield incorrect results if multiple cities with the |
|
same name exist. |
|
temp_units (Literal['kelvin', 'celsius', 'fahrenheit']): Units for |
|
temperature. (default: :obj:`kelvin`) |
|
wind_units |
|
(Literal['meters_sec', 'miles_hour', 'knots', 'beaufort']): |
|
Units for wind speed. (default: :obj:`meters_sec`) |
|
visibility_units (Literal['meters', 'miles']): Units for visibility |
|
distance. (default: :obj:`meters`) |
|
time_units (Literal['unix', 'iso', 'date']): Format for sunrise and |
|
sunset times. (default: :obj:`unix`) |
|
|
|
Returns: |
|
str: A string containing the fetched weather data, formatted in a |
|
readable manner. If an error occurs, a message indicating the |
|
error will be returned instead. |
|
|
|
Example of return string: |
|
"Weather in Paris, FR: 15°C, feels like 13°C. Max temp: 17°C, |
|
Min temp : 12°C. |
|
Wind: 5 m/s at 270 degrees. Visibility: 10 kilometers. |
|
Sunrise at 05:46:05 (UTC), Sunset at 18:42:20 (UTC)." |
|
|
|
Note: |
|
Please ensure that the API key is valid and has permissions |
|
to access the weather data. |
|
""" |
|
|
|
|
|
|
|
try: |
|
import pyowm |
|
except ImportError: |
|
raise ImportError( |
|
"Please install `pyowm` first. You can install it by running " |
|
"`pip install pyowm`." |
|
) |
|
|
|
OPENWEATHERMAP_API_KEY = self.get_openweathermap_api_key() |
|
owm = pyowm.OWM(OPENWEATHERMAP_API_KEY) |
|
mgr = owm.weather_manager() |
|
|
|
try: |
|
observation = mgr.weather_at_place(city) |
|
weather = observation.weather |
|
|
|
|
|
temperature = weather.temperature(temp_units) |
|
|
|
|
|
wind_data = observation.weather.wind(unit=wind_units) |
|
wind_speed = wind_data.get('speed') |
|
|
|
wind_deg = wind_data.get('deg', 'N/A') |
|
|
|
|
|
visibility_distance = observation.weather.visibility_distance |
|
visibility = ( |
|
str(visibility_distance) |
|
if visibility_units == 'meters' |
|
else str(observation.weather.visibility(unit='miles')) |
|
) |
|
|
|
|
|
sunrise_time = str(weather.sunrise_time(timeformat=time_units)) |
|
sunset_time = str(weather.sunset_time(timeformat=time_units)) |
|
|
|
|
|
weather_report = ( |
|
f"Weather in {city}: " |
|
f"{temperature['temp']}°{temp_units.title()}, " |
|
f"feels like " |
|
f"{temperature['feels_like']}°{temp_units.title()}. " |
|
f"Max temp: {temperature['temp_max']}°{temp_units.title()}, " |
|
f"Min temp: {temperature['temp_min']}°{temp_units.title()}. " |
|
f"Wind: {wind_speed} {wind_units} at {wind_deg} degrees. " |
|
f"Visibility: {visibility} {visibility_units}. " |
|
f"Sunrise at {sunrise_time}, Sunset at {sunset_time}." |
|
) |
|
|
|
return weather_report |
|
|
|
except Exception as e: |
|
error_message = ( |
|
f"An error occurred while fetching weather data for {city}: " |
|
f"{e!s}." |
|
) |
|
return error_message |
|
|
|
def get_tools(self) -> List[FunctionTool]: |
|
r"""Returns a list of FunctionTool objects representing the |
|
functions in the toolkit. |
|
|
|
Returns: |
|
List[FunctionTool]: A list of FunctionTool objects |
|
representing the functions in the toolkit. |
|
""" |
|
return [ |
|
FunctionTool(self.get_weather_data), |
|
] |
|
|