Compare commits

..

No commits in common. "a898d0d9b8b4f9715af7d5fc79d6e199c330249f" and "c2df6f91926097c03088b5b8fd7ae6da8e83ff13" have entirely different histories.

10 changed files with 382 additions and 549 deletions

View File

@ -8,12 +8,9 @@ This is a Discord Bot that Uses OpenAI's new Chat API-Endpoint to generate text
This Bot uses the PyCord Library ([PyCord](https://pycord.dev/)) and the OpenAI Python Library ([OpenAI](https://platform.openai.com/docs/libraries)) This Bot uses the PyCord Library ([PyCord](https://pycord.dev/)) and the OpenAI Python Library ([OpenAI](https://platform.openai.com/docs/libraries))
There are three ways to use this bot: There are two ways to use this bot:
1. By just inviting [this Bot](https://discord.com/api/oauth2/authorize?client_id=1083786070786850959&permissions=2147486720&scope=bot) to your Server Using Docker or without Docker.
2. Using Docker
3. Without using Docker
### The No Docker Way ### The No Docker Way

View File

@ -1,16 +1,22 @@
import asyncio
import discord import discord
from discord.ext import commands from discord.ext import commands
from dotenv import load_dotenv from dotenv import load_dotenv
import os import os
import modules.gpt as gpt import modules.gpt as gpt
import modules.dbmanagement as dbm import modules.tts as tts
import modules.summarize as summarize import modules.summarize as summarize
import modules.channelconfig as config
description = "ChatGPT Bot for Discord" description = "ChatGPT Bot for Discord"
configfolder = "config" configfolder = "configs"
audiofolder = "audio"
load_dotenv(dotenv_path=os.path.join(configfolder, ".env")) load_dotenv(dotenv_path=os.path.join(configfolder, ".env"))
text_channels, prefix_channels = config.load_config()
tts_language = "de-DE"
intents = discord.Intents.default() intents = discord.Intents.default()
intents.message_content = True intents.message_content = True
intents.members = True intents.members = True
@ -21,234 +27,131 @@ bot = discord.Bot(
intents=intents, intents=intents,
) )
### \/ Events Area \/ ###
@bot.event @bot.event
async def on_ready(): async def on_ready():
print(f"We have logged in as {bot.user}") print(f"We have logged in as {bot.user}")
await dbm.init_db()
### Message Listener
@bot.event @bot.event
async def on_message(message): async def on_message(message):
if message.author == bot.user: if message.author == bot.user:
return return
### Check if Channel is Configured if str(message.channel.id) in text_channels and not message.content.startswith("$"):
if await dbm.get_channel_by_id(message.guild.id, message.channel.id) is not None: await message.channel.trigger_typing()
config = await dbm.get_config_by_id(message.guild.id, message.channel.id) print(f'{message.author} asked: {message.content}')
if message.content.startswith(config[2]): answer = await gpt.get_answer(message.channel.id, message.author, message.content)
### Count Messages for Summary print(f'Answer: {answer}')
counter = 0 await message.channel.send(answer)
if await dbm.get_last_chat(message.guild.id, message.channel.id) is not None:
counter = await dbm.get_last_chat(message.guild.id, message.channel.id)
counter = counter[8]
counter = counter + 1
else:
await dbm.add_summary_zero(message.guild.id, message.channel.id)
### Read and Send Message/Answer if str(message.channel.id) in prefix_channels:
if message.content.startswith("!"):
msg_split = message.content.split("!")[1]
await message.channel.trigger_typing() await message.channel.trigger_typing()
msg = message.content.replace(config[2], "", 1) print(f'{message.author} asked: {message.content}')
await dbm.add_chat(message.guild.id, message.channel.id, message.author.id, message.author.name, "user", message.id, f'{message.author}: {msg}', counter) answer = await gpt.get_answer(message.channel.id, message.author, msg_split)
answer = await gpt.get_answer(message.guild.id, message.channel.id) print(f'Answer: {answer}')
sendmsg = await message.channel.send(answer) await message.channel.send(answer)
await dbm.add_chat(message.guild.id, message.channel.id, bot.user.id, bot.user.name, "assistant", sendmsg.id, answer, counter+1)
### Check if Summary is needed
last_summary = await dbm.get_latest_summary(message.guild.id, message.channel.id)
last_summary = last_summary[4]
last_message = await dbm.get_last_chat(message.guild.id, message.channel.id)
last_message = last_message[8]
### Check if Last Summary is older than 20 Messages
if last_message - last_summary >= 30:
await summarize.new_summarize(message.guild.id, message.channel.id)
### /\ End Events Area /\ ###
### \/ Modal Area \/ ###
### Modal Class for Setup
class SetupModal(discord.ui.Modal):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.add_item(discord.ui.InputText(label="Channel-ID", placeholder="Channel-ID", required=True))
self.add_item(discord.ui.InputText(label="Prefix", placeholder="!", required=False))
self.add_item(discord.ui.InputText(label="GPT", placeholder="3", required=True))
self.add_item(discord.ui.InputText(label="System Message", placeholder="System Message", required=False, style=discord.InputTextStyle.long))
async def callback(self, interaction: discord.Interaction):
embed = discord.Embed(title="Setup Vals")
embed.add_field(name="Channel-ID", value=self.children[0].value)
embed.add_field(name="Prefix", value=self.children[1].value)
embed.add_field(name="GPT", value=self.children[2].value)
embed.add_field(name="System Message", value=self.children[3].value)
await interaction.response.send_message(embeds=[embed], ephemeral=True)
if await dbm.get_server_by_id(interaction.guild.id) is None:
print("Server not in DB")
await dbm.add_server(interaction.guild.id)
await dbm.add_channel(interaction.guild.id, self.children[0].value)
if dbm.is_premium(interaction.guild.id):
await dbm.add_config(interaction.guild.id, self.children[0].value, self.children[1].value, self.children[2].value, self.children[3].value)
else:
await dbm.add_config(interaction.guild.id, self.children[0].value, 3, self.children[2].value, self.children[3].value)
await dbm.add_summary_zero(interaction.guild.id, self.children[0].value)
await dbm.default_premium(interaction.guild.id)
print("Setup: Server")
elif await dbm.get_server_by_id(interaction.guild.id) is not None and await dbm.get_channel_by_id(interaction.guild.id, self.children[0].value) is None:
print("Server in DB, but Channel not")
await dbm.add_channel(interaction.guild.id, self.children[0].value)
if dbm.is_premium(interaction.guild.id):
await dbm.add_config(interaction.guild.id, self.children[0].value, self.children[1].value, self.children[2].value, self.children[3].value)
else:
await dbm.add_config(interaction.guild.id, self.children[0].value, 3, self.children[2].value, self.children[3].value)
await dbm.add_summary_zero(interaction.guild.id, self.children[0].value)
print("Setup: Channel, Config")
elif await dbm.get_server_by_id(interaction.guild.id) is not None and await dbm.get_channel_by_id(interaction.guild.id, self.children[0].value) is not None:
print("Server and Channel in DB, rerun Setup")
await dbm.remove_channel(interaction.guild.id, self.children[0].value)
await dbm.remove_config(interaction.guild.id, self.children[0].value)
await dbm.add_channel(interaction.guild.id, self.children[0].value)
if dbm.is_premium(interaction.guild.id):
await dbm.add_config(interaction.guild.id, self.children[0].value, self.children[1].value, self.children[2].value, self.children[3].value)
else:
await dbm.add_config(interaction.guild.id, self.children[0].value, 3, self.children[2].value, self.children[3].value)
await dbm.add_summary_zero(interaction.guild.id, self.children[0].value)
print("Setup: Channel, Config")
### Add Modal
class AddModal(discord.ui.Modal):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.add_item(discord.ui.InputText(label="Prefix (Leave empty for no Prefix)", placeholder="!", required=False))
self.add_item(discord.ui.InputText(label="GPT (3 - GPT-3.5-Turbo; 4- GPT-4)", placeholder="3", required=True))
self.add_item(discord.ui.InputText(label="System Message", placeholder="System Message", required=False, style=discord.InputTextStyle.long))
async def callback(self, interaction: discord.Interaction):
if await dbm.get_server_by_id(interaction.guild.id) is None:
print("Server not in DB")
await dbm.add_server(interaction.guild.id)
await dbm.add_channel(interaction.guild.id, interaction.channel.id)
if dbm.is_premium(interaction.guild.id):
await dbm.add_config(interaction.guild.id, interaction.channel.id, self.children[0].value, self.children[1].value, self.children[2].value)
else:
await dbm.add_config(interaction.guild.id, interaction.channel.id, self.children[0].value, 3, self.children[2].value)
await dbm.add_summary_zero(interaction.guild.id, interaction.channel.id)
print("Setup: Channel, Server, Config")
elif await dbm.get_server_by_id(interaction.guild.id) is not None and await dbm.get_channel_by_id(interaction.guild.id, interaction.channel.id) is None:
await dbm.add_channel(interaction.guild.id, interaction.channel.id)
if dbm.is_premium(interaction.guild.id):
await dbm.add_config(interaction.guild.id, interaction.channel.id, self.children[0].value,
self.children[1].value, self.children[2].value)
else:
await dbm.add_config(interaction.guild.id, interaction.channel.id, self.children[0].value, 3,
self.children[2].value)
await dbm.add_summary_zero(interaction.guild.id, interaction.channel.id)
print("Setup: Channel, Config")
elif await dbm.get_server_by_id(interaction.guild.id) is not None and await dbm.get_channel_by_id(interaction.guild.id, interaction.channel.id) is not None:
await dbm.remove_channel(interaction.guild.id, interaction.channel.id)
await dbm.remove_config(interaction.guild.id, interaction.channel.id)
if dbm.is_premium(interaction.guild.id):
await dbm.add_config(interaction.guild.id, interaction.channel.id, self.children[0].value,
self.children[1].value, self.children[2].value)
else:
await dbm.add_config(interaction.guild.id, interaction.channel.id, self.children[0].value, 3,
self.children[2].value)
await dbm.add_config(interaction.guild.id, interaction.channel.id, self.children[0].value, self.children[1].value, self.children[2].value)
await dbm.add_summary_zero(interaction.guild.id, interaction.channel.id)
print("Setup: Channel, Config")
if dbm.is_premium(interaction.guild.id):
await interaction.response.send_message('Setup Channel', ephemeral=True)
else:
await interaction.response.send_message('Setup Channel (Using GPT-3.5)', ephemeral=True)
### Edit Modal
class EditSystemModal(discord.ui.Modal):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.add_item(discord.ui.InputText(label="System Message", placeholder="System Message", required=False, style=discord.InputTextStyle.long))
async def callback(self, interaction: discord.Interaction):
server, channel, prefix, gptver, systemmsg = await dbm.get_config_by_id(interaction.guild.id, interaction.channel.id)
await dbm.remove_config(interaction.guild.id, interaction.channel.id)
await dbm.add_config(interaction.guild.id, interaction.channel.id, prefix, gptver, self.children[0].value)
await interaction.response.send_message("System Message changed", ephemeral=True)
### /\ End Modal Area /\ ###
### \/ Commands Area \/ ###
### Setup Command
@bot.command(name="setup", description="Used to setup the Bot")
@commands.has_permissions(administrator=True)
async def setup(ctx: discord.ApplicationContext):
modal = SetupModal(title="Setup ChatGPT")
await ctx.send_modal(modal)
@bot.command(name="add", description="Used to add Bot answering to specific Channels") @bot.command(name="add", description="Used to add Bot answering to specific Channels")
@commands.has_permissions(administrator=True) async def add(
async def add(ctx: discord.ApplicationContext): ctx: discord.ApplicationContext,
if await dbm.get_channel_by_id(ctx.guild.id, ctx.channel.id) is None: option: discord.Option(str, choices=["text","prefix"], description="Type of Channel to Add"),
modal = AddModal(title="Add Channel") id: discord.Option(str, description="Channel-ID -> Activate Developer-Options to Copy")):
await ctx.send_modal(modal)
else:
await ctx.respond("Channel has already been added. Use /setup", ephemeral=True)
if ctx.author.guild_permissions.administrator:
try:
config.add_channel(option, id)
if option == "text":
text_channels.append(id)
elif option == "prefix":
prefix_channels.append(id)
await ctx.respond(f'{option} channel {id} added', ephemeral=True)
except ValueError as e:
await ctx.respond(f'Error: {e}', ephemeral=True)
else:
await ctx.respond(f'Error: You need to be an Administrator to use this command', ephemeral=True)
@bot.command(name="remove", description="Used to remove Bot answering to specific Channels") @bot.command(name="remove", description="Used to remove Bot answering to specific Channels")
@commands.has_permissions(administrator=True) async def remove(
async def remove(ctx: discord.ApplicationContext): ctx: discord.ApplicationContext,
if await dbm.get_channel_by_id(ctx.guild.id, ctx.channel.id) is not None: option: discord.Option(str, choices=["text", "prefix"], description="Type of Channel to Add"),
await dbm.remove_channel(ctx.guild.id, ctx.channel.id) id: discord.Option(str, description="Channel-ID -> Activate Developer-Options to Copy")):
await ctx.respond("Channel removed", ephemeral=True) if ctx.author.guild_permissions.administrator:
try:
config.remove_channel(option, id)
if option == "text":
text_channels.remove(id)
elif option == "prefix":
prefix_channels.remove(id)
await ctx.respond(f'{option} channel {id} removed', ephemeral=True)
except ValueError as e:
await ctx.respond(f'Error: {e}', ephemeral=True)
else: else:
await ctx.respond("Channel not active. Nothing Done", ephemeral=True) await ctx.respond(f'Error: You need to be an Administrator to use this command', ephemeral=True)
@bot.command(name="list", description="Used to list all Channels the Bot is answering to")
async def list(
ctx: discord.ApplicationContext,
option: discord.Option(str, choices=["text", "prefix"], description="Type of Channels to List")):
@bot.command(name="list", description="Used to list all Channels in the Server") if ctx.author.guild_permissions.administrator:
@commands.has_permissions(administrator=True) if option == "text":
async def list(ctx: discord.ApplicationContext): await ctx.respond(f'{option} channels: {str(text_channels)}', ephemeral=True)
elif option == "prefix":
await ctx.respond(f'{option} channels: {str(prefix_channels)}', ephemeral=True)
else:
await ctx.respond(f'Error: You need to be an Administrator to use this command', ephemeral=True)
await ctx.respond("This command is WIP") @bot.command(name="delete", description="Used to delete chat history of specific Channels/Users")
async def delete(
ctx: discord.ApplicationContext,
option: discord.Option(str, choices=["text", "prefix"], description="Type of Channel to Delete"),
id: discord.Option(str, description="Channel-ID -> Activate Developer-Options to Copy")):
if ctx.author.guild_permissions.administrator:
try:
gpt.delete_history(id)
await ctx.respond(f'{option} channel {id} history deleted', ephemeral=True)
except Exception as e:
await ctx.respond(f'Error: {e}', ephemeral=True)
else:
await ctx.respond(f'Error: You need to be an Administrator to use this command', ephemeral=True)
@bot.command(name="clear", description="Used to clear chat history of specific Channels/Users")
@commands.has_permissions(administrator=True)
async def clear(ctx: discord.ApplicationContext):
await dbm.add_summary_zero(ctx.guild.id, ctx.channel.id)
await ctx.respond("Bot got Amnesia", ephemeral=True)
# Old System, Rewrite needed
@bot.command(name="help", description="Used to get help") @bot.command(name="help", description="Used to get help")
async def help(ctx: discord.ApplicationContext): async def help(ctx: discord.ApplicationContext):
await ctx.respond(f'Here is a list of all commands:\n' await ctx.respond(f'Here is a list of all commands:\n'
'Needs Rewrite\n', ephemeral=True) f'/ping\n'
f'/setup <channel-id> <system-message>\n'
f'/add <text/prefix> <channel-id>\n'
f'/remove <text/prefix> <channel-id>\n'
f'/list <text/prefix>\n'
f'/delete <text/prefix> <channel-id>\n'
f'/help', ephemeral=True)
@bot.command(name="ping", description="Used to check if the bot is alive") @bot.command(name="ping", description="Used to check if the bot is alive")
async def ping(ctx: discord.ApplicationContext): async def ping(ctx: discord.ApplicationContext):
await ctx.respond(f'pong', ephemeral=True) await ctx.respond(f'pong', ephemeral=True)
# Old System, Rewrite needed @bot.command(name="setup", description="Used to setup the bot with a custom system message")
@bot.command(name="system", description="Used to setup the bot with a custom system message") async def setup(ctx: discord.ApplicationContext,
@commands.has_permissions(administrator=True) id: discord.Option(str, description="Channel-ID -> Activate Developer-Options to Copy"),
async def system(ctx: discord.ApplicationContext): message: discord.Option(str, description="System Message")):
try: if ctx.author.guild_permissions.administrator:
modal = EditSystemModal(title="Change System Message") try:
await ctx.send_modal(modal) gpt.setup_history(id, message)
except: await ctx.respond(f'Setup successful', ephemeral=True)
await ctx.respond("No Config found for this Channel", ephemeral=True) except Exception as e:
await ctx.respond(f'Error: {e}', ephemeral=True)
### /\ End Commands Area /\ ### else:
await ctx.respond(f'Error: You need to be an Administrator to use this command', ephemeral=True)
bot.run(str(os.environ.get('DISCORD_TOKEN'))) bot.run(str(os.environ.get('DISCORD_TOKEN')))

51
bot/featuretest.py Normal file
View File

@ -0,0 +1,51 @@
import modules.channelconfig as config
import modules.gpt as gpt
import os
text_channels = config.load_config()
def listen_input(username, channel):
message = input(f'{username} {channel}: ')
if message.startswith("/"):
print(slash_command(username, channel, message))
elif message.startswith("$") and channel in text_channels:
ask_gpt(username, channel, message)
else:
print(log_message(username, channel, message))
def log_message(user, channel, message):
return f'User {user} sent "{message}" in {channel}'
# Slash Command Wrapper
def slash_command(user, channel, message):
message = message.split("/")[1].split(" ")
# Add Channels to Config
if message[0] == "add":
pass
if message[1] == "text":
config.add_channel("text", message[2])
print("Added Channel to Config")
# Remove Channels from Config
elif message[0] == "remove":
if message[1] == "text":
return config.remove_channel("text", message[2])
# Reload Config
elif message[0] == "reload":
text_channels = config.load_config()
return text_channels
else:
return "Invalid Command"
def ask_gpt(user, id, message):
message = message.split('$')[1]
answer = gpt.get_answer(id, user, message)
print(answer)
username = "XYZ"
channel = "112233445566"
while True:
text_channels = config.load_config()
listen_input(username, channel)

View File

@ -0,0 +1,88 @@
# Rewrite of Channelmgmt
from os import path
folder = "configs"
text_channel_file = "text_channels.txt"
prefix_channel_file = "prefix_channels.txt"
def load_config():
# Load Text-Channel Config
try:
with open(path.join(folder,text_channel_file), "r") as f:
text_channels = f.read().split("\n")
except Exception as error:
print(f'File not Fount, creating new. {error}')
with open(path.join(folder,text_channel_file), "w") as f:
f.write('')
text_channels = []
# Load Prefix-Channel Config
try:
with open(path.join(folder, prefix_channel_file), "r") as f:
prefix_channels = f.read().split("\n")
except Exception as error:
print(f'File not Fount, creating new. {error}')
with open(path.join(folder, prefix_channel_file), "w") as f:
f.write('')
prefix_channels = []
return text_channels, prefix_channels
# Add Channel to Config
def add_channel(type, id):
try:
if type == "text":
text_channels = load_config()
if id in text_channels:
# Throw Error if already in List
raise ValueError("Channel already in List")
else:
with open(path.join(folder, text_channel_file), 'a') as f:
f.write(f'{id}\n')
return True
elif type == "prefix":
prefix_channels = load_config()
if id in prefix_channels:
# Throw Error if already in List
raise ValueError("Channel already in List")
else:
with open(path.join(folder, prefix_channel_file), 'a') as f:
f.write(f'{id}\n')
return True
except FileNotFoundError as error:
load_config()
add_channel(type, id)
def remove_channel(type, id):
try:
if type == "text":
text_channels = load_config()
if id in text_channels:
text_channels.remove(id)
new_conf = ""
for x in text_channels:
new_conf += f'{x}\n'
with open(path.join(folder, text_channel_file), 'w') as f:
f.write(new_conf)
return True
else:
raise ValueError("Channel not in List")
elif type == "prefix":
prefix_channels = load_config()
if id in prefix_channels:
prefix_channels.remove(id)
new_conf = ""
for x in prefix_channels:
new_conf += f'{x}\n'
with open(path.join(folder, prefix_channel_file), 'w') as f:
f.write(new_conf)
return True
else:
raise ValueError("Channel not in List")
except Exception as error:
print(error)
return False

View File

@ -1,259 +0,0 @@
import os
import aiosqlite
DB_FILE = os.path.join("config", "database.db")
async def init_db():
async with aiosqlite.connect(DB_FILE) as db:
await db.execute(
'''CREATE TABLE IF NOT EXISTS servers
(id INTEGER PRIMARY KEY AUTOINCREMENT, server_id TEXT UNIQUE, is_premium INTEGER)'''
)
await db.execute(
'''CREATE TABLE IF NOT EXISTS channels
(id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id TEXT,
channel_id TEXT UNIQUE,
FOREIGN KEY(server_id) REFERENCES servers(id))'''
)
await db.execute(
'''CREATE TABLE IF NOT EXISTS config
(server_id TEXT,
channel_id TEXT,
prefix TEXT,
gpt INTEGER,
systemmsg TEXT,
FOREIGN KEY(server_id) REFERENCES servers(id),
FOREIGN KEY(channel_id) REFERENCES channels(id))'''
)
await db.execute(
'''CREATE TABLE IF NOT EXISTS chats
(id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id TEXT,
channel_id TEXT,
user_id TEXT,
username TEXT,
msgrole TEXT,
message_id TEXT UNIQUE,
message TEXT,
messagecount INTEGER,
FOREIGN KEY(server_id) REFERENCES servers(id),
FOREIGN KEY(channel_id) REFERENCES channels(id))'''
)
await db.execute(
'''CREATE TABLE IF NOT EXISTS summaries
(id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id TEXT,
channel_id TEXT,
summary TEXT,
summarycount INTEGER,
FOREIGN KEY(server_id) REFERENCES servers(id),
FOREIGN KEY(channel_id) REFERENCES channels(id))'''
)
await db.commit()
async def add_server(server_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('INSERT OR IGNORE INTO servers (server_id) VALUES (?)', (server_id,))
await db.commit()
async def remove_server(server_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('DELETE FROM servers WHERE server_id = ?', (server_id,))
await db.commit()
async def list_servers():
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM servers')
servers = await cursor.fetchall()
return servers
async def is_premium(server_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM servers WHERE server_id = ?', (server_id,))
server = await cursor.fetchone()
if server[2] == 1:
return True
else:
return False
async def default_premium(server_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('UPDATE servers SET is_premium = 0 WHERE server_id = ?', (server_id,))
await db.commit()
async def set_premium(server_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('UPDATE servers SET is_premium = 1 WHERE server_id = ?', (server_id,))
await db.commit()
async def unset_premium(server_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('UPDATE servers SET is_premium = 0 WHERE server_id = ?', (server_id,))
await db.commit()
async def get_server_by_id(server_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM servers WHERE server_id = ?', (server_id,))
server = await cursor.fetchone()
return server
async def add_channel(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('INSERT OR IGNORE INTO channels (server_id, channel_id) VALUES (?, ?)', (server_id, channel_id))
await db.commit()
async def remove_channel(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('DELETE FROM channels WHERE server_id = ? AND channel_id = ?', (server_id, channel_id))
await db.commit()
async def list_channels(server_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM channels WHERE server_id = ?', (server_id,))
channels = await cursor.fetchall()
return channels
async def get_channel_by_id(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM channels WHERE server_id = ? AND channel_id = ?', (server_id, channel_id))
channel = await cursor.fetchone()
return channel
async def add_config(server_id, channel_id, prefix, gpt, systemmsg):
msg = f'Users are named like this: Username#1234 the #1234 is an identifier and can be ignored. {systemmsg}'
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('INSERT OR IGNORE INTO config (server_id, channel_id, prefix, gpt, systemmsg) VALUES (?, ?, ?, ?, ?)', (server_id, channel_id, prefix, gpt, msg))
await db.commit()
async def remove_config(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('DELETE FROM config WHERE server_id = ? AND channel_id = ?', (server_id, channel_id))
await db.commit()
async def list_configs(server_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM config WHERE server_id = ?', (server_id,))
configs = await cursor.fetchall()
return configs
async def get_config_by_id(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM config WHERE server_id = ? AND channel_id = ?', (server_id, channel_id))
config = await cursor.fetchone()
return config
async def get_channels_by_server(server_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM channels WHERE server_id = ?', (server_id,))
channels = await cursor.fetchall()
return channels
async def get_configs_by_server(server_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM config WHERE server_id = ?', (server_id,))
configs = await cursor.fetchall()
return configs
async def add_chat(server_id, channel_id, user_id, username, msgrole, message_id, message, messagecount):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('INSERT OR IGNORE INTO chats (server_id, channel_id, user_id, username, msgrole, message_id, message, messagecount) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', (server_id, channel_id, user_id, username, msgrole, message_id, message, messagecount))
await db.commit()
async def remove_chat(server_id, channel_id, message_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('DELETE FROM chats WHERE server_id = ? AND channel_id = ? AND message_id = ?', (server_id, channel_id, message_id))
await db.commit()
async def remove_all_chats(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('DELETE FROM chats WHERE server_id = ? AND channel_id = ?', (server_id, channel_id))
await db.commit()
async def list_chats(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM chats WHERE server_id = ? AND channel_id = ? ORDER BY id ASC LIMIT 150', (server_id, channel_id))
chats = await cursor.fetchall()
return chats
async def get_chats_custom(server_id, channel_id, limit):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM chats WHERE server_id = ? AND channel_id = ? ORDER BY id ASC LIMIT ?', (server_id, channel_id, limit))
chats = await cursor.fetchall()
return chats
async def get_chat_by_id(server_id, channel_id, message_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM chats WHERE server_id = ? AND channel_id = ? AND message_id = ?', (server_id, channel_id, message_id))
chat = await cursor.fetchone()
return chat
async def get_last_chat(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM chats WHERE server_id = ? AND channel_id = ? ORDER BY id DESC LIMIT 1', (server_id, channel_id))
chat = await cursor.fetchone()
return chat
async def get_chat_range(server_id, channel_id, start, end):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM chats WHERE server_id = ? AND channel_id = ? AND messagecount >= ? AND messagecount <= ? ORDER BY id ASC', (server_id, channel_id, start, end))
chats = await cursor.fetchall()
return chats
async def get_last_twenty_chats(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM chats WHERE server_id = ? AND channel_id = ? ORDER BY id ASC LIMIT 20', (server_id, channel_id))
chats = await cursor.fetchall()
return chats
async def add_summary(server_id, channel_id, summary, summarycount):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('INSERT OR IGNORE INTO summaries (server_id, channel_id, summary, summarycount) VALUES (?, ?, ?, ?)', (server_id, channel_id, summary, summarycount))
await db.commit()
async def remove_summary(id, server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('DELETE FROM summaries WHERE id = ? AND server_id = ? AND channel_id = ?', (id, server_id, channel_id))
await db.commit()
async def list_summaries(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM summaries WHERE server_id = ? AND channel_id = ?', (server_id, channel_id))
summaries = await cursor.fetchall()
return summaries
async def get_summary_by_id(id, server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM summaries WHERE id = ? AND server_id = ? AND channel_id = ?', (id, server_id, channel_id))
summary = await cursor.fetchone()
return summary
async def get_summary_by_count(server_id, channel_id, summarycount):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM summaries WHERE server_id = ? AND channel_id = ? AND summarycount = ?', (server_id, channel_id, summarycount))
summary = await cursor.fetchone()
return summary
async def get_latest_summary(server_id, channel_id):
async with aiosqlite.connect(DB_FILE) as db:
cursor = await db.execute('SELECT * FROM summaries WHERE server_id = ? AND channel_id = ? ORDER BY id DESC LIMIT 1', (server_id, channel_id))
summary = await cursor.fetchone()
return summary
async def add_summary_zero(server_id, channel_id):
summary = ''
summarycount = 0
if await get_latest_summary(server_id, channel_id) is not None:
if await get_last_chat(server_id, channel_id) is not None:
new_summary_point = await get_last_chat(server_id, channel_id)
new_summary_point = int(new_summary_point[8])
summarycount = new_summary_point + 1
async with aiosqlite.connect(DB_FILE) as db:
await db.execute('INSERT OR IGNORE INTO summaries (server_id, channel_id, summary, summarycount) VALUES (?, ?, ?, ?)', (server_id, channel_id, summary, summarycount))
await db.commit()

View File

@ -2,91 +2,110 @@ import openai
import json import json
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
try: import modules.summarize as summarize
import summarize import asyncio
import dbmanagement as dbm
except:
import modules.summarize as summarize
import modules.dbmanagement as dbm
load_dotenv(os.path.join("configs", ".env"))
load_dotenv(os.path.join("config", ".env"))
openai.api_key = os.environ.get('OPENAI_API_KEY') openai.api_key = os.environ.get('OPENAI_API_KEY')
folder = 'chats' folder = 'chats'
async def load_history(server_id, channel_id, mode): def load_history(id):
if mode == 0: ### Normal History with System Messages filename = f'{id}.json'
systemmsg = await dbm.get_config_by_id(server_id, channel_id) try:
systemmsg = systemmsg[4] with open(os.path.join(folder, filename), 'r') as f:
checkpoint = await dbm.get_latest_summary(server_id, channel_id) json.load(f)
checkpoint = checkpoint[4]
msgpoint = await dbm.get_last_chat(server_id, channel_id)
print(str(msgpoint))
msgpoint = msgpoint[8]
results = await dbm.get_chat_range(server_id, channel_id, checkpoint, msgpoint) except FileNotFoundError as error:
print(f'File not Found, creating... {error}')
if id == "199":
data = 'summarize:'
setup_history(id, data)
else:
data = 'default:'
setup_history(id, data)
messages = [{'role': result[5], 'content': result[7]} for result in results] except json.JSONDecodeError as error:
messages.insert(0, {'role': 'system', 'content': f'{systemmsg}'}) os.remove(os.path.join(folder, filename))
print(f'File is empty, creating... {error}')
load_history(id)
summary = await dbm.get_latest_summary(server_id, channel_id) with open(os.path.join(folder, filename), 'r') as f:
summary = summary[3] f = json.load(f)
if summary != '':
messages.insert(1, {'role': 'system', 'content': 'This is the Summary of previous conversations:\n\n' + summary})
return messages return f
if mode == 1: ### Summary Mode without System Messages and Formatted differently def update_history(id, data):
checkpoint = await dbm.get_latest_summary(server_id, channel_id) filename = f'{id}.json'
checkpoint = checkpoint[4] try:
msgpoint = await dbm.get_last_chat(server_id, channel_id) with open(os.path.join(folder, filename), "r") as f:
msgpoint = msgpoint[8] loaded = json.load(f)
loaded.append(data)
results = await dbm.get_chat_range(server_id, channel_id, checkpoint, msgpoint-10) with open(os.path.join(folder, filename), "w") as f:
json.dump(loaded, f)
messages = '' except Exception as error:
for result in results: print(error)
if result[5] == 'assistant':
messages += f"Assistant: {result[7]}\n"
elif result[5] == 'user':
messages += f"{result[7]}\n"
return messages def delete_history(id):
filename = f'{id}.json'
try:
os.remove(os.path.join(folder, filename))
return "Successfully deleted"
except Exception as error:
return error
async def get_answer(id, user, message):
try:
history = load_history(id)
add_history = {"role": "user", "content": f'{user}: {message}'}
update_history(id, add_history)
history.append(add_history)
answer = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=history
)
answer = answer['choices'][0]['message']['content']
update_history(id, {"role": "assistant", "content": f"{answer}"})
if len(history) >= 26:
await summarize.summarize(id)
# add optional parameter for mode return answer
async def get_answer(server_id=0, channel_id=0, mode=0, msg=''): except Exception as error:
if mode == 0: ### Normal Mode return "Error while trying to use ChatAPI: " + str(error)
gptversion = await dbm.get_config_by_id(server_id, channel_id)
gptversion = gptversion[3]
if gptversion == 3:
usemodel = "gpt-3.5-turbo"
elif gptversion == 4:
usemodel = "gpt-4"
history = await load_history(server_id, channel_id, 0) # def get_answergpt4(id, user, message):
# try:
# update_history(id, {"role": "user", "content": f'{user}: {message}'})
# history = load_history(id)
# answer = openai.ChatCompletion.create(
# model="gpt-4",
# messages=history
# )
# answer = answer['choices'][0]['message']['content']
# update_history(id, {"role": "assistant", "content": f"{answer}"})
# print(len(history))
# if len(history) >= 23:
# summarize.summarize(id)
#
# return answer
# except Exception as error:
# return "Error while trying to use ChatAPI " + str(error)
try: def setup_history(id, message):
answer = openai.ChatCompletion.create( filename = f'{id}.json'
model=usemodel,
messages=history
)
answer = answer['choices'][0]['message']['content']
return answer if message == "summarize":
except Exception as e: message = [{"role": "system", "content": "You summarize conversation. You keep the most important things. Everything else can be removed."}]
return "Error while trying to use ChatAPI: " + str(e) elif message == "default":
message = [{"role": "system", "content": "You are an helpful assistant. Every Message the user writes starts with their username, the numbers and # must be ignored"}]
elif mode == 1: ### Summarize Mode else:
try: message = [{"role": "system", "content": f"The Username consists of a name#numbers. The numbers can be ignored. {message}"}]
answer = openai.ChatCompletion.create(
model="gpt-4",
messages=[{'role': 'user',
'content': f'Please summarize the following conversation: {msg}'}])
answer = answer['choices'][0]['message']['content']
return answer
except Exception as e:
return "Error while trying to use ChatAPI: " + str(e)
# If file exists, delete it
if os.path.exists(os.path.join(folder, filename)):
os.remove(os.path.join(folder, filename))
# Create new file
with open(os.path.join(folder, filename), "w") as f:
json.dump(message, f)

View File

@ -1,11 +1,7 @@
import modules.gpt as gpt
import json import json
import os import os
try: import asyncio
import dbmanagement as dbm
import gpt
except:
import modules.dbmanagement as dbm
import modules.gpt as gpt
folder = 'chats' folder = 'chats'
async def summarize(id): async def summarize(id):
@ -36,12 +32,3 @@ async def summarize(id):
os.remove(os.path.join(folder, '199.json')) os.remove(os.path.join(folder, '199.json'))
return summarised return summarised
async def new_summarize(server_id, channel_id):
### Get
print(f'new_summarize called with {server_id} and {channel_id}')
history = await gpt.load_history(server_id, channel_id, 1)
summary = await gpt.get_answer(mode=1, msg=history)
msgpoint = await dbm.get_last_chat(server_id, channel_id)
msgpoint = msgpoint[8]
await dbm.add_summary(server_id, channel_id, summary, msgpoint-10)

24
bot/modules/tts.py Normal file
View File

@ -0,0 +1,24 @@
# from TTS.api import TTS
# import uuid
# import os
# import asyncio
#
# # Use Model tts_models/de/thorsten/tacotron2-DCA
# # coqui-ai
#
# async def generate_audio(text):
# loop = asyncio.get_event_loop()
# folder = "audio"
# filename = f"{uuid.uuid4().hex}.wav"
# path = os.path.join(folder, filename)
#
# try:
# def tts_to_file_blocking():
# tts = TTS(model_name="tts_models/de/thorsten/tacotron2-DDC", progress_bar=True, gpu=False)
# tts.tts_to_file(text=text, file_path=path)
#
# await loop.run_in_executor(None, tts_to_file_blocking)
# return path
# except Exception as e:
# print(e)
# return str(e)

24
bot/summary.py Normal file
View File

@ -0,0 +1,24 @@
import modules.summarize as summarize
import modules.gpt as gpt
history = gpt.load_history('112233445566')
#print(summarize.summarize('112233445566'))
new_string = ''
if history[1]['role'] == 'system':
new_string += f"System:{history[1]['content']}\n"
for x in history[:-3]:
if x['role'] == "assistant":
new_string += f"Assistant: {x['content']}\n"
elif x['role'] == "user":
new_string += f"{x['content']}\n"
print(new_string)
print(history[1])
history[1] = {'test'}
print(history)

View File

@ -1,6 +1,5 @@
aiohttp==3.8.4 aiohttp==3.8.4
aiosignal==1.3.1 aiosignal==1.3.1
aiosqlite==0.18.0
async-timeout==4.0.2 async-timeout==4.0.2
attrs==22.2.0 attrs==22.2.0
certifi==2022.12.7 certifi==2022.12.7