Merge pull request #21 from Paillat-dev/dev

Dev
This commit is contained in:
Paillat
2022-12-19 14:33:39 +01:00
committed by GitHub
8 changed files with 192 additions and 61 deletions

1
.gitignore vendored
View File

@@ -163,3 +163,4 @@ key.txt
data.db data.db
premium-key.txt premium-key.txt
premium.db premium.db
guildscount.py

View File

@@ -42,6 +42,8 @@ You can always disable the bot by doing **/disable** and delete your api key fro
*/default* - Set the advanced settings to their default values */default* - Set the advanced settings to their default values
*/redo* - Redo the last answer
*/help* - Show this command list */help* - Show this command list
# Support me # Support me
@@ -75,9 +77,10 @@ After that you will normally be able to access some new channels in our discord
- [ ] Publish a GOOD docker image on dockerhub and add some more instructions about how to selfhost - [ ] Publish a GOOD docker image on dockerhub and add some more instructions about how to selfhost
- [ ] Add a log and updates channel option and a way for devs to send messages to that channel on all servers. - [ ] Add a log and updates channel option and a way for devs to send messages to that channel on all servers.
- [ ] Add moderation. - [ ] Add moderation.
- [ ] Add DateHour in prompts
- [ ] Add /redo
- [ ] Add TOKENS warnings (when setting the bot up, people dosen't understand tha ot uses their tokens) - [ ] Add TOKENS warnings (when setting the bot up, people dosen't understand tha ot uses their tokens)
- [ ] Add a /continue command - you know
- [x] Add DateHour in prompts
- [x] Add /redo
- [x] Add uses count reset after 24h - [x] Add uses count reset after 24h
- [x] Organize code in COGs - [x] Organize code in COGs
- [x] add way to consider the answers to the bot's messages. - [x] add way to consider the answers to the bot's messages.

View File

@@ -1,13 +1,16 @@
#coucou c'est fives #coucou c'est fives
# wesh wesh ici latouff # wesh wesh ici latouff
import discord # pip install pycord import discord # pip install pycord
from discord import Intents
import asyncio # pip install asyncio import asyncio # pip install asyncio
import cogs # import the cogs import cogs # import the cogs
import datetime # pip install datetime import datetime # pip install datetime
from config import debug, conn, c # import the debug function and the database connection from config import debug, conn, c # import the debug function and the database connectionimport apsw # pip install apsw. ApSW is a Python interface to SQLite 3
#add the message content intent to the bot, aka discord.Intents.default() and discord.Intents.message_content
intents = discord.Intents.default() intents = discord.Intents.default()
intents.message_content = True intents.message_content = True
intents.members = True intents.members = True
import apsw # pip install apsw. ApSW is a Python interface to SQLite 3
bot = discord.Bot(intents=intents, help_command=None) # create the bot bot = discord.Bot(intents=intents, help_command=None) # create the bot
bot.add_cog(cogs.Setup(bot)) bot.add_cog(cogs.Setup(bot))
bot.add_cog(cogs.Settings(bot)) bot.add_cog(cogs.Settings(bot))
@@ -19,32 +22,14 @@ async def on_ready():
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="your messages to answer you")) await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="your messages to answer you"))
debug("Bot is ready") debug("Bot is ready")
'''
def reset_uses_count_today():
c.execute("UPDATE data SET uses_count_today = 0")
conn.commit()
#get the current date and save it in the previous_date variable
#if the day number is different from the previous day number, reset the uses count today
def check_day():
global previous_date
if datetime.datetime.now().day != previous_date.day:
previous_date = datetime.datetime.now()
previous_date = datetime.datetime.now()
return True
else:
previous_date = datetime.datetime.now()
return False
#run check_day every 10 seconds
async def check_day_task():
while True:
check_day()
await asyncio.sleep(60)
#add a task to the bot that runs check_day every 1 minute
bot.loop.create_task(check_day_task())
'''
#run the bot #run the bot
# Replace the following with your bot's token # Replace the following with your bot's token
with open("./key.txt") as f: with open("./key.txt") as f:
key = f.read() key = f.read()
bot.run(key) bot.run(key)
#set the bot's watching status to watcing your messages to answer you
@bot.event
async def on_ready():
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name="your messages to answer you"))
debug("Bot is ready")

View File

