Compare commits

4 Commits

Author SHA1 Message Date
bfef23eb72 revert URL cleaning and update year on license
All checks were successful
Garfbot CI/CD Deployment / Deploy (push) Successful in 16s
2026-03-14 22:50:23 -05:00
940b6b80d9 yolo
All checks were successful
Garfbot CI/CD Deployment / Deploy (push) Successful in 59s
2026-03-07 14:15:08 -06:00
f77940dff9 Merge pull request 'enable garfbot context awareness when user ask "is this true"' (#9) from smart-garf into main
All checks were successful
Garfbot CI/CD Deployment / Deploy (push) Successful in 46s
Reviewed-on: #9

This is a very simple implementation but I don't want to over-complicate the source with trying to add to much at once -- might come back to this one or do some more interesting things with context awareness
2026-01-04 12:19:55 +00:00
68696e25f0 test smart garf and fix weather error log 2026-01-04 06:13:15 -06:00
7 changed files with 66 additions and 26 deletions

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@ config.py
__pycache__/
garfpy/__pycache__/
*.venv*
.idea
*.json
*.old
*.log*

View File

@@ -1,6 +1,6 @@
MIT No Attribution
Copyright 2025 Aaron Crate
Copyright 2026 Aaron Crate
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software

View File

@@ -2,14 +2,6 @@ services:
garfbot:
image: git.crate.zip/crate/garfbot:latest
container_name: garfbot
environment:
- TXT_MODEL=${TXT_MODEL}
- IMG_MODEL=${IMG_MODEL}
- GARFBOT_TOKEN=${GARFBOT_TOKEN}
- OPENAI_TOKEN=${OPENAI_TOKEN}
- WEATHER_TOKEN=${WEATHER_TOKEN}
- KROGER_ID=${KROGER_ID}
- KROGER_SECRET=${KROGER_SECRET}
restart: always
volumes:
- /home/crate/garfbot:/usr/src/app

View File

@@ -1,7 +1,9 @@
import os
import re
import config
import asyncio
import discord
from discord.ext import commands
from urllib.parse import urlparse, parse_qs
from garfpy import (
help,
@@ -16,9 +18,10 @@ from garfpy import (
)
garfkey = os.getenv("GARFBOT_TOKEN")
txtmodel = os.getenv("TXT_MODEL")
imgmodel = os.getenv("IMG_MODEL")
# gapikey = config.GIF_TOKEN
garfkey = config.GARFBOT_TOKEN
txtmodel = config.TXT_MODEL
imgmodel = config.IMG_MODEL
intents = discord.Intents.default()
intents.members = True
@@ -39,6 +42,36 @@ kroger = Kroger()
weather = WeatherAPI()
URL_PATTERNS = [
r'https?://(?:www\.)?youtube\.com/watch\?[^\s]*',
r'https?://youtu\.be/[^\s]*',
r'https?://(?:open\.)?spotify\.com/[^\s]*',
]
def clean_url(url):
try:
parsed = urlparse(url)
if 'youtube.com' in parsed.hostname:
params = parse_qs(parsed.query)
video_id = params.get('v', [None])[0]
if not video_id:
return None
# timestamp = params.get('t', [None])[0]
# if timestamp:
# return f"https://www.youtube.com/watch?v={video_id}&t={timestamp}"
return f"https://www.youtube.com/watch?v={video_id}"
if 'youtu.be' in parsed.hostname:
return f"https://youtu.be{parsed.path}"
if 'spotify.com' in parsed.hostname:
return f"https://open.spotify.com{parsed.path}"
except Exception:
return None
@garfbot.event
async def on_ready():
try:
@@ -117,6 +150,9 @@ async def garfbot_weather(ctx, *, location):
@garfbot.command(name="chat")
async def garfchat(ctx, *, prompt):
if "is this true" in prompt.lower():
messages = [msg async for msg in ctx.channel.history(limit=2)]
prompt = messages[1].content
answer = await garfield.generate_chat(prompt)
logger.info(
f"Chat Request - User: {ctx.author.name}, Server: {ctx.guild.name}, Prompt: {prompt}"
@@ -147,6 +183,19 @@ async def on_message(message):
content = message.content.strip()
lower = content.lower()
# # Remove tracking stuff from youtube and spotify links
# cleaned_urls = []
# for pattern in URL_PATTERNS:
# for match in re.finditer(pattern, message.content):
# cleaned = clean_url(match.group(0))
# if cleaned and cleaned != match.group(0):
# cleaned_urls.append(cleaned)
# if cleaned_urls:
# links = '\n'.join(cleaned_urls)
# await message.reply(f"🔗 Cleaned link{'s' if len(cleaned_urls) > 1 else ''}:\n{links}")
# Chats & pics
if lower.startswith("hey garfield") or isinstance(
message.channel, discord.DMChannel
@@ -180,7 +229,7 @@ async def on_message(message):
async def garfbot_connect():
while True:
try:
await garfbot.start(garfkey) # type: ignore
await garfbot.start(garfkey)
except Exception as e:
e = str(e)
logger.error(f"Garfbot couldn't connect! {e}")

View File

@@ -1,6 +1,6 @@
import io
import os
import openai
import config
import aiohttp
import asyncio
import discord
@@ -11,9 +11,9 @@ from garfpy import logger
class GarfAI:
def __init__(self):
self.openaikey = os.getenv('OPENAI_TOKEN')
self.txtmodel = os.getenv('TXT_MODEL')
self.imgmodel = os.getenv('IMG_MODEL')
self.openaikey = config.OPENAI_TOKEN
self.txtmodel = config.TXT_MODEL
self.imgmodel = config.IMG_MODEL
self.image_request_queue = asyncio.Queue()
async def garfpic(self, ctx, prompt):
@@ -82,7 +82,7 @@ class GarfAI:
try:
client = AsyncOpenAI(api_key=self.openaikey)
response = await client.chat.completions.create(
model=self.txtmodel, # type: ignore
model=self.txtmodel,
messages=[
{
"role": "system",

View File

@@ -1,4 +1,4 @@
import os
import config
import requests
from base64 import b64encode
from garfpy import logger
@@ -6,8 +6,8 @@ from garfpy import logger
class Kroger:
def __init__(self):
self.client_id = os.getenv('CLIENT_ID')
self.client_secret = os.getenv('CLIENT_SECRET')
self.client_id = config.CLIENT_ID
self.client_secret = config.CLIENT_SECRET
self.auth = b64encode(
f"{self.client_id}:{self.client_secret}".encode()
).decode()

View File

@@ -1,5 +1,5 @@
import os
import re
import config
import discord
import aiohttp
from garfpy import logger
@@ -7,7 +7,7 @@ from garfpy import logger
class WeatherAPI:
def __init__(self, api_key=None):
self.api_key = api_key or os.getenv("WEATHER_TOKEN")
self.api_key = api_key or config.WEATHER_TOKEN
self.base_url = "https://api.openweathermap.org/data/2.5/weather"
def parse_location(self, location):
@@ -126,7 +126,7 @@ class WeatherAPI:
response.raise_for_status()
return await response.json()
except aiohttp.ClientError as e:
logger.error(f"Error fetching weather data for '{location}'")
logger.error(f"Error fetching weather data for '{location}' - {e}")
await ctx.send(f"`Error fetching weather data for '{location}'`")
return None