add weather

This commit is contained in:
2025-06-06 20:14:50 -05:00
parent 6ec931265f
commit 4d2a0dc2d9
4 changed files with 203 additions and 133 deletions

View File

@ -10,6 +10,7 @@ from garfpy import (
Kroger, Kroger,
GarfAI, GarfAI,
GarfbotRespond, GarfbotRespond,
WeatherAPI,
) )
@ -28,6 +29,7 @@ garf_respond = GarfbotRespond()
garfield = GarfAI() garfield = GarfAI()
iputils = IPUtils() iputils = IPUtils()
kroger = Kroger() kroger = Kroger()
weather = WeatherAPI()
@garfbot.event @garfbot.event
@ -107,6 +109,12 @@ async def on_message(message):
) )
await garfield.garfpic(message, prompt) await garfield.garfpic(message, prompt)
# Weather
elif lower.startswith("garfbot weather "):
location = lower[16:]
embed = await weather.weather(location)
await message.channel.send(embed=embed)
# GarfBot help # GarfBot help
elif lower.strip() == "garfbot help": elif lower.strip() == "garfbot help":
embed = discord.Embed(title="**Need help?**", color=0x4D4D4D) embed = discord.Embed(title="**Need help?**", color=0x4D4D4D)

View File

@ -8,3 +8,4 @@ from .respond import GarfbotRespond
from .aod import aod_message from .aod import aod_message
from .qr import generate_qr from .qr import generate_qr
from .iputils import IPUtils from .iputils import IPUtils
from .weather import WeatherAPI

View File

@ -48,11 +48,11 @@ class GarfAI:
async with session.get(image_url) as resp: async with session.get(image_url) as resp:
if resp.status == 200: if resp.status == 200:
image_data = await resp.read() image_data = await resp.read()
ram_image = io.BytesIO(image_data) image = io.BytesIO(image_data)
ram_image.seek(0) image.seek(0)
timestamp = message.created_at.strftime("%Y%m%d%H%M%S") timestamp = message.created_at.strftime("%Y%m%d%H%M%S")
filename = f"{timestamp}_generated_image.png" filename = f"{timestamp}_generated_image.png"
sendfile = discord.File(fp=ram_image, filename=filename) sendfile = discord.File(fp=image, filename=filename)
try: try:
await message.channel.send(file=sendfile) await message.channel.send(file=sendfile)
except Exception as e: except Exception as e:

View File