@@ -5,6 +5,7 @@ import openai
from config import debug, c, max_uses, cp, conn, connp from config import debug, c, max_uses, cp, conn, connp
import random import random
import threading import threading
import time
class Chat (discord.Cog) : class Chat (discord.Cog) :
def __init__(self, bot: discord.Bot): def __init__(self, bot: discord.Bot):
super().__init__() super().__init__()
@@ -18,48 +19,99 @@ class Chat (discord.Cog) :
@discord.slash_command(name="say", description="Say a message") @discord.slash_command(name="say", description="Say a message")
async def say(self, ctx: discord.ApplicationContext, message: str): async def say(self, ctx: discord.ApplicationContext, message: str):
debug(f"The user {ctx.author.display_name} ran the say command command in the channel {ctx.channel} of the guild {ctx.guild}, named {ctx.guild.name}") print(f"The user {ctx.author.display_name} ran the say command command in the channel {ctx.channel} of the guild {ctx.guild}, named {ctx.guild.name}")
await ctx.respond("Message sent !", ephemeral=True) await ctx.respond("Message sent !", ephemeral=True)
await ctx.send(message) await ctx.send(message)
async def on_message_process(message, self): @discord.slash_command(name="redo", description="Redo a message")
#my code async def redo(self, ctx: discord.ApplicationContext):
#debug the thread id #first delete the last message but only if it was sent by the bot
debug(f"Thread id: {threading.get_ident()}") # get the last message
if message.author.bot: history = await ctx.channel.history(limit=2).flatten()
message_to_delete = history[0]
message_to_redo = history[1]
if message_to_delete.author.id == self.bot.user.id:
await message_to_delete.delete()
else:
await ctx.respond("The last message wasn't sent by the bot", ephemeral=True)
return return
#get the message to redo aka the last message, because the old last message has been deleted
#get the message before the last message, because the new last message is the bot thinking message, so the message before the last message is the message to redo
if message_to_redo.author.id == self.bot.user.id:
await ctx.respond("The message to redo was sent by the bot", ephemeral=True)
return
loop = asyncio.get_event_loop()
thread = threading.Thread(target=asyncio.run_coroutine_threadsafe, args=(on_message_process(message_to_redo, self), loop))
thread.start()
await ctx.respond("Message redone !", delete_after=1)
async def on_message_process(message: discord.Message, self: Chat):
#my code
#print the thread id
print(f"Thread id: {threading.get_ident()}")
print("hello")
if message.author.bot:
print("The message was sent by a bot")
return
print("The message was sent by a human")
#check if the guild is in the database #check if the guild is in the database
c.execute("SELECT * FROM data WHERE guild_id = ?", (message.guild.id,)) c.execute("SELECT * FROM data WHERE guild_id = ?", (message.guild.id,))
if c.fetchone() is None: if c.fetchone() is None:
print("The guild is not in the database")
return return
print("The guild is in the database")
#check if the bot is enabled #check if the bot is enabled
c.execute("SELECT is_active FROM data WHERE guild_id = ?", (message.guild.id,)) c.execute("SELECT is_active FROM data WHERE guild_id = ?", (message.guild.id,))
if c.fetchone()[0] == False: if c.fetchone()[0] == False:
print("The bot is disabled")
return return
print("The bot is enabled")
#check if the message has been sent in the channel set in the database #check if the message has been sent in the channel set in the database
c.execute("SELECT channel_id FROM data WHERE guild_id = ?", (message.guild.id,)) c.execute("SELECT channel_id FROM data WHERE guild_id = ?", (message.guild.id,))
#check if the message begins with --, if it does, ignore it, it's a comment
if message.content.startswith("-"):
print("The message is a comment")
return
#select channels from the premium table
try :
cp.execute("SELECT * FROM channels WHERE guild_id = ?", (message.guild.id,))
channels = cp.fetchone()[1:]
except :
channels = []
print("No premium channels")
print("here2")
try : original_message = await message.channel.fetch_message(message.reference.message_id) try : original_message = await message.channel.fetch_message(message.reference.message_id)
except : original_message = None except : original_message = None
if original_message != None and original_message.author.id != self.bot.user.id: if original_message != None and original_message.author.id != self.bot.user.id:
original_message = None original_message = None
if str(message.channel.id) != str(c.fetchone()[0]): print("The message is a reply, but the reply is not to the bot")
print("here")
try :
cp.execute("SELECT premium FROM data WHERE guild_id = ?", (message.guild.id,))
premium = cp.fetchone()[0]
except :
premium = 0
print("No premium")
if str(message.channel.id) != str(c.fetchone()[0]) :
#check if the message is a mention or if the message replies to the bot #check if the message is a mention or if the message replies to the bot
if original_message != None: if original_message != None:
debug("wrong channel, but reply") print("wrong channel, but reply")
elif message.content.find("<@"+str(self.bot.user.id)+">") != -1: elif message.content.find("<@"+str(self.bot.user.id)+">") != -1:
debug("wrong channel, but mention") print("wrong channel, but mention")
elif str(message.channel.id) in channels and premium == 1:
print("in a channel that is in the database and premium")
else : else :
debug("The message has been sent in the wrong channel") print("The message has been sent in the wrong channel")
return return
#check if the bot hasn't been used more than 5000 times in the last 24 hours (uses_count_today) #check if the bot hasn't been used more than 5000 times in the last 24 hours (uses_count_today)
c.execute("SELECT uses_count_today FROM data WHERE guild_id = ?", (message.guild.id,)) c.execute("SELECT uses_count_today FROM data WHERE guild_id = ?", (message.guild.id,))
uses = c.fetchone()[0] uses = c.fetchone()[0]
try: try:
cp.execute("SELECT premium FROM data WHERE guild_id = ?", (message.guild.id,)) cp.execute("SELECT premium FROM data WHERE guild_id = ?", (message.guild.id,))
premium = cp.fetchone()[0] premium = cp.fetchone()[0]
except: premium = 0 except: premium = 0
print("here1")
if uses >= 500 and premium == 0: if uses >= 500 and premium == 0:
debug(f"The bot has been used more than {max_uses} times in the last 24 hours in this guild. Please try again in 24h.") print(f"The bot has been used more than {max_uses} times in the last 24 hours in this guild. Please try again in 24h.")
await message.channel.send("The bot has been used more than 500 times in the last 24 hours in this guild. Please try again in 24h.") await message.channel.send("The bot has been used more than 500 times in the last 24 hours in this guild. Please try again in 24h.")
return return
#add 1 to the uses_count_today #add 1 to the uses_count_today
@@ -86,11 +138,6 @@ async def on_message_process(message, self):
#get the channel id from the database #get the channel id from the database
c.execute("SELECT channel_id FROM data WHERE guild_id = ?", (message.guild.id,)) c.execute("SELECT channel_id FROM data WHERE guild_id = ?", (message.guild.id,))
for msg in messages: for msg in messages:
if msg.author.bot:
prompt += f"Botator: {msg.content}\n"
else:
#replace the mentions of each user with their name
#first get all the mentions in the message
mentions = re.findall(r"<@!?\d+>", msg.content) mentions = re.findall(r"<@!?\d+>", msg.content)
#then replace each mention with the name of the user #then replace each mention with the name of the user
for mention in mentions: for mention in mentions:
@@ -100,7 +147,10 @@ async def on_message_process(message, self):
user = await self.bot.fetch_user(id) user = await self.bot.fetch_user(id)
#replace the mention with the name #replace the mention with the name
msg.content = msg.content.replace(mention, msg.guild.get_member(user.id).display_name + f"<@{id}>") msg.content = msg.content.replace(mention, msg.guild.get_member(user.id).display_name + f"<@{id}>")
prompt += f"{msg.author.display_name}: {msg.content}\n" #get the gmt time the message was sent
gmt_time = message.created_at.strftime("%Y-%m-%d %H:%M:%S")
print(f"{gmt_time}")
prompt += f"{msg.author.display_name} ({gmt_time} GMT-0): {msg.content}\n"
#get the prompt_prefix from the database #get the prompt_prefix from the database
#check if the bot is in pretend mode #check if the bot is in pretend mode
c.execute("SELECT pretend_enabled FROM data WHERE guild_id = ?", (message.guild.id,)) c.execute("SELECT pretend_enabled FROM data WHERE guild_id = ?", (message.guild.id,))
@@ -145,8 +195,8 @@ async def on_message_process(message, self):
prompt += "System: Fives3dprint detected. Botator will be very nice and cute with fives3dprint.\n" prompt += "System: Fives3dprint detected. Botator will be very nice and cute with fives3dprint.\n"
prompt += "Botator:" prompt += "Botator:"
prompt = prompt + f"\n" prompt = prompt + f"\n"
debug("Sending request to the api") print("Sending request to the api")
#debug(prompt) #print(prompt)
openai.api_key = api_key openai.api_key = api_key
response = openai.Completion.create( response = openai.Completion.create(
engine="text-davinci-003", engine="text-davinci-003",
@@ -164,11 +214,11 @@ async def on_message_process(message, self):
#if tts is enabled, send the message with tts enabled #if tts is enabled, send the message with tts enabled
if tts == 1: if tts == 1:
await message.channel.send(response["choices"][0]["text"], tts=True) await message.channel.send(response["choices"][0]["text"], tts=True)
debug("The response has been sent with tts enabled") print("The response has been sent with tts enabled")
#if tts is disabled, send the message with tts disabled #if tts is disabled, send the message with tts disabled
else: else:
await message.channel.send(response["choices"][0]["text"]) await message.channel.send(response["choices"][0]["text"])
debug("The response has been sent with tts disabled") print("The response has been sent with tts disabled")
else: else:
await message.channel.send("The AI is not sure what to say (the response was empty)") await message.channel.send("The AI is not sure what to say (the response was empty)")
debug("The response was empty") print("The response was empty")

View File

@@ -17,6 +17,7 @@ class Help (discord.Cog) :
embed.add_field(name="/advanced_help", value="Get help about the advanced settings", inline=False) embed.add_field(name="/advanced_help", value="Get help about the advanced settings", inline=False)
embed.add_field(name="/enable_tts", value="Enable the Text To Speech", inline=False) embed.add_field(name="/enable_tts", value="Enable the Text To Speech", inline=False)
embed.add_field(name="/disable_tts", value="Disable the Text To Speech", inline=False) embed.add_field(name="/disable_tts", value="Disable the Text To Speech", inline=False)
embed.add_field(name="/add|remove_channel", value="Add or remove a channel to the list of channels where the bot will answer. Only available on premium guilds", inline=False)
embed.add_field(name="/delete", value="Delete all your data from our server", inline=False) embed.add_field(name="/delete", value="Delete all your data from our server", inline=False)
embed.add_field(name="/cancel", value="Cancel the last message sent by the bot", inline=False) embed.add_field(name="/cancel", value="Cancel the last message sent by the bot", inline=False)
embed.add_field(name="/default", value="Set the advanced settings to their default values", inline=False) embed.add_field(name="/default", value="Set the advanced settings to their default values", inline=False)

View File

@@ -152,7 +152,7 @@ class Settings (discord.Cog) :
conn.commit() conn.commit()
await ctx.respond("Pretend mode enabled", ephemeral=True) await ctx.respond("Pretend mode enabled", ephemeral=True)
#change the bots name on the server wit ctx.guild.me.edit(nick=pretend_to_be) #change the bots name on the server wit ctx.guild.me.edit(nick=pretend_to_be)
ctx.guild.me.edit(nick=pretend_to_be) await ctx.guild.me.edit(nick=pretend_to_be)
c.execute("UPDATE data SET pretend_to_be = ? WHERE guild_id = ?", (pretend_to_be, ctx.guild.id)) c.execute("UPDATE data SET pretend_to_be = ? WHERE guild_id = ?", (pretend_to_be, ctx.guild.id))
conn.commit() conn.commit()
await ctx.guild.me.edit(nick=pretend_to_be) await ctx.guild.me.edit(nick=pretend_to_be)

View File

@@ -1,5 +1,5 @@
import discord import discord
from config import debug, conn, c from config import debug, conn, c, connp, cp
class Setup (discord.Cog) : class Setup (discord.Cog) :
def __init__(self, bot: discord.Bot): def __init__(self, bot: discord.Bot):
@@ -78,3 +78,92 @@ class Setup (discord.Cog) :
c.execute("UPDATE data SET is_active = ? WHERE guild_id = ?", (False, ctx.guild.id)) c.execute("UPDATE data SET is_active = ? WHERE guild_id = ?", (False, ctx.guild.id))
conn.commit() conn.commit()
await ctx.respond("Disabled", ephemeral=True) await ctx.respond("Disabled", ephemeral=True)
#create a command calles "add channel" that can only be used in premium servers
@discord.slash_command(name="add_channel", description="Add a channel to the list of channels. Premium only.")
@discord.option(name="channel", description="The channel to add", type=discord.TextChannel, required=False)
async def add_channel(self, ctx: discord.ApplicationContext, channel: discord.TextChannel = None):
debug(f"The user {ctx.author} ran the add_channel command in the channel {ctx.channel} of the guild {ctx.guild}, named {ctx.guild.name}")
#check if the guild is in the database
c.execute("SELECT * FROM data WHERE guild_id = ?", (ctx.guild.id,))
if c.fetchone() is None:
await ctx.respond("This server is not setup", ephemeral=True)
return
#check if the guild is premium
try :
cp.execute("SELECT premium FROM data WHERE guild_id = ?", (ctx.guild.id,))
premium = cp.fetchone()[0]
except :
premium = 0
if not premium:
await ctx.respond("This server is not premium", ephemeral=True)
return
if channel is None:
channel = ctx.channel
#check if the channel is already in the list
c.execute("SELECT channel_id FROM data WHERE guild_id = ?", (ctx.guild.id,))
if str(channel.id) == c.fetchone()[0]:
await ctx.respond("This channel is already set as the main channel", ephemeral=True)
return
cp.execute("SELECT * FROM channels WHERE guild_id = ?", (ctx.guild.id,))
guild_channels = cp.fetchone()
if guild_channels is None:
# if the channel is not in the list, add it
cp.execute("INSERT INTO channels VALUES (?, ?, ?, ?, ?, ?)", (ctx.guild.id, channel.id, None, None, None, None))
connp.commit()
await ctx.respond(f"Added channel **{channel.name}**", ephemeral=True)
return
channels = guild_channels[1:]
if str(channel.id) in channels:
await ctx.respond("This channel is already added", ephemeral=True)
return
for i in range(5):
if channels[i] == None:
cp.execute(f"UPDATE channels SET channel{i} = ? WHERE guild_id = ?", (channel.id, ctx.guild.id))
connp.commit()
await ctx.respond(f"Added channel **{channel.name}**", ephemeral=True)
return
await ctx.respond("You can only add 5 channels", ephemeral=True)
#create a command called "remove channel" that can only be used in premium servers
@discord.slash_command(name="remove_channel", description="Remove a channel from the list of channels. Premium only.")
@discord.option(name="channel", description="The channel to remove", type=discord.TextChannel, required=False)
async def remove_channel(self, ctx: discord.ApplicationContext, channel: discord.TextChannel = None):
debug(f"The user {ctx.author} ran the remove_channel command in the channel {ctx.channel} of the guild {ctx.guild}, named {ctx.guild.name}")
#check if the guild is in the database
c.execute("SELECT * FROM data WHERE guild_id = ?", (ctx.guild.id,))
if c.fetchone() is None:
await ctx.respond("This server is not setup", ephemeral=True)
return
#check if the guild is premium
try :
cp.execute("SELECT premium FROM data WHERE guild_id = ?", (ctx.guild.id,))
premium = cp.fetchone()[0]
except :
premium = 0
if not premium:
await ctx.respond("This server is not premium", ephemeral=True)
return
if channel is None:
channel = ctx.channel
#check if the channel is in the list
cp.execute("SELECT * FROM channels WHERE guild_id = ?", (ctx.guild.id,))
guild_channels = cp.fetchone()
c.execute("SELECT channel_id FROM data WHERE guild_id = ?", (ctx.guild.id,))
if str(channel.id) == c.fetchone()[0]:
await ctx.respond("This channel is set as the main channel and therefore cannot be removed. Type /setup to change the main channel.", ephemeral=True)
return
if guild_channels is None:
await ctx.respond("This channel was not added. Nothing changed", ephemeral=True)
return
channels = guild_channels[1:]
if str(channel.id) not in channels:
await ctx.respond("This channel was not added. Nothing changed", ephemeral=True)
return
#remove the channel from the list
for i in range(5):
if channels[i] == str(channel.id):
cp.execute(f"UPDATE channels SET channel{i} = ? WHERE guild_id = ?", (None, ctx.guild.id))
connp.commit()
await ctx.respond(f"Removed channel **{channel.name}**", ephemeral=True)
return

View File

@@ -15,3 +15,5 @@ cp = connp.cursor()
# Create table called "data" if it does not exist with the following columns: guild_id, channel_id, api_key, is_active, max_tokens, temperature, frequency_penalty, presence_penalty, uses_count_today, prompt_size # Create table called "data" if it does not exist with the following columns: guild_id, channel_id, api_key, is_active, max_tokens, temperature, frequency_penalty, presence_penalty, uses_count_today, prompt_size
c.execute('''CREATE TABLE IF NOT EXISTS data (guild_id text, channel_id text, api_key text, is_active boolean, max_tokens integer, temperature real, frequency_penalty real, presence_penalty real, uses_count_today integer, prompt_size integer, prompt_prefix text, tts boolean, pretend_to_be text, pretend_enabled boolean)''') c.execute('''CREATE TABLE IF NOT EXISTS data (guild_id text, channel_id text, api_key text, is_active boolean, max_tokens integer, temperature real, frequency_penalty real, presence_penalty real, uses_count_today integer, prompt_size integer, prompt_prefix text, tts boolean, pretend_to_be text, pretend_enabled boolean)''')
cp.execute('''CREATE TABLE IF NOT EXISTS data (user_id text, guild_id text, premium boolean)''') cp.execute('''CREATE TABLE IF NOT EXISTS data (user_id text, guild_id text, premium boolean)''')
# create table called "channels" if it does not exist with the following columns: guild_id, channel1, channel2, channel3, channel4, channel5
cp.execute('''CREATE TABLE IF NOT EXISTS channels (guild_id text, channel0 text, channel1 text, channel2 text, channel3 text, channel4 text)''')