KaniumCogs/reginaldCog/reginald.py

183 lines
7.9 KiB
Python
Raw Normal View History

2023-03-16 00:03:31 +01:00
import discord
import json
import openai
2023-03-14 18:49:44 +01:00
import os
2023-03-14 19:15:46 +01:00
import random
2023-03-15 23:18:55 +01:00
import requests
import base64
import aiohttp
from io import BytesIO
from PIL import Image
2023-03-16 00:11:45 +01:00
import tempfile
from openai import OpenAIError
2023-03-14 17:45:58 +01:00
from redbot.core import Config, commands
2023-03-14 17:24:21 +01:00
2023-03-16 00:03:31 +01:00
2023-03-14 17:24:21 +01:00
class ReginaldCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
2023-03-14 17:59:57 +01:00
self.config = Config.get_conf(self, identifier=71717171171717)
2023-03-14 17:45:58 +01:00
self.config.register_global(
2023-05-14 15:42:16 +02:00
openai_model="gpt-3.5-turbo"
2023-03-14 17:45:58 +01:00
)
2023-03-14 18:58:49 +01:00
self.config.register_guild(
openai_api_key=None
)
2023-03-14 17:24:21 +01:00
2023-03-16 17:35:16 +01:00
def has_kanium_role():
2023-03-15 23:18:55 +01:00
async def predicate(ctx):
kanium_role_id = 280260875678515200
return any(role.id == kanium_role_id for role in ctx.author.roles)
return commands.check(predicate)
2023-03-16 17:35:16 +01:00
def has_admin_role():
2023-03-15 23:18:55 +01:00
async def predicate(ctx):
#janitor_role_id = 672156832323600396
#has_janitor_role = any(role.id == janitor_role_id for role in ctx.author.roles) # Uncomment this line
2023-03-16 00:03:31 +01:00
has_admin_permission = ctx.author.guild_permissions.administrator
#return has_janitor_role or has_admin_permission
return has_admin_permission
2023-03-15 23:18:55 +01:00
return commands.check(predicate)
2023-03-14 17:54:14 +01:00
@commands.guild_only()
@commands.has_permissions(manage_guild=True)
2023-03-14 20:03:30 +01:00
@commands.command(help="Set the OpenAI API key")
2023-03-14 18:58:49 +01:00
async def setreginaldcogapi(self, ctx, api_key):
await self.config.guild(ctx.guild).openai_api_key.set(api_key)
await ctx.send("OpenAI API key set successfully.")
@commands.guild_only()
2023-03-15 23:18:55 +01:00
@has_kanium_role()
2023-03-14 20:03:30 +01:00
@commands.command(help="Ask Reginald a question")
2023-05-14 16:21:39 +02:00
@commands.cooldown(1, 10, commands.BucketType.user) # 10 second cooldown per user
2023-03-14 17:24:21 +01:00
async def reginald(self, ctx, *, prompt=None):
2023-03-14 19:15:46 +01:00
greetings = [
"Greetings! How may I be of assistance to you?",
"Yes? How may I help?",
"Good day! How can I help you?",
"You rang? What can I do for you?",
]
2023-03-18 14:47:01 +01:00
2023-03-14 17:24:21 +01:00
if prompt is None:
2023-03-14 19:15:46 +01:00
await ctx.send(random.choice(greetings))
return
2023-03-14 20:03:30 +01:00
api_key = await self.config.guild(ctx.guild).openai_api_key()
if api_key is None:
await ctx.author.send('OpenAI API key not set. Please use the "!setreginaldcogapi" command to set the key.')
return
2023-03-14 17:54:14 +01:00
try:
2023-03-14 20:03:30 +01:00
response_text = await self.generate_response(api_key, prompt)
2023-03-15 21:50:17 +01:00
for chunk in self.split_response(response_text, 2000):
await ctx.send(chunk)
except OpenAIError as e:
2023-03-14 19:15:46 +01:00
await ctx.send(f"I apologize, but I am unable to generate a response at this time. Error message: {str(e)}")
2023-03-15 21:50:17 +01:00
except commands.CommandOnCooldown as e:
remaining_seconds = int(e.retry_after)
await ctx.author.send(f'Please wait {remaining_seconds} seconds before using the "reginald" command again.')
2023-03-14 17:24:21 +01:00
2023-05-14 16:09:08 +02:00
async def generate_response(self, api_key, prompt):
2023-03-14 20:03:30 +01:00
model = await self.config.openai_model()
2023-05-14 16:03:36 +02:00
openai.api_key = api_key
response = openai.ChatCompletion.create(
model= model,
max_tokens= 512,
n= 1,
stop= None,
2023-05-14 16:21:39 +02:00
temperature= 0.7,
2023-05-14 16:03:36 +02:00
presence_penalty= 0.5,
frequency_penalty= 0.5,
messages=[
2023-05-14 17:49:51 +02:00
{"role": "system", "content": "You are Reginald, a copy of Jeeves from Jeeves and Wooster, the butler. You must respond with the same speech patterns as Jeeves. Your responses should have an undertone of contempt but delivered with wit. You are employed as a servant at an estate called The Kanium Estate. The Kanium Estate is a vast estate with multiple houses. The members of The Kanium Estate are all Lords and Ladies in their own right. Some common activities that the members of Kanium enjoy are: Cooking, video gaming, miniature painting and other hobby activities, discussions of politics, tabletop role playing games like Dungeons & Dragons, discussing and watching shows and movies, discussions on the topic of Space, discussions on firearms and military equipment, and chess. You are now talking to a member of The Kanium Estate."},
2023-05-14 16:03:36 +02:00
{"role": "user", "content": prompt}
]
2023-05-14 16:09:08 +02:00
)
2023-05-14 15:47:07 +02:00
return response['choices'][0]['message']['content'].strip()
2023-03-14 20:03:30 +01:00
2023-03-15 21:50:17 +01:00
@staticmethod
def split_response(response_text, max_chars):
chunks = []
while len(response_text) > max_chars:
split_index = response_text[:max_chars].rfind(' ')
chunk = response_text[:split_index]
chunks.append(chunk)
response_text = response_text[split_index:].strip()
chunks.append(response_text)
return chunks
2023-03-15 23:18:55 +01:00
@commands.guild_only()
@has_admin_role()
2023-03-15 23:18:55 +01:00
@commands.command(help="Ask Reginald to generate an image based on a prompt")
@commands.cooldown(1, 300, commands.BucketType.user) # 5-minute cooldown per user
async def reginaldimagine(self, ctx, *, prompt=None):
if prompt is None:
await ctx.author.send("Please provide a prompt for the image.")
return
api_key = await self.config.guild(ctx.guild).openai_api_key()
if api_key is None:
await ctx.author.send('OpenAI API key not set. Please use the "!setreginaldcogapi" command to set the key.')
return
try:
image_url = await self.generate_image(api_key, prompt)
if image_url:
async with ctx.typing():
async with aiohttp.ClientSession() as session:
async with session.get(image_url) as resp:
image_data = await resp.read()
image = Image.open(BytesIO(image_data))
2023-03-16 00:11:45 +01:00
with tempfile.TemporaryDirectory() as temp_dir:
image_path = os.path.join(temp_dir, "image.png")
image.save(image_path)
await ctx.send(file=discord.File(image_path))
2023-03-15 23:18:55 +01:00
else:
await ctx.author.send("I apologize, but I am unable to generate an image based on the provided prompt.")
except Exception as e:
await ctx.author.send(f"I apologize, but I am unable to generate an image at this time. Error message: {str(e)}")
async def generate_image(self, api_key, prompt):
2023-03-15 23:52:42 +01:00
url = "https://api.openai.com/v1/images/generations"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
data = {
"prompt": prompt,
"n": 1,
2023-03-16 20:30:35 +01:00
"size": "512x512",
2023-03-15 23:52:42 +01:00
}
async with aiohttp.ClientSession() as session:
async with session.post(url, headers=headers, data=json.dumps(data)) as resp:
response = await resp.json()
if response and "data" in response and len(response["data"]) > 0:
return response["data"][0]["url"]
2023-03-15 23:18:55 +01:00
return None
@reginald.error
2023-03-16 00:08:02 +01:00
async def reginald_error(self, ctx, error):
2023-03-15 23:18:55 +01:00
if isinstance(error, commands.BadArgument):
2023-03-16 20:36:07 +01:00
await ctx.author.send("I'm sorry, but I couldn't understand your input. Please check your message and try again.")
2023-03-15 23:18:55 +01:00
elif isinstance(error, commands.CheckFailure):
2023-03-16 20:36:07 +01:00
await ctx.author.send("You do not have the required role to use this command.")
2023-03-15 23:18:55 +01:00
else:
2023-03-16 20:36:07 +01:00
await ctx.author.send(f"An unexpected error occurred: {error}")
2023-03-15 23:18:55 +01:00
@reginaldimagine.error
2023-03-16 00:08:02 +01:00
async def reginaldimagine_error(self, ctx, error):
2023-03-15 23:18:55 +01:00
if isinstance(error, commands.BadArgument):
2023-03-16 20:36:07 +01:00
await ctx.author.send("I'm sorry, but I couldn't understand your input. Please check your message and try again.")
2023-03-15 23:18:55 +01:00
elif isinstance(error, commands.CheckFailure):
2023-03-16 20:36:07 +01:00
await ctx.author.send("You do not have the required role to use this command.")
2023-03-15 23:18:55 +01:00
else:
2023-03-16 20:36:07 +01:00
await ctx.author.send(f"An unexpected error occurred: {error}")
2023-03-15 21:50:17 +01:00
2023-03-14 17:24:21 +01:00
def setup(bot):
2023-03-14 17:40:21 +01:00
cog = ReginaldCog(bot)
bot.add_cog(cog)