From 6cfd2838a55b99641c4a626868c49ebc21dc8440 Mon Sep 17 00:00:00 2001 From: Rene Teigen Date: Thu, 5 Jan 2023 14:27:39 +0000 Subject: [PATCH 1/7] Added autocompleters to settings and opener files Settings now gets current keys so manual updating of choices isn't required Changed the way opener files are added to the conversation Using an opener file also enables minimal starter Added some example opener files --- README.md | 4 ++- cogs/gpt_3_commands_and_converser.py | 52 +++++++++++++--------------- models/autocomplete_model.py | 34 ++++++++++++++++++ openers/english_translator.txt | 1 + openers/javascript_console.txt | 1 + 5 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 models/autocomplete_model.py create mode 100644 openers/english_translator.txt create mode 100644 openers/javascript_console.txt diff --git a/README.md b/README.md index b7dfe05..87a0fba 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,9 @@ These commands are grouped, so each group has a prefix but you can easily tab co `/gpt converse private:yes` - Start a private conversation with the bot, like ChatGPT -`/gpt converse opener: | .txt` - Start a conversation with the bot, with a custom opener text (this is useful if you want it to take on a custom personality from the start). You can also load the opener text from a file by saving it in the bot root directory as .txt and referencing it in the opener param. +`/gpt converse opener:` - Start a conversation with the bot, with a custom opener text (this is useful if you want it to take on a custom personality from the start). + +`/gpt converse opener_file:.txt` - Starts a conversation with the bot, using a custom file, using this option also enables the minimal conversation starter. Loads files from the `/openers` folder, has autocomplete support so files in the folder will show up `/gpt converse minimal:yes` - Start a conversation with the bot, like ChatGPT, with minimal context (saves tokens) diff --git a/cogs/gpt_3_commands_and_converser.py b/cogs/gpt_3_commands_and_converser.py index 856e41c..c59ab05 100644 --- a/cogs/gpt_3_commands_and_converser.py +++ b/cogs/gpt_3_commands_and_converser.py @@ -13,6 +13,7 @@ from models.env_service_model import EnvService from models.message_model import Message from models.user_model import User, RedoUser from models.check_model import Check +from models.autocomplete_model import Settings_autocompleter, File_autocompleter from collections import defaultdict original_message = {} @@ -749,7 +750,15 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): guild_ids=ALLOWED_GUILDS, ) @discord.option( - name="opener", description="Which sentence to start with", required=False + name="opener", + description="Which sentence to start with, added after the file", + required=False, + ) + @discord.option( + name="opener_file", + description="Which file to start with, added before the opener, disables conversation starters", + required=False, + autocomplete=File_autocompleter.get_openers ) @discord.option( name="private", @@ -759,13 +768,13 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): ) @discord.option( name="minimal", - description="Use minimal starter text", + description="Use minimal starter text, saves tokens and has a more open personality", required=False, choices=["yes"], ) @discord.guild_only() async def converse( - self, ctx: discord.ApplicationContext, opener: str, private, minimal + self, ctx: discord.ApplicationContext, opener: str, opener_file: str, private, minimal ): if private: await ctx.defer(ephemeral=True) @@ -781,22 +790,24 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): await self.deletion_queue(message) return - if not opener: + if not opener or not opener_file: user_id_normalized = user.id else: user_id_normalized = ctx.author.id # Pre-check for opener, check if they provided a valid file if it is indeed a file. # If the opener ends in .txt, its a file and we want to load it - if opener.endswith(".txt"): + if opener_file.endswith(".txt"): # Load the file and read it into opener - opener = await self.load_file(opener, ctx) - if not opener: + opener_file = f"openers/{opener_file}" + opener_file = await self.load_file(opener_file, ctx) + opener = opener_file + opener + if not opener_file: return self.conversating_users[user_id_normalized] = User(user_id_normalized) # Append the starter text for gpt3 to the user's history so it gets concatenated with the prompt later - if minimal: + if minimal or opener_file: self.conversating_users[user_id_normalized].history.append( self.CONVERSATION_STARTER_TEXT_MINIMAL ) @@ -890,28 +901,13 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): name="parameter", description="The setting to change", required=False, - choices=[ - "mode", - "temp", - "top_p", - "max_tokens", - "presence_penalty", - "frequency_penalty", - "best_of", - "prompt_min_length", - "max_conversation_length", - "model", - "low_usage_mode", - "image_size", - "num_images", - "summarize_conversations", - "summarize_threshold", - "welcome_message_enabled", - "IMAGE_SAVE_PATH", - ], + autocomplete=Settings_autocompleter.get_settings ) @discord.option( - name="value", description="The value to set the setting to", required=False + name="value", + description="The value to set the setting to", + required=False, + autocomplete=Settings_autocompleter.get_value ) @discord.guild_only() async def settings( diff --git a/models/autocomplete_model.py b/models/autocomplete_model.py new file mode 100644 index 0000000..1c65e72 --- /dev/null +++ b/models/autocomplete_model.py @@ -0,0 +1,34 @@ +from pathlib import Path +import os +import re + +import discord +from models.usage_service_model import UsageService +from models.openai_model import Model + +usage_service = UsageService(Path(os.environ.get("DATA_DIR", os.getcwd()))) +model = Model(usage_service) + + +class Settings_autocompleter: + async def get_settings(ctx: discord.AutocompleteContext): + SETTINGS = [re.sub("^_","",key) for key in model.__dict__.keys() if key not in model._hidden_attributes] + return [parameter for parameter in SETTINGS if parameter.startswith(ctx.value.lower())] + async def get_value(ctx: discord.AutocompleteContext): # Behaves a bit weird if you go back and edit the parameter without typing in a new command + values = { + 'mode' : ['temperature', 'top_p'], + 'model' : ["text-davinci-003", "text-curie-001"], + 'low_usage_mode' : ["True", "False"], + 'image_size' : ["256x256", "512x512", "1024x1024"], + 'summarize_conversastion' : ["True", "False"], + 'welcome_message_enabled' : ["True", "False"] + } + if ctx.options["parameter"] in values.keys(): + return[value for value in values[ctx.options["parameter"]]] + else: + await ctx.interaction.response.defer() # defer so the autocomplete in int values doesn't error but rather just says not found + return [] + +class File_autocompleter: + async def get_openers(ctx: discord.AutocompleteContext): + return [file for file in os.listdir('openers') if file.startswith(ctx.value.lower())] \ No newline at end of file diff --git a/openers/english_translator.txt b/openers/english_translator.txt new file mode 100644 index 0000000..c3fded6 --- /dev/null +++ b/openers/english_translator.txt @@ -0,0 +1 @@ +I want you to act as an English translator, spelling corrector and improver. I will speak to you in any language and you will detect the language, translate it and answer in the corrected and improved version of my text, in English. I want you to replace my simplified A0-level words and sentences with more beautiful and elegant, upper level English words and sentences. Keep the meaning same, but make them more literary. I want you to only reply the correction, the improvements and nothing else, do not write explanations. \ No newline at end of file diff --git a/openers/javascript_console.txt b/openers/javascript_console.txt new file mode 100644 index 0000000..57342d3 --- /dev/null +++ b/openers/javascript_console.txt @@ -0,0 +1 @@ +I want you to act as a javascript console. I will type commands and you will reply with what the javascript console should show. I want you to only reply with the terminal output inside one unique code block, and nothing else. do not write explanations. do not type commands unless I instruct you to do so. when i need to tell you something in english, i will do so by putting text inside curly brackets {like this}. \ No newline at end of file From f2033c0fccd9476f5cdff726afd72883369ef067 Mon Sep 17 00:00:00 2001 From: Rene Teigen Date: Thu, 5 Jan 2023 15:12:59 +0000 Subject: [PATCH 2/7] Set autocomplete to limit to 25 options, the max --- models/autocomplete_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/autocomplete_model.py b/models/autocomplete_model.py index 1c65e72..adf5779 100644 --- a/models/autocomplete_model.py +++ b/models/autocomplete_model.py @@ -13,7 +13,7 @@ model = Model(usage_service) class Settings_autocompleter: async def get_settings(ctx: discord.AutocompleteContext): SETTINGS = [re.sub("^_","",key) for key in model.__dict__.keys() if key not in model._hidden_attributes] - return [parameter for parameter in SETTINGS if parameter.startswith(ctx.value.lower())] + return [parameter for parameter in SETTINGS if parameter.startswith(ctx.value.lower())][:25] async def get_value(ctx: discord.AutocompleteContext): # Behaves a bit weird if you go back and edit the parameter without typing in a new command values = { 'mode' : ['temperature', 'top_p'], @@ -31,4 +31,4 @@ class Settings_autocompleter: class File_autocompleter: async def get_openers(ctx: discord.AutocompleteContext): - return [file for file in os.listdir('openers') if file.startswith(ctx.value.lower())] \ No newline at end of file + return [file for file in os.listdir('openers') if file.startswith(ctx.value.lower())][:25] # returns the 25 first files from your current input \ No newline at end of file From af76a580a4d018563ba675abe8ec7240b08e17ec Mon Sep 17 00:00:00 2001 From: Rene Teigen Date: Thu, 5 Jan 2023 15:33:53 +0000 Subject: [PATCH 3/7] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 87a0fba..e0bf87f 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ These commands are grouped, so each group has a prefix but you can easily tab co `/gpt converse opener:` - Start a conversation with the bot, with a custom opener text (this is useful if you want it to take on a custom personality from the start). -`/gpt converse opener_file:.txt` - Starts a conversation with the bot, using a custom file, using this option also enables the minimal conversation starter. Loads files from the `/openers` folder, has autocomplete support so files in the folder will show up +`/gpt converse opener_file:.txt` - Starts a conversation with the bot, using a custom file, using this option also enables the minimal conversation starter. Loads files from the `/openers` folder, has autocomplete support so files in the folder will show up. Added before the `opener` as both can be used at the same time `/gpt converse minimal:yes` - Start a conversation with the bot, like ChatGPT, with minimal context (saves tokens) @@ -68,7 +68,7 @@ These commands are grouped, so each group has a prefix but you can easily tab co `/system settings` - Display settings for the model (temperature, top_p, etc) -`/system settings ` - Change a model setting to a new value +`/system settings ` - Change a model setting to a new value. Has autocomplete support, certain settings will have autocompleted values too. `/system usage` Estimate current usage details (based on davinci) From 581ec17643919332eadf5f9f019baf27d709b719 Mon Sep 17 00:00:00 2001 From: Rene Teigen Date: Thu, 5 Jan 2023 15:44:44 +0000 Subject: [PATCH 4/7] Wrong opener_file description --- cogs/gpt_3_commands_and_converser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogs/gpt_3_commands_and_converser.py b/cogs/gpt_3_commands_and_converser.py index c59ab05..53979cc 100644 --- a/cogs/gpt_3_commands_and_converser.py +++ b/cogs/gpt_3_commands_and_converser.py @@ -756,7 +756,7 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): ) @discord.option( name="opener_file", - description="Which file to start with, added before the opener, disables conversation starters", + description="Which file to start with, added before the opener, sets minimal starter", required=False, autocomplete=File_autocompleter.get_openers ) From f8d3dd0ffd7436fa00952e3d59368c312dfbb3de Mon Sep 17 00:00:00 2001 From: Rene Teigen Date: Thu, 5 Jan 2023 16:06:00 +0000 Subject: [PATCH 5/7] Added os specific separator like in gpt3discord.py --- cogs/gpt_3_commands_and_converser.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cogs/gpt_3_commands_and_converser.py b/cogs/gpt_3_commands_and_converser.py index 53979cc..bfe0b4e 100644 --- a/cogs/gpt_3_commands_and_converser.py +++ b/cogs/gpt_3_commands_and_converser.py @@ -2,6 +2,7 @@ import datetime import json import re import traceback +import sys from pathlib import Path import aiofiles @@ -18,6 +19,10 @@ from collections import defaultdict original_message = {} ALLOWED_GUILDS = EnvService.get_allowed_guilds() +if sys.platform == "win32": + separator = "\\" +else: + separator = "/" class GPT3ComCon(discord.Cog, name="GPT3ComCon"): @@ -798,7 +803,7 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): # If the opener ends in .txt, its a file and we want to load it if opener_file.endswith(".txt"): # Load the file and read it into opener - opener_file = f"openers/{opener_file}" + opener_file = f"openers{separator}{opener_file}" opener_file = await self.load_file(opener_file, ctx) opener = opener_file + opener if not opener_file: From ae64bc9fa2ce4107580697f309162bd3e4854d98 Mon Sep 17 00:00:00 2001 From: Rene Teigen Date: Thu, 5 Jan 2023 22:29:48 +0000 Subject: [PATCH 6/7] Fixed opener_file not being able to be used alone --- cogs/gpt_3_commands_and_converser.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/cogs/gpt_3_commands_and_converser.py b/cogs/gpt_3_commands_and_converser.py index bfe0b4e..fa18e41 100644 --- a/cogs/gpt_3_commands_and_converser.py +++ b/cogs/gpt_3_commands_and_converser.py @@ -795,19 +795,23 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): await self.deletion_queue(message) return - if not opener or not opener_file: + if not opener and not opener_file: user_id_normalized = user.id else: user_id_normalized = ctx.author.id - # Pre-check for opener, check if they provided a valid file if it is indeed a file. - # If the opener ends in .txt, its a file and we want to load it - if opener_file.endswith(".txt"): - # Load the file and read it into opener - opener_file = f"openers{separator}{opener_file}" - opener_file = await self.load_file(opener_file, ctx) - opener = opener_file + opener - if not opener_file: - return + if opener_file: # only load in files if it's included in the command, if not pass on as normal + if opener_file.endswith(".txt"): + # Load the file and read it into opener + opener_file = f"openers{separator}{opener_file}" + opener_file = await self.load_file(opener_file, ctx) + if not opener: # if we only use opener_file then only pass on opener_file for the opening prompt + opener = opener_file + else: + opener = opener_file + opener + if not opener_file: + return + else: + pass self.conversating_users[user_id_normalized] = User(user_id_normalized) From 92f902cb157ee3bc05203a7bcb54329143f290ae Mon Sep 17 00:00:00 2001 From: Rene Teigen Date: Thu, 5 Jan 2023 22:46:59 +0000 Subject: [PATCH 7/7] return message if no opener folder --- models/autocomplete_model.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/models/autocomplete_model.py b/models/autocomplete_model.py index adf5779..5698412 100644 --- a/models/autocomplete_model.py +++ b/models/autocomplete_model.py @@ -31,4 +31,7 @@ class Settings_autocompleter: class File_autocompleter: async def get_openers(ctx: discord.AutocompleteContext): - return [file for file in os.listdir('openers') if file.startswith(ctx.value.lower())][:25] # returns the 25 first files from your current input \ No newline at end of file + try: + return [file for file in os.listdir('openers') if file.startswith(ctx.value.lower())][:25] # returns the 25 first files from your current input + except: + return ["No 'openers' folder"] \ No newline at end of file