File size: 5,663 Bytes
b36a86c |
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 |
from datetime import datetime
from typing import Optional
import httpx
from pydantic import BaseModel, Field
from simpleaichat import AIChat
from utils.env import get_from_env
WEATHERAPI_BASE_URL = "http://api.weatherapi.com/v1"
class WeatherAPI(BaseModel):
"""Wrapper for WeatherAPI
Docs for using:
1. Go to https://www.weatherapi.com/ and sign up for an API key
2. Save your API WEATHERAPI_API_KEY env variable
"""
weatherapi_key: Optional[str] = get_from_env("WEATHERAPI_API_KEY")
forecast_response: dict = None
warning: str = ""
def _format_weather_info(self):
current = self.forecast_response["current"]
forecast = self.forecast_response["forecast"]["forecastday"][0]
location_name = self.forecast_response["location"]["name"]
current_status = current["condition"]["text"]
wind_speed = current["wind_kph"]
wind_degree = current["wind_degree"]
humidity = current["humidity"]
cloud = current["cloud"]
feels_like = current["feelslike_c"]
current_temp = current["temp_c"]
min_temp = forecast["day"]["mintemp_c"]
max_temp = forecast["day"]["maxtemp_c"]
total_precip_mm = forecast["day"]["totalprecip_mm"]
total_snow_cm = forecast["day"]["totalsnow_cm"]
chance_of_rain = forecast["day"]["daily_chance_of_rain"]
chance_of_snow = forecast["day"]["daily_chance_of_snow"]
status = forecast["day"]["condition"]["text"]
is_day = current["is_day"]
sunrise = forecast["astro"]["sunrise"]
sunset = forecast["astro"]["sunset"]
# Convert the sunrise and sunset times to datetime objects
sunrise_time = datetime.strptime(sunrise, "%H:%M %p").time()
# sunset_time = datetime.strptime(sunset, "%I:%M %p").time()
# Get the current time
now = datetime.now().time()
# Check if the current time is before or after sunrise
if now < sunrise_time:
next_event = f"The sun will rise at {sunrise}."
else:
next_event = f"The sun will set at {sunset}."
rain_times = []
snow_times = []
for i, c in enumerate(forecast["hour"]):
if c["will_it_rain"]:
rain_times.append(c["time"])
if c["will_it_snow"]:
snow_times.append(c["time"])
results = (
f"In {location_name}, the current weather is as follows:\n"
f"Detailed status: {current_status}\n"
f"Wind speed: {wind_speed} kph, direction: {wind_degree}°\n"
f"Humidity: {humidity}%\n"
f"Temperature: \n"
f" - Current: {current_temp}°C\n"
f" - High: {max_temp}°C\n"
f" - Low: {min_temp}°C\n"
f" - Feels like: {feels_like}°C\n"
f"Cloud cover: {cloud}%\n"
f"Precipitation:\n"
f" - Total precipitation: {total_precip_mm} mm\n"
f" - Total snowfall: {total_snow_cm} cm\n"
f"Chance of precipitation:\n"
f" - Chance of rain: {chance_of_rain}%\n"
f" - Chance of snow: {chance_of_snow}%\n"
f"Weather status for the day: {status}\n"
+ (
f"It is currently daytime.\n"
if is_day
else f"It is currently nighttime.\n"
)
+ next_event
)
if rain_times:
results += "There is a chance of rain at the following times:\n"
for time in rain_times:
results += f"- {time}\n"
if snow_times:
results += "There is a chance of snow at the following times:\n"
for time in snow_times:
results += f"- {time}\n"
return f"{self.warning}\n{results}"
def get_forecast(self, location: dict):
"""Get the current weather information for a specified location."""
forecast_url = f"{WEATHERAPI_BASE_URL}/forecast.json"
forecast_params = {
"key": self.weatherapi_key,
"q": location["city"],
"format": "json",
"days": 1,
}
r = httpx.get(forecast_url, params=forecast_params).json()
self.forecast_response = r
def run(self, query) -> str | None:
location = get_location(query)
if not location:
self.warning = (
"Could not identify any location in the query. Defaulted to Halifax."
)
location = {"city": "Halifax", "country": "CA"}
self.get_forecast(location)
weather_info = self._format_weather_info()
return weather_info
class GetLocationMetadata(BaseModel):
"""Location information"""
city: str = Field(description="The city of the location.")
state: int = Field(
description="The state or province of the location. Must be the full state name"
)
state_code: int = Field(
description="The state or province of the location. Must be a 2-char string."
)
country: str = Field(
description="The country of the location. Country must be a 2-char string"
)
def get_location(query: str) -> dict | None:
params = {"temperature": 0.0, "max_tokens": 100}
system_prompt = (
"You reply ONLY with the location information. If no location is detected, respond with None in "
"each field"
)
ai = AIChat(system=system_prompt, params=params)
# noinspection PyTypeChecker
location: dict = ai(query, output_schema=GetLocationMetadata)
if location["city"] == "None":
return None
return location
|