@ -1,142 +1,203 @@
import discord import discord
import requests import aiohttp
import json import config
from garfpy import logger
class WeatherAPI: class WeatherAPI:
def __init__(self, api_key): def __init__(self, api_key=None):
self.api_key = api_key self.api_key = api_key or config.WEATHER_TOKEN
self.base_url = "https://api.openweathermap.org/data/2.5/weather" self.base_url = "https://api.openweathermap.org/data/2.5/weather"
def get_weather_by_zip(self, zip_code, country_code='US', units='metric'): def parse_location(self, location):
""" location = location.strip().lower()
Get weather data by zip code
if location.isdigit():
Args: if len(location) == 5:
zip_code (str): ZIP code return {"zip": f"{location},US"}
country_code (str): Country code (default: 'US') else:
units (str): 'metric', 'imperial', or 'standard' return {"zip": location}
"""
parts = location.split()
if len(parts) == 1:
return {"q": f"{parts[0]},US"}
elif len(parts) == 2:
city, second = parts
if len(second) == 2 and second.upper() not in [
"AK",
"AL",
"AR",
"AZ",
"CA",
"CO",
"CT",
"DE",
"FL",
"GA",
"HI",
"IA",
"ID",
"IL",
"IN",
"KS",
"KY",
"LA",
"MA",
"MD",
"ME",
"MI",
"MN",
"MO",
"MS",
"MT",
"NC",
"ND",
"NE",
"NH",
"NJ",
"NM",
"NV",
"NY",
"OH",
"OK",
"OR",
"PA",
"RI",
"SC",
"SD",
"TN",
"TX",
"UT",
"VA",
"VT",
"WA",
"WI",
"WV",
"WY",
"DC",
"AS",
"GU",
"MP",
"PR",
"VI",
]:
return {"q": f"{city},{second.upper()}"}
else:
return {"q": f"{city},{second},US"}
elif len(parts) == 3:
city, state, country = parts
return {"q": f"{city},{state},{country.upper()}"}
else:
# Check if last part looks like country code
if len(parts[-1]) == 2:
city_parts = parts[:-1]
country = parts[-1]
city_name = " ".join(city_parts)
return {"q": f"{city_name},{country.upper()}"}
elif len(parts) >= 2 and len(parts[-1]) == 2 and len(parts[-2]) <= 2:
city_parts = parts[:-2]
state = parts[-2]
country = parts[-1]
city_name = " ".join(city_parts)
return {"q": f"{city_name},{state},{country.upper()}"}
else:
city_name = " ".join(parts)
return {"q": f"{city_name},US"}
async def get_weather(self, location, units="metric"):
location_params = self.parse_location(location)
params = { params = {
'zip': f'{zip_code},{country_code}', **location_params,
'appid': self.api_key, "appid": self.api_key,
'units': units "units": units,
} }
try: try:
response = requests.get(self.base_url, params=params) async with aiohttp.ClientSession() as session:
response.raise_for_status() async with session.get(self.base_url, params=params) as response:
return response.json() response.raise_for_status()
return await response.json()
except requests.exceptions.RequestException as e: except aiohttp.ClientError as e:
print(f"Error fetching weather data: {e}") logger.error(f"Error fetching weather data for '{location}': {e}")
return None return None
def weather_embed(self, weather_data): def weather_embed(self, weather_data):
if not weather_data: if not weather_data:
embed = discord.Embed(
title="❌ Error",
description="Could not fetch weather data",
color=discord.Color.red(),
)
return embed
weather_emojis = {
"clear sky": "☀️",
"few clouds": "🌤️",
"scattered clouds": "",
"broken clouds": "☁️",
"shower rain": "🌦️",
"rain": "🌧️",
"thunderstorm": "⛈️",
"snow": "❄️",
"mist": "🌫️",
}
condition = weather_data["weather"][0]["description"].lower()
emoji = weather_emojis.get(condition, "🌍")
embed = discord.Embed( embed = discord.Embed(
title="❌ Error", title=f"{emoji} Weather in {weather_data['name']}",
description="Could not fetch weather data", description=f"{weather_data['weather'][0]['description'].title()}",
color=discord.Color.red() color=discord.Color.blue(),
) )
embed.add_field(
name="🌡️ Temperature",
value=f"{weather_data['main']['temp']}°C\nFeels like {weather_data['main']['feels_like']}°C",
inline=True,
)
embed.add_field(
name="💧 Humidity",
value=f"{weather_data['main']['humidity']}%",
inline=True,
)
embed.add_field(
name="🗜️ Pressure",
value=f"{weather_data['main']['pressure']} hPa",
inline=True,
)
if "wind" in weather_data:
embed.add_field(
name="💨 Wind Speed",
value=f"{weather_data['wind']['speed']} m/s",
inline=True,
)
if "visibility" in weather_data:
embed.add_field(
name="👁️ Visibility",
value=f"{weather_data['visibility'] / 1000} km",
inline=True,
)
embed.set_footer(
text=f"Lat: {weather_data['coord']['lat']}, Lon: {weather_data['coord']['lon']}"
)
return embed return embed
weather_emojis = {
'clear sky': '☀️',
'few clouds': '🌤️',
'scattered clouds': '',
'broken clouds': '☁️',
'shower rain': '🌦️',
'rain': '🌧️',
'thunderstorm': '⛈️',
'snow': '❄️',
'mist': '🌫️'
}
condition = weather_data['weather'][0]['description'].lower()
emoji = weather_emojis.get(condition, '🌍')
embed = discord.Embed(
title=f"{emoji} Weather in {weather_data['name']}",
description=f"{weather_data['weather'][0]['description'].title()}",
color=discord.Color.blue()
)
embed.add_field(
name="🌡️ Temperature",
value=f"{weather_data['main']['temp']}°C\nFeels like {weather_data['main']['feels_like']}°C",
inline=True
)
embed.add_field(
name="💧 Humidity",
value=f"{weather_data['main']['humidity']}%",
inline=True
)
embed.add_field(
name="🗜️ Pressure",
value=f"{weather_data['main']['pressure']} hPa",
inline=True
)
if 'wind' in weather_data:
embed.add_field(
name="💨 Wind Speed",
value=f"{weather_data['wind']['speed']} m/s",
inline=True
)
if 'visibility' in weather_data:
embed.add_field(
name="👁️ Visibility",
value=f"{weather_data['visibility']/1000} km",
inline=True
)
embed.set_footer(
text=f"Lat: {weather_data['coord']['lat']}, Lon: {weather_data['coord']['lon']}"
)
return embed
@commands.command(name='weather') async def weather(self, location):
async def weather_command(self, ctx, zip_code: str, country_code: str = 'US'): weather_data = await self.get_weather(location)
""" embed = self.weather_embed(weather_data)
Get weather by zip code return embed
Usage: !weather 10001 US
"""
await ctx.typing()
weather_data = await self.get_weather_by_zip(zip_code, country_code)
embed = self.create_weather_embed(weather_data)
await ctx.send(embed=embed)
# def display_weather(self, weather_data):
# """Pretty print weather information"""
# if not weather_data:
# print("No weather data available")
# return
# print(f"\n🌤 Weather for {weather_data['name']}")
# print(f"Temperature: {weather_data['main']['temp']}°C")
# print(f"Feels like: {weather_data['main']['feels_like']}°C")
# print(f"Condition: {weather_data['weather'][0]['description'].title()}")
# print(f"Humidity: {weather_data['main']['humidity']}%")
# print(f"Pressure: {weather_data['main']['pressure']} hPa")
# if 'visibility' in weather_data:
# print(f"Visibility: {weather_data['visibility']/1000} km")
# if __name__ == "__main__":
# API_KEY = "x"
# weather = WeatherAPI(API_KEY)
# zip_codes = ['10001', '90210', '60601']
# for zip_code in zip_codes:
# data = weather.get_weather_by_zip(zip_code)
# weather.display_weather(data)
# print("-" * 40)