diff --git a/cogs/commands.py b/cogs/commands.py index 0264d91..6f7f647 100644 --- a/cogs/commands.py +++ b/cogs/commands.py @@ -523,6 +523,89 @@ class Commands(discord.Cog, name="Commands"): # # Index commands # + @add_to_group("index") + @discord.slash_command( + name="rename-user", + description="Select one of your saved indexes to rename", + guild_ids=ALLOWED_GUILDS, + ) + @discord.guild_only() + @discord.option( + name="user_index", + description="Which user index to rename", + required=False, + autocomplete=File_autocompleter.get_user_indexes, + ) + @discord.option( + name="new_name", + description="The new name", + required=False, + type=discord.SlashCommandOptionType.string, + ) + async def rename_user_index( + self, + ctx: discord.ApplicationContext, + user_index: str, + new_name: str, + ): + await ctx.defer() + await self.index_cog.rename_user_index_command(ctx, user_index, new_name) + + @add_to_group("index") + @discord.slash_command( + name="rename-server", + description="Select one of your saved server indexes to rename", + guild_ids=ALLOWED_GUILDS, + ) + @discord.guild_only() + @discord.option( + name="server_index", + description="Which server index to rename", + required=False, + autocomplete=File_autocompleter.get_server_indexes, + ) + @discord.option( + name="new_name", + description="The new name", + required=False, + type=discord.SlashCommandOptionType.string, + ) + async def rename_server_index( + self, + ctx: discord.ApplicationContext, + server_index: str, + new_name: str, + ): + await ctx.defer() + await self.index_cog.rename_server_index_command(ctx, server_index, new_name) + + @add_to_group("index") + @discord.slash_command( + name="rename-search", + description="Select one of your saved search indexes to rename", + guild_ids=ALLOWED_GUILDS, + ) + @discord.guild_only() + @discord.option( + name="search_index", + description="Which search index to rename", + required=False, + autocomplete=File_autocompleter.get_user_search_indexes, + ) + @discord.option( + name="new_name", + description="The new name", + required=False, + type=discord.SlashCommandOptionType.string, + ) + async def rename_search_index( + self, + ctx: discord.ApplicationContext, + search_index: str, + new_name: str, + ): + await ctx.defer() + await self.index_cog.rename_search_index_command(ctx, search_index, new_name) @add_to_group("index") @discord.slash_command( @@ -622,10 +705,21 @@ class Commands(discord.Cog, name="Commands"): required=False, input_type=discord.SlashCommandOptionType.channel, ) + @discord.option( + name="message_limit", + description="The number of messages to index", + required=False, + input_type=discord.SlashCommandOptionType.integer, + ) async def set_discord( - self, ctx: discord.ApplicationContext, channel: discord.TextChannel + self, + ctx: discord.ApplicationContext, + channel: discord.TextChannel, + message_limit: int, ): - await self.index_cog.set_discord_command(ctx, channel) + await self.index_cog.set_discord_command( + ctx, channel, message_limit=message_limit + ) @add_to_group("index") @discord.slash_command( @@ -634,9 +728,15 @@ class Commands(discord.Cog, name="Commands"): guild_ids=ALLOWED_GUILDS, checks=[Check.check_admin_roles(), Check.check_index_roles()], ) + @discord.option( + name="message_limit", + description="The number of messages to index per channel", + required=False, + input_type=discord.SlashCommandOptionType.integer, + ) @discord.guild_only() - async def discord_backup(self, ctx: discord.ApplicationContext): - await self.index_cog.discord_backup_command(ctx) + async def discord_backup(self, ctx: discord.ApplicationContext, message_limit: int): + await self.index_cog.discord_backup_command(ctx, message_limit=message_limit) @add_to_group("index") @discord.slash_command( @@ -650,7 +750,7 @@ class Commands(discord.Cog, name="Commands"): required=False, default=1, min_value=1, - max_value=3, + max_value=5, input_type=discord.SlashCommandOptionType.integer, ) @discord.option( @@ -661,15 +761,27 @@ class Commands(discord.Cog, name="Commands"): default="default", choices=["default", "compact", "tree_summarize"], ) + @discord.option( + name="child_branch_factor", + description="Only for deep indexes, how deep to go, higher is expensive.", + required=False, + default=1, + min_value=1, + max_value=3, + input_type=discord.SlashCommandOptionType.integer, + ) async def query( self, ctx: discord.ApplicationContext, query: str, nodes: int, response_mode: str, + child_branch_factor: int, ): await ctx.defer() - await self.index_cog.query_command(ctx, query, nodes, response_mode) + await self.index_cog.query_command( + ctx, query, nodes, response_mode, child_branch_factor + ) # # DALLE commands @@ -859,7 +971,7 @@ class Commands(discord.Cog, name="Commands"): description="The higher the number, the more accurate the results, but more expensive", required=False, input_type=discord.SlashCommandOptionType.integer, - max_value=5, + max_value=8, min_value=1, ) @discord.option( diff --git a/cogs/index_service_cog.py b/cogs/index_service_cog.py index 635ecae..0656206 100644 --- a/cogs/index_service_cog.py +++ b/cogs/index_service_cog.py @@ -1,4 +1,5 @@ import traceback +from pathlib import Path import discord @@ -24,6 +25,52 @@ class IndexService(discord.Cog, name="IndexService"): self.bot = bot self.index_handler = Index_handler(bot, usage_service) + async def rename_user_index_command(self, ctx, user_index, new_name): + """Command handler to rename a user index""" + + if not new_name: + await ctx.respond("Please provide a new name for this index") + return + + if await self.index_handler.rename_index( + ctx, + f"indexes/{ctx.user.id}/{user_index}", + f"indexes/{ctx.user.id}/{new_name}", + ): + await ctx.respond(f"Your index has been renamed to `{new_name}`") + else: + await ctx.respond("Something went wrong while renaming your index") + + async def rename_server_index_command(self, ctx, server_index, new_name): + """Command handler to rename a user index""" + + if not new_name: + await ctx.respond("Please provide a new name for this index") + return + + if await self.index_handler.rename_index( + ctx, + f"indexes/{ctx.guild.id}/{server_index}", + f"indexes/{ctx.guild.id}/{new_name}", + ): + await ctx.respond(f"Your index has been renamed to `{new_name}`") + else: + await ctx.respond("Something went wrong while renaming your index") + + async def rename_search_index_command(self, ctx, search_index, new_name): + if not new_name: + await ctx.respond("Please provide a new name for this index") + return + + if await self.index_handler.rename_index( + ctx, + f"indexes/{ctx.user.id}_search/{search_index}", + f"indexes/{ctx.user.id}_search/{new_name}", + ): + await ctx.respond(f"Your index has been renamed to `{new_name}`") + else: + await ctx.respond("Something went wrong while renaming your index") + async def set_index_command( self, ctx, file: discord.Attachment = None, link: str = None ): @@ -56,7 +103,9 @@ class IndexService(discord.Cog, name="IndexService"): ctx, link, user_api_key=user_api_key ) - async def set_discord_command(self, ctx, channel: discord.TextChannel = None): + async def set_discord_command( + self, ctx, channel: discord.TextChannel = None, message_limit: int = 2500 + ): """Command handler to set a channel as your personal index""" await ctx.defer() @@ -69,7 +118,7 @@ class IndexService(discord.Cog, name="IndexService"): return await self.index_handler.set_discord_index( - ctx, channel, user_api_key=user_api_key + ctx, channel, user_api_key=user_api_key, message_limit=message_limit ) async def reset_command(self, ctx): @@ -83,7 +132,7 @@ class IndexService(discord.Cog, name="IndexService"): "Something went wrong while resetting your indexes. Contact the server admin." ) - async def discord_backup_command(self, ctx): + async def discord_backup_command(self, ctx, message_limit: int = 2500): """Command handler to backup the entire server""" await ctx.defer() @@ -94,7 +143,9 @@ class IndexService(discord.Cog, name="IndexService"): ) if not user_api_key: return - await self.index_handler.backup_discord(ctx, user_api_key=user_api_key) + await self.index_handler.backup_discord( + ctx, user_api_key=user_api_key, message_limit=message_limit + ) async def load_index_command(self, ctx, user_index, server_index, search_index): """Command handler to load indexes""" @@ -137,7 +188,9 @@ class IndexService(discord.Cog, name="IndexService"): return await self.index_handler.load_index(ctx, index, server, search, user_api_key) - async def query_command(self, ctx, query, nodes, response_mode): + async def query_command( + self, ctx, query, nodes, response_mode, child_branch_factor + ): """Command handler to query your index""" user_api_key = None @@ -153,7 +206,9 @@ class IndexService(discord.Cog, name="IndexService"): if await Moderation.simple_moderate_and_respond(query, ctx): return - await self.index_handler.query(ctx, query, response_mode, nodes, user_api_key) + await self.index_handler.query( + ctx, query, response_mode, nodes, user_api_key, child_branch_factor + ) async def compose_command(self, ctx, name): """Command handler to compose from your index""" diff --git a/cogs/text_service_cog.py b/cogs/text_service_cog.py index 91ee72e..74060fd 100644 --- a/cogs/text_service_cog.py +++ b/cogs/text_service_cog.py @@ -793,6 +793,13 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): user = ctx.user if is_context else ctx.author prompt = await self.mention_to_username(ctx, prompt.strip()) + if len(prompt) < self.model.prompt_min_length: + alias = ctx.respond if is_context else ctx.send + await alias( + f"Prompt must be greater than {self.model.prompt_min_length} characters, it is currently: {len(prompt)} characters" + ) + return + user_api_key = None if USER_INPUT_API_KEYS: user_api_key = await TextService.get_user_api_key(user.id, ctx, USER_KEY_DB) @@ -846,6 +853,13 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"): text = await self.mention_to_username(ctx, text.strip()) instruction = await self.mention_to_username(ctx, instruction.strip()) + # Validate that all the parameters are in a good state before we send the request + if len(instruction) < self.model.prompt_min_length: + await ctx.respond( + f"Instruction must be at least {self.model.prompt_min_length} characters long" + ) + return + user_api_key = None if USER_INPUT_API_KEYS: user_api_key = await TextService.get_user_api_key(user.id, ctx, USER_KEY_DB) diff --git a/detailed_guides/CUSTOM-INDEXES.md b/detailed_guides/CUSTOM-INDEXES.md index 9ce130c..39f84c4 100644 --- a/detailed_guides/CUSTOM-INDEXES.md +++ b/detailed_guides/CUSTOM-INDEXES.md @@ -12,4 +12,8 @@ Supported filetypes: Index Compositions: Indexes can be combined with other indexes through a composition. To combine indexes, you can run the `/index compose` command, and select the indexes that you want to combine together. You should only combine relevant indexes together, combining irrelevant indexes together will result in poor results (for example, don't upload a math textbook and then upload a large set of poems and combine them together). When creating a composition, you will be given the option to do a "Deep" composition, deep compositions are more detailed and will give you better results, but are incredibly costly and will sometimes take multiple minutes to compose. -You can also compose a singular index with itself with "Deep Compose", this will give you a more detailed version of the index, but will be costly and will sometimes take multiple minutes to compose. **Deep compositions are useless for very short documents!** \ No newline at end of file +You can also compose a singular index with itself with "Deep Compose", this will give you a more detailed version of the index, but will be costly and will sometimes take multiple minutes to compose. **Deep compositions are useless for very short documents!** + +Doing a deep composition will also allow you to use the `child_branch_factor` parameter for `/index query`, increasing this past 1 will take a much longer time to query and will be much more expensive for large documents, so be wary. + +**When doing Deep Compositions, it's highly reccomended to keep the document size small, or only do deep compositions on single documents.** This is because a deep composition reorganizes the simple index into a tree structure and uses GPT3 to summarize different nodes of the tree, which will lead to high costs. For example, a deep composition of a 300 page lab manual and the contents of my personal website at https://kaveenk.com cost me $2 USD roughly. \ No newline at end of file diff --git a/gpt3discord.py b/gpt3discord.py index 8654cf3..fe81729 100644 --- a/gpt3discord.py +++ b/gpt3discord.py @@ -31,7 +31,7 @@ from services.environment_service import EnvService from models.openai_model import Model -__version__ = "10.6.3" +__version__ = "10.7.0" PID_FILE = Path("bot.pid") diff --git a/models/index_model.py b/models/index_model.py index 870c470..087daa0 100644 --- a/models/index_model.py +++ b/models/index_model.py @@ -1,3 +1,4 @@ +import functools import os import random import tempfile @@ -18,6 +19,7 @@ from langchain import OpenAI from gpt_index.readers import YoutubeTranscriptReader from gpt_index.readers.schema.base import Document +from gpt_index.langchain_helpers.text_splitter import TokenTextSplitter from gpt_index import ( GPTSimpleVectorIndex, @@ -46,7 +48,14 @@ SHORT_TO_LONG_CACHE = {} def get_and_query( - user_id, index_storage, query, response_mode, nodes, llm_predictor, embed_model + user_id, + index_storage, + query, + response_mode, + nodes, + llm_predictor, + embed_model, + child_branch_factor, ): index: [GPTSimpleVectorIndex, ComposableGraph] = index_storage[ user_id @@ -54,9 +63,10 @@ def get_and_query( if isinstance(index, GPTTreeIndex): response = index.query( query, - child_branch_factor=2, + child_branch_factor=child_branch_factor, llm_predictor=llm_predictor, embed_model=embed_model, + use_async=True, ) else: response = index.query( @@ -65,6 +75,7 @@ def get_and_query( llm_predictor=llm_predictor, embed_model=embed_model, similarity_top_k=nodes, + use_async=True, ) return response @@ -116,7 +127,8 @@ class IndexData: # First, clear all the files inside it for file in os.listdir(f"{app_root_path()}/indexes/{user_id}"): os.remove(f"{app_root_path()}/indexes/{user_id}/{file}") - + for file in os.listdir(f"{app_root_path()}/indexes/{user_id}_search"): + os.remove(f"{app_root_path()}/indexes/{user_id}_search/{file}") except Exception: traceback.print_exc() @@ -139,6 +151,22 @@ class Index_handler: ) self.EMBED_CUTOFF = 2000 + async def rename_index(self, ctx, original_path, rename_path): + """Command handler to rename a user index""" + + index_file = EnvService.find_shared_file(original_path) + if not index_file: + return False + + # Rename the file at f"indexes/{ctx.user.id}/{user_index}" to f"indexes/{ctx.user.id}/{new_name}" using Pathlib + try: + if not rename_path.endswith(".json"): + rename_path = rename_path + ".json" + Path(original_path).rename(rename_path) + return True + except Exception as e: + return False + async def paginate_embed(self, response_text): """Given a response text make embed pages and return a list of the pages. Codex makes it a codeblock in the embed""" @@ -165,22 +193,26 @@ class Index_handler: return pages - # TODO We need to do predictions below for token usage. def index_file(self, file_path, embed_model) -> GPTSimpleVectorIndex: document = SimpleDirectoryReader(file_path).load_data() - index = GPTSimpleVectorIndex(document, embed_model=embed_model) + index = GPTSimpleVectorIndex(document, embed_model=embed_model, use_async=True) return index def index_gdoc(self, doc_id, embed_model) -> GPTSimpleVectorIndex: document = GoogleDocsReader().load_data(doc_id) - index = GPTSimpleVectorIndex(document, embed_model=embed_model) + index = GPTSimpleVectorIndex(document, embed_model=embed_model, use_async=True) return index def index_youtube_transcript(self, link, embed_model): - documents = YoutubeTranscriptReader().load_data(ytlinks=[link]) + try: + documents = YoutubeTranscriptReader().load_data(ytlinks=[link]) + except Exception as e: + raise ValueError(f"The youtube transcript couldn't be loaded: {e}") + index = GPTSimpleVectorIndex( documents, embed_model=embed_model, + use_async=True, ) return index @@ -202,6 +234,7 @@ class Index_handler: index = GPTSimpleVectorIndex( documents, embed_model=embed_model, + use_async=True, ) return index @@ -216,6 +249,7 @@ class Index_handler: index = GPTSimpleVectorIndex( document, embed_model=embed_model, + use_async=True, ) return index @@ -252,10 +286,16 @@ class Index_handler: # Detect if the link is a PDF, if it is, we load it differently if response.headers["Content-Type"] == "application/pdf": documents = await self.index_pdf(url) - index = GPTSimpleVectorIndex( - documents, - embed_model=embed_model, + index = await self.loop.run_in_executor( + None, + functools.partial( + GPTSimpleVectorIndex, + documents=documents, + embed_model=embed_model, + use_async=True, + ), ) + return index except: raise ValueError("Could not load webpage") @@ -263,7 +303,16 @@ class Index_handler: documents = BeautifulSoupWebReader( website_extractor=DEFAULT_WEBSITE_EXTRACTOR ).load_data(urls=[url]) - index = GPTSimpleVectorIndex(documents, embed_model=embed_model) + # index = GPTSimpleVectorIndex(documents, embed_model=embed_model, use_async=True) + index = await self.loop.run_in_executor( + None, + functools.partial( + GPTSimpleVectorIndex, + documents=documents, + embed_model=embed_model, + use_async=True, + ), + ) return index def reset_indexes(self, user_id): @@ -331,7 +380,6 @@ class Index_handler: else: os.environ["OPENAI_API_KEY"] = user_api_key - # TODO Link validation try: embedding_model = OpenAIEmbedding() @@ -380,6 +428,11 @@ class Index_handler: self.index_storage[ctx.user.id].add_index(index, ctx.user.id, file_name) + except ValueError as e: + await ctx.respond(str(e)) + traceback.print_exc() + return + except Exception: await ctx.respond("Failed to set index") traceback.print_exc() @@ -392,6 +445,7 @@ class Index_handler: ctx: discord.ApplicationContext, channel: discord.TextChannel, user_api_key, + message_limit: int = 2500, ): if not user_api_key: os.environ["OPENAI_API_KEY"] = self.openai_key @@ -400,7 +454,7 @@ class Index_handler: try: document = await self.load_data( - channel_ids=[channel.id], limit=1000, oldest_first=False + channel_ids=[channel.id], limit=message_limit, oldest_first=False ) embedding_model = OpenAIEmbedding() index = await self.loop.run_in_executor( @@ -445,6 +499,33 @@ class Index_handler: traceback.print_exc() await ctx.respond(e) + async def index_to_docs( + self, old_index, chunk_size: int = 4000, chunk_overlap: int = 200 + ) -> List[Document]: + documents = [] + for doc_id in old_index.docstore.docs.keys(): + text = "" + if isinstance(old_index, GPTSimpleVectorIndex): + nodes = old_index.docstore.get_document(doc_id).get_nodes( + old_index.docstore.docs[doc_id].id_map + ) + for node in nodes: + extra_info = node.extra_info + text += f"{node.text} " + if isinstance(old_index, GPTTreeIndex): + nodes = old_index.docstore.get_document(doc_id).all_nodes.items() + for node in nodes: + extra_info = node[1].extra_info + text += f"{node[1].text} " + text_splitter = TokenTextSplitter( + separator=" ", chunk_size=chunk_size, chunk_overlap=chunk_overlap + ) + text_chunks = text_splitter.split_text(text) + for text in text_chunks: + document = Document(text, extra_info=extra_info) + documents.append(document) + return documents + async def compose_indexes(self, user_id, indexes, name, deep_compose): # Load all the indexes first index_objects = [] @@ -459,11 +540,7 @@ class Index_handler: if deep_compose: documents = [] for _index in index_objects: - [ - documents.append(_index.docstore.get_document(doc_id)) - for doc_id in [docmeta for docmeta in _index.docstore.docs.keys()] - if isinstance(_index.docstore.get_document(doc_id), Document) - ] + documents.extend(await self.index_to_docs(_index, 256, 20)) llm_predictor = LLMPredictor( llm=OpenAI(model_name="text-davinci-003", max_tokens=-1) ) @@ -476,6 +553,7 @@ class Index_handler: documents=documents, llm_predictor=llm_predictor, embed_model=embedding_model, + use_async=True, ), ) @@ -497,11 +575,7 @@ class Index_handler: else: documents = [] for _index in index_objects: - [ - documents.append(_index.docstore.get_document(doc_id)) - for doc_id in [docmeta for docmeta in _index.docstore.docs.keys()] - if isinstance(_index.docstore.get_document(doc_id), Document) - ] + documents.extend(await self.index_to_docs(_index)) embedding_model = OpenAIEmbedding() @@ -511,6 +585,7 @@ class Index_handler: GPTSimpleVectorIndex, documents=documents, embed_model=embedding_model, + use_async=True, ), ) @@ -525,7 +600,9 @@ class Index_handler: simple_index.save_to_disk(f"indexes/{user_id}/{name}.json") self.index_storage[user_id].queryable_index = simple_index - async def backup_discord(self, ctx: discord.ApplicationContext, user_api_key): + async def backup_discord( + self, ctx: discord.ApplicationContext, user_api_key, message_limit + ): if not user_api_key: os.environ["OPENAI_API_KEY"] = self.openai_key else: @@ -536,7 +613,7 @@ class Index_handler: for c in ctx.guild.text_channels: channel_ids.append(c.id) document = await self.load_data( - channel_ids=channel_ids, limit=3000, oldest_first=False + channel_ids=channel_ids, limit=message_limit, oldest_first=False ) embedding_model = OpenAIEmbedding() index = await self.loop.run_in_executor( @@ -567,6 +644,7 @@ class Index_handler: response_mode, nodes, user_api_key, + child_branch_factor, ): if not user_api_key: os.environ["OPENAI_API_KEY"] = self.openai_key @@ -588,6 +666,7 @@ class Index_handler: nodes, llm_predictor, embedding_model, + child_branch_factor, ), ) print("The last token usage was ", llm_predictor.last_token_usage) diff --git a/models/openai_model.py b/models/openai_model.py index 17befe5..5a0ef9f 100644 --- a/models/openai_model.py +++ b/models/openai_model.py @@ -649,13 +649,6 @@ class Model: codex=False, custom_api_key=None, ): - # Validate that all the parameters are in a good state before we send the request - if len(instruction) < self.prompt_min_length: - raise ValueError( - "Instruction must be greater than 8 characters, it is currently " - + str(len(instruction)) - ) - print( f"The text about to be edited is [{text}] with instructions [{instruction}] codex [{codex}]" ) @@ -831,10 +824,6 @@ class Model: Tuple[dict, bool] ): # The response, and a boolean indicating whether or not the context limit was reached. # Validate that all the parameters are in a good state before we send the request - if len(prompt) < self.prompt_min_length: - raise ValueError( - f"Prompt must be greater than {self.prompt_min_length} characters, it is currently: {len(prompt)} characters" - ) if not max_tokens_override: if model: diff --git a/pyproject.toml b/pyproject.toml index 08156d8..7ecfdb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ dependencies = [ "sentencepiece", "protobuf", "python-pptx", + "langchain", ] dynamic = ["version"] diff --git a/requirements.txt b/requirements.txt index db7b599..c1c3b22 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,4 +17,5 @@ sentencepiece==0.1.97 protobuf==3.20.2 python-pptx==0.6.21 sentence-transformers==2.2.2 -openai-whisper \ No newline at end of file +langchain==0.0.93 +openai-whisper diff --git a/requirements_base.txt b/requirements_base.txt index 9c8092c..ac37df2 100644 --- a/requirements_base.txt +++ b/requirements_base.txt @@ -15,4 +15,5 @@ PyPDF2==3.0.1 youtube_transcript_api==0.5.0 sentencepiece==0.1.97 protobuf==3.20.2 -python-pptx==0.6.21 \ No newline at end of file +python-pptx==0.6.21 +langchain==0.0.93 \ No newline at end of file diff --git a/sample.env b/sample.env index 97a208e..0b21bfa 100644 --- a/sample.env +++ b/sample.env @@ -2,11 +2,11 @@ OPENAI_TOKEN = "" DISCORD_TOKEN = "" -#PINECONE_TOKEN = "" # pinecone token if you have it enabled. See readme -#PINECONE_REGION = "" # add your region here if it's not us-west1-gcp -#GOOGLE_SEARCH_API_KEY: "" -#GOOGLE_SEARCH_ENGINE_ID: "" -#DEEPL_TOKEN: "" +# PINECONE_TOKEN = "" # pinecone token if you have it enabled. See readme +# PINECONE_REGION = "" # add your region here if it's not us-west1-gcp +# GOOGLE_SEARCH_API_KEY: "" +# GOOGLE_SEARCH_ENGINE_ID: "" +# DEEPL_TOKEN: "" DEBUG_GUILD = "974519864045756446" # discord_server_id DEBUG_CHANNEL = "977697652147892304" # discord_chanel_id @@ -29,7 +29,7 @@ SEARCH_ROLES: "Admin,Owner" CUSTOM_BOT_NAME: "GPT3Discord" # If True, users must use their own API keys for OpenAI. If False, the bot will use the API key in the .env file. -USER_INPUT_API_KEYS="False" +USER_INPUT_API_KEYS = "False" # Moderations Service alert channel, this is where moderation alerts will be sent as a default if enabled MODERATIONS_ALERT_CHANNEL = "977697652147892304" @@ -44,4 +44,4 @@ PRE_MODERATE = "False" FORCE_ENGLISH = "False" # The welcome message to send it the welcome setting is set to true -WELCOME_MESSAGE = "Hi There! Welcome to our Discord server. We hope you'll enjoy our server and we look forward to engaging with you!" # This is a fallback message if gpt3 fails to generate a welcome message. \ No newline at end of file +WELCOME_MESSAGE = "Hi There! Welcome to our Discord server. We hope you'll enjoy our server and we look forward to engaging with you!" # This is a fallback message if gpt3 fails to generate a welcome message.