Merge pull request 'jonbot' (#13) from jonbot into main
All checks were successful
Garfbot CI/CD Deployment / Deploy (push) Successful in 1m17s

Reviewed-on: #13
This commit is contained in:
2026-06-19 06:05:00 +00:00
8 changed files with 172 additions and 67 deletions

View File

@@ -23,7 +23,7 @@ jobs:
docker compose down docker compose down
fi fi
docker build -t git.crate.zip/crate/garfbot:latest . docker build -t git.crate.zip/crate/garfbot:latest .
docker compose up -d docker compose up -d --build
else else
docker restart garfbot docker restart garfbot
fi fi

View File

@@ -2,6 +2,19 @@ services:
garfbot: garfbot:
image: git.crate.zip/crate/garfbot:latest image: git.crate.zip/crate/garfbot:latest
container_name: garfbot container_name: garfbot
build:
context: .
dockerfile: Dockerfile
restart: always restart: always
volumes: volumes:
- /home/crate/garfbot:/usr/src/app - ../garfbot:/usr/src/app
jonbot:
image: git.crate.zip/crate/jonbot:latest
container_name: jonbot
build:
context: ./jonbot
dockerfile: Dockerfile
restart: always
volumes:
- ../garfbot/jonbot:/usr/src/app

View File

@@ -1,53 +0,0 @@
import config
import openai
import discord
import asyncio
import os
openai.api_key = config.OPENAI_TOKEN
jonkey = config.JONBOT_TOKEN
model = config.TXT_MODEL
intents = discord.Intents.default()
intents.messages = True
intents.message_content = True
client = discord.Client(intents=intents)
@client.event
async def on_ready():
print(f"Logged in as {client.user.name} running {model}.", flush=True)
@client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.lower().startswith("hey jon") or isinstance(message.channel, discord.DMChannel):
question = message.content[7:] if message.content.lower().startswith("hey jon") else message.content
try:
response = openai.ChatCompletion.create(
model=model,
messages=[
{"role": "system", "content": "Pretend you are friendly Jon Arbuckle."},
{"role": "user", "content": f"{question}"}
],
max_tokens=400
)
answer = response['choices'][0]['message']['content']
answer = answer.replace("AI language model", "American citizen")
answer = answer.replace("language model AI", "citizen of the United States")
await message.channel.send(answer)
except Exception as e:
e = str(e)
await message.channel.send(f"`JonBot Error: {e}`")
async def jonbot_connect():
while True:
try:
await client.start(jonkey)
except Exception as e:
e = str(e)
logger.error(f"Jonbot couldn't connect! {e}")
await asyncio.sleep(60)
if __name__ == "__main__":
asyncio.run(jonbot_connect())

View File

@@ -1,4 +1,3 @@
import re
import config import config
import asyncio import asyncio
import discord import discord

View File

@@ -1,12 +1,11 @@
# garfpy/__init__.py # garfpy/__init__.py
from .log import logger from .log import logger as logger
from .help import help from .help import help as help
from .kroger import Kroger from .kroger import Kroger as Kroger
from .kroger import Kroger from .garfai import GarfAI as GarfAI
from .garfai import GarfAI from .respond import GarfbotRespond as GarfbotRespond
from .respond import GarfbotRespond from .aod import aod_message as aod_message
from .aod import aod_message from .qr import generate_qr as generate_qr
from .qr import generate_qr from .iputils import IPUtils as IPUtils
from .iputils import IPUtils from .weather import WeatherAPI as WeatherAPI
from .weather import WeatherAPI

View File

@@ -1,5 +1,4 @@
import os import os
import re
import json import json
import discord import discord
from garfpy import logger from garfpy import logger

30
jonbot/Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
FROM python:alpine
WORKDIR /usr/src/app
RUN apk update && \
apk add --no-cache \
iputils \
bind-tools \
nmap \
gcc \
musl-dev \
jpeg-dev \
zlib-dev \
freetype-dev \
lcms2-dev \
openjpeg-dev \
tiff-dev \
tk-dev \
tcl-dev
RUN pip3 install --no-cache-dir \
config \
discord \
openai \
aiohttp \
requests \
wikipedia \
pillow \
qrcode
CMD [ "python", "jonbot.py" ]

118
jonbot/jonbot.py Normal file
View File

@@ -0,0 +1,118 @@
import config
import openai
from openai import AsyncOpenAI
import discord
from discord.ext import commands
import asyncio
import logging
from logging.handlers import TimedRotatingFileHandler
logger = logging.getLogger("garflog")
logger.setLevel(logging.INFO)
formatter = logging.Formatter(
"%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
)
file_handler = TimedRotatingFileHandler(
"jonbot.log",
when="midnight",
interval=1,
backupCount=7,
delay=True,
)
file_handler.setFormatter(formatter)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
if not logger.hasHandlers():
logger.addHandler(file_handler)
logger.addHandler(console_handler)
openai.api_key = config.OPENAI_TOKEN
jonkey = config.JONBOT_TOKEN
model = config.TXT_MODEL
intents = discord.Intents.default()
intents.messages = True
intents.message_content = True
client = commands.Bot(
command_prefix=["Jonbot ", "jonbot ", "Jon", "jon"],
case_insensitive=True,
intents=intents,
)
@client.event
async def on_ready():
print(f"Logged in as {client.user.name} running {model}.", flush=True)
@client.command(name="chat")
async def jonchat(ctx, *, prompt):
if "is this true" in prompt.lower():
messages = [msg async for msg in ctx.channel.history(limit=2)]
prompt = messages[1].content
prompt = f"Is this true: {prompt}"
answer = await generate_chat(prompt)
logger.info(
f"Chat Request - User: {ctx.author.name}, Server: {ctx.guild.name}, Prompt: {prompt}"
)
await ctx.reply(answer)
@client.event
async def on_message(message):
if message.author == client.user:
return
content = message.content.strip()
lower = content.lower()
if lower.startswith("hey jon") or isinstance(
message.channel, discord.DMChannel
):
ctx = await client.get_context(message)
await jonchat(ctx, prompt=content)
oai = AsyncOpenAI(
api_key=config.OPENAI_TOKEN,
base_url=config.BASE_URL,
)
async def generate_chat(self, question: str) -> str:
try:
response = await oai.chat.completions.create(
model=self.txtmodel,
messages=[
{"role": "system", "content": self.sysprompt},
{"role": "user", "content": question},
],
max_tokens=400,
temperature=1.2,
)
answer = response.choices[0].message.content
return answer
except openai.BadRequestError as e:
logger.error(e)
return f"`JonBot Error: {e}`"
except openai.APIError as e:
logger.error(e)
return "`JonBot Error: Odie`"
except Exception as e:
logger.error(e)
return "`JonBot Error: Liz`"
async def jonbot_connect():
while True:
try:
await client.start(jonkey)
except Exception as e:
e = str(e)
logger.error(f"Jonbot couldn't connect! {e}")
await asyncio.sleep(60)
if __name__ == "__main__":
asyncio.run(jonbot_connect())