KaniumCogs/reginaldCog/reginald.py

124 lines
5.4 KiB
Python
Raw Normal View History

2023-03-16 00:03:31 +01:00
import discord
import openai
2023-03-14 17:45:58 +01:00
from redbot.core import Config, commands
2023-03-14 17:24:21 +01:00
class ReginaldCog(commands.Cog):
def __init__(self, bot):
self.bot = bot
2023-06-03 17:23:31 +02:00
self.config = Config.get_conf(self, identifier=71717171171717)
default_global = {"openai_model": "gpt-3.5-turbo"}
default_guild = {"openai_api_key": None, "memory": {}, "shared_memory": []}
self.config.register_global(**default_global)
self.config.register_guild(**default_guild)
2023-03-14 17:24:21 +01:00
2023-06-03 19:03:23 +02:00
async def is_admin(self, ctx):
admin_role = await self.config.guild(ctx.guild).admin_role()
return discord.utils.get(ctx.author.roles, name=admin_role) is not None or ctx.author.guild_permissions.administrator
2023-03-15 23:18:55 +01:00
2023-06-03 19:03:23 +02:00
async def is_allowed(self, ctx):
allowed_role = await self.config.guild(ctx.guild).allowed_role()
return discord.utils.get(ctx.author.roles, name=allowed_role) is not None
2023-06-03 18:18:22 +02:00
@commands.command(name="reginald_allowrole", help="Allow a role to use the Reginald command")
2023-06-03 18:02:59 +02:00
@commands.has_permissions(administrator=True)
async def allow_role(self, ctx, role: discord.Role):
await self.config.guild(ctx.guild).allowed_role.set(role.name)
await ctx.send(f"The {role.name} role is now allowed to use the Reginald command.")
2023-06-03 18:02:59 +02:00
2023-06-03 18:18:22 +02:00
@commands.command(name="reginald_disallowrole", help="Remove a role's ability to use the Reginald command")
2023-06-03 18:02:59 +02:00
@commands.has_permissions(administrator=True)
2023-06-03 19:03:23 +02:00
async def disallow_role(self, ctx):
await self.config.guild(ctx.guild).allowed_role.clear()
await ctx.send(f"The role's permission to use the Reginald command has been revoked.")
2023-03-15 23:18:55 +01:00
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-14 20:03:30 +01:00
@commands.command(help="Ask Reginald a question")
@commands.cooldown(1, 10, commands.BucketType.user)
2023-03-14 17:24:21 +01:00
async def reginald(self, ctx, *, prompt=None):
2023-06-03 19:20:01 +02:00
if not await self.is_admin(ctx) and not await self.is_allowed(ctx):
raise commands.CheckFailure("You do not have the required role to use this command.")
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:
user_id = str(ctx.author.id)
memory = await self.config.guild(ctx.guild).memory()
shared_memory = await self.config.guild(ctx.guild).shared_memory()
if user_id not in memory:
memory[user_id] = []
memory[user_id].append({"role": "user", "content": prompt})
response_text = await self.generate_response(api_key, memory[user_id] + shared_memory)
memory[user_id].append({"role": "assistant", "content": response_text})
await self.config.guild(ctx.guild).memory.set(memory)
# Optionally, add to shared memory if relevant
shared_memory.append({"role": "user", "content": prompt})
shared_memory.append({"role": "assistant", "content": response_text})
await self.config.guild(ctx.guild).shared_memory.set(shared_memory)
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-14 17:24:21 +01:00
async def generate_response(self, api_key, messages):
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,
temperature=0.7,
presence_penalty=0.5,
frequency_penalty=0.5,
messages=messages
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[:max_chars] if split_index == -1 else response_text[:split_index]
chunks.append(chunk.strip())
response_text = response_text[split_index:].strip() if split_index != -1 else response_text[max_chars:]
2023-03-15 21:50:17 +01:00
chunks.append(response_text)
return chunks
2023-03-15 23:18:55 +01:00
@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
2023-03-14 17:24:21 +01:00
def setup(bot):
bot.add_cog(ReginaldCog(bot))