Compare commits

...

2 Commits

Author SHA1 Message Date
crennis
a898d0d9b8 Update 2023-04-11 09:30:17 +02:00
crennis
cffa0954a8 Update, SQLite, Async and More 2023-04-11 09:27:20 +02:00
10 changed files with 549 additions and 382 deletions

View File

@ -8,9 +8,12 @@ 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 two ways to use this bot: There are three ways to use this bot:
Using Docker or without Docker. 1. By just inviting [this Bot](https://discord.com/api/oauth2/authorize?client_id=1083786070786850959&permissions=2147486720&scope=bot) to your Server
2. Using Docker
3. Without using Docker
### The No Docker Way ### The No Docker Way

View File

@ -1,22 +1,16 @@
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.tts as tts import modules.dbmanagement as dbm
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 = "configs" configfolder = "config"
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
@ -27,131 +21,234 @@ 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
if str(message.channel.id) in text_channels and not message.content.startswith("$"): ### Check if Channel is Configured
await message.channel.trigger_typing() if await dbm.get_channel_by_id(message.guild.id, message.channel.id) is not None:
print(f'{message.author} asked: {message.content}') config = await dbm.get_config_by_id(message.guild.id, message.channel.id)
answer = await gpt.get_answer(message.channel.id, message.author, message.content) if message.content.startswith(config[2]):
print(f'Answer: {answer}') ### Count Messages for Summary
await message.channel.send(answer) counter = 0
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)
if str(message.channel.id) in prefix_channels: ### Read and Send Message/Answer
if message.content.startswith("!"):
msg_split = message.content.split("!")[1]
await message.channel.trigger_typing() await message.channel.trigger_typing()
print(f'{message.author} asked: {message.content}') msg = message.content.replace(config[2], "", 1)
answer = await gpt.get_answer(message.channel.id, message.author, msg_split) await dbm.add_chat(message.guild.id, message.channel.id, message.author.id, message.author.name, "user", message.id, f'{message.author}: {msg}', counter)
print(f'Answer: {answer}') answer = await gpt.get_answer(message.guild.id, message.channel.id)
await message.channel.send(answer) sendmsg = 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")
async def add( @commands.has_permissions(administrator=True)
ctx: discord.ApplicationContext, async def add(ctx: discord.ApplicationContext):
option: discord.Option(str, choices=["text","prefix"], description="Type of Channel to Add"), if await dbm.get_channel_by_id(ctx.guild.id, ctx.channel.id) is None:
id: discord.Option(str, description="Channel-ID -> Activate Developer-Options to Copy")): modal = AddModal(title="Add Channel")
await ctx.send_modal(modal)
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: else:
await ctx.respond(f'Error: You need to be an Administrator to use this command', ephemeral=True) await ctx.respond("Channel has already been added. Use /setup", 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")
async def remove( @commands.has_permissions(administrator=True)
ctx: discord.ApplicationContext, async def remove(ctx: discord.ApplicationContext):
option: discord.Option(str, choices=["text", "prefix"], description="Type of Channel to Add"), if await dbm.get_channel_by_id(ctx.guild.id, ctx.channel.id) is not None:
id: discord.Option(str, description="Channel-ID -> Activate Developer-Options to Copy")): await dbm.remove_channel(ctx.guild.id, ctx.channel.id)
if ctx.author.guild_permissions.administrator: await ctx.respond("Channel removed", ephemeral=True)
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(f'Error: You need to be an Administrator to use this command', ephemeral=True) await ctx.respond("Channel not active. Nothing Done", 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")):
if ctx.author.guild_permissions.administrator: @bot.command(name="list", description="Used to list all Channels in the Server")
if option == "text": @commands.has_permissions(administrator=True)
await ctx.respond(f'{option} channels: {str(text_channels)}', ephemeral=True) async def list(ctx: discord.ApplicationContext):
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)
@bot.command(name="delete", description="Used to delete chat history of specific Channels/Users") await ctx.respond("This command is WIP")
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'
f'/ping\n' 'Needs Rewrite\n', ephemeral=True)
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)
@bot.command(name="setup", description="Used to setup the bot with a custom system message") # Old System, Rewrite needed
async def setup(ctx: discord.ApplicationContext, @bot.command(name="system", description="Used to setup the bot with a custom system message")
id: discord.Option(str, description="Channel-ID -> Activate Developer-Options to Copy"), @commands.has_permissions(administrator=True)
message: discord.Option(str, description="System Message")): async def system(ctx: discord.ApplicationContext):
if ctx.author.guild_permissions.administrator:
try: try:
gpt.setup_history(id, message) modal = EditSystemModal(title="Change System Message")
await ctx.respond(f'Setup successful', ephemeral=True) await ctx.send_modal(modal)
except Exception as e: except:
await ctx.respond(f'Error: {e}', ephemeral=True) await ctx.respond("No Config found for this Channel", ephemeral=True)
else:
await ctx.respond(f'Error: You need to be an Administrator to use this command', ephemeral=True) ### /\ End Commands Area /\ ###
bot.run(str(os.environ.get('DISCORD_TOKEN'))) bot.run(str(os.environ.get('DISCORD_TOKEN')))

View File

@ -1,51 +0,0 @@
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

@ -1,88 +0,0 @@
# 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

259
bot/modules/dbmanagement.py Normal file
View File

@ -0,0 +1,259 @@
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,110 +2,91 @@ import openai
import json import json
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
try:
import summarize
import dbmanagement as dbm
except:
import modules.summarize as summarize import modules.summarize as summarize
import asyncio 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'
def load_history(id): async def load_history(server_id, channel_id, mode):
filename = f'{id}.json' if mode == 0: ### Normal History with System Messages
systemmsg = await dbm.get_config_by_id(server_id, channel_id)
systemmsg = systemmsg[4]
checkpoint = await dbm.get_latest_summary(server_id, channel_id)
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)
messages = [{'role': result[5], 'content': result[7]} for result in results]
messages.insert(0, {'role': 'system', 'content': f'{systemmsg}'})
summary = await dbm.get_latest_summary(server_id, channel_id)
summary = summary[3]
if summary != '':
messages.insert(1, {'role': 'system', 'content': 'This is the Summary of previous conversations:\n\n' + summary})
return messages
if mode == 1: ### Summary Mode without System Messages and Formatted differently
checkpoint = await dbm.get_latest_summary(server_id, channel_id)
checkpoint = checkpoint[4]
msgpoint = await dbm.get_last_chat(server_id, channel_id)
msgpoint = msgpoint[8]
results = await dbm.get_chat_range(server_id, channel_id, checkpoint, msgpoint-10)
messages = ''
for result in results:
if result[5] == 'assistant':
messages += f"Assistant: {result[7]}\n"
elif result[5] == 'user':
messages += f"{result[7]}\n"
return messages
# add optional parameter for mode
async def get_answer(server_id=0, channel_id=0, mode=0, msg=''):
if mode == 0: ### Normal Mode
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)
try: try:
with open(os.path.join(folder, filename), 'r') as f:
json.load(f)
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)
except json.JSONDecodeError as error:
os.remove(os.path.join(folder, filename))
print(f'File is empty, creating... {error}')
load_history(id)
with open(os.path.join(folder, filename), 'r') as f:
f = json.load(f)
return f
def update_history(id, data):
filename = f'{id}.json'
try:
with open(os.path.join(folder, filename), "r") as f:
loaded = json.load(f)
loaded.append(data)
with open(os.path.join(folder, filename), "w") as f:
json.dump(loaded, f)
except Exception as error:
print(error)
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( answer = openai.ChatCompletion.create(
model="gpt-3.5-turbo", model=usemodel,
messages=history messages=history
) )
answer = answer['choices'][0]['message']['content'] answer = answer['choices'][0]['message']['content']
update_history(id, {"role": "assistant", "content": f"{answer}"})
if len(history) >= 26:
await summarize.summarize(id)
return answer return answer
except Exception as error: except Exception as e:
return "Error while trying to use ChatAPI: " + str(error) return "Error while trying to use ChatAPI: " + str(e)
# def get_answergpt4(id, user, message): elif mode == 1: ### Summarize Mode
# try: try:
# update_history(id, {"role": "user", "content": f'{user}: {message}'}) answer = openai.ChatCompletion.create(
# history = load_history(id) model="gpt-4",
# answer = openai.ChatCompletion.create( messages=[{'role': 'user',
# model="gpt-4", 'content': f'Please summarize the following conversation: {msg}'}])
# 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)
def setup_history(id, message): answer = answer['choices'][0]['message']['content']
filename = f'{id}.json' return answer
except Exception as e:
return "Error while trying to use ChatAPI: " + str(e)
if message == "summarize":
message = [{"role": "system", "content": "You summarize conversation. You keep the most important things. Everything else can be removed."}]
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"}]
else:
message = [{"role": "system", "content": f"The Username consists of a name#numbers. The numbers can be ignored. {message}"}]
# 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,7 +1,11 @@
import modules.gpt as gpt
import json import json
import os import os
import asyncio try:
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):
@ -32,3 +36,12 @@ 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)

View File

@ -1,24 +0,0 @@
# 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)

View File

@ -1,24 +0,0 @@
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,5 +1,6 @@
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