From 6c404c38035bfcf27d6090341b59498ec18f07eb Mon Sep 17 00:00:00 2001 From: Paillat Date: Sun, 16 Jul 2023 17:11:24 +0200 Subject: [PATCH] FIxed stuff --- src/functionscalls.py | 79 ++++++++++++++++++++++++++++++++++- src/makeprompt.py | 67 +++++++++++++++++++---------- src/prompts/gpt-3.5-turbo.txt | 3 ++ src/utils/openaicaller.py | 71 ++++++++++++++++++++++--------- 4 files changed, 179 insertions(+), 41 deletions(-) diff --git a/src/functionscalls.py b/src/functionscalls.py index 2993204..8e669f7 100644 --- a/src/functionscalls.py +++ b/src/functionscalls.py @@ -1,5 +1,78 @@ import discord +functions = [ + { + "name": "add_reaction_to_last_message", + "description": "React to the last message sent by the user with an emoji.", + "parameters": { + "type": "object", + "properties": { + "emoji": { + "type": "string", + "description": "an emoji to react with, only one emoji is supported" + }, + "message": { + "type": "string", + "description": "Your message" + } + }, + "required": ["emoji"] + } + }, + { + "name": "reply_to_last_message", + "description": "Reply to the last message sent by the user.", + "parameters": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Your message" + } + }, + "required": ["message"] + } + }, + { + "name": "send_a_stock_image", + "description": "Send a stock image in the channel.", + "parameters": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "The query to search for, words separated by spaces" + }, + "message": { + "type": "string", + "description": "Your message to send with the image" + } + }, + "required": ["query"] + } + } +] + +server_normal_channel_functions = [ + { + "name": "create_a_thread", + "description": "Create a thread in the channel. Use this if you see a long discussion coming.", + "parameters": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the thread" + }, + "message": { + "type": "string", + "description": "Your message to send with the thread" + } + }, + "required": ["name", "message"] + } + }, +] unsplash_random_image_url = "https://source.unsplash.com/random/1920x1080" async def add_reaction_to_last_message(message_to_react_to: discord.Message, emoji, message=""): if message == "": @@ -17,4 +90,8 @@ async def send_a_stock_image(message_in_channel_in_wich_to_send: discord.Message await message_in_channel_in_wich_to_send.channel.send(f"https://source.unsplash.com/random/1920x1080?{query}") else: await message_in_channel_in_wich_to_send.channel.send(message) - await message_in_channel_in_wich_to_send.channel.send(f"https://source.unsplash.com/random/1920x1080?{query}") \ No newline at end of file + await message_in_channel_in_wich_to_send.channel.send(f"https://source.unsplash.com/random/1920x1080?{query}") + +async def create_a_thread(channel_in_which_to_create_the_thread: discord.TextChannel, name: str, message: str): + msg = await channel_in_which_to_create_the_thread.send(message) + await msg.create_thread(name=name) \ No newline at end of file diff --git a/src/makeprompt.py b/src/makeprompt.py index 3d9541d..71bfcf0 100644 --- a/src/makeprompt.py +++ b/src/makeprompt.py @@ -1,11 +1,12 @@ import asyncio import os -from src.config import curs_data, max_uses, curs_premium, functions, moderate +from src.config import curs_data, max_uses, curs_premium, moderate import re import discord import datetime +import json from src.utils.openaicaller import openai_caller -from src.functionscalls import add_reaction_to_last_message, reply_to_last_message, send_a_stock_image +from src.functionscalls import add_reaction_to_last_message, reply_to_last_message, send_a_stock_image, create_a_thread, functions, server_normal_channel_functions async def replace_mentions(content, bot): mentions = re.findall(r"<@!?\d+>", content) for mention in mentions: @@ -52,36 +53,57 @@ async def chatgpt_process(self, messages, message: discord.Message, api_key, pro response = str() caller = openai_caller(api_key=api_key) + async def error_call(error=""): + try: + if error != "": + await message.channel.send(f"An error occured: {error}", delete_after=10) + await message.channel.trigger_typing() + except: + pass + funcs = functions + if isinstance(message.channel, discord.TextChannel): + for func in server_normal_channel_functions: + funcs.append(func) response = await caller.generate_response( + error_call, model=model, messages=msgs, functions=functions, - function_call="auto", + #function_call="auto", ) response = response["choices"][0]["message"] #type: ignore if response.get("function_call"): - function_calls = response.get("function_call") - if function_calls.get("add_reaction_to_last_message"): - func = function_calls.get("add_reaction_to_last_message") - if func.get("emoji"): - emoji = func.get("emoji") - reply = func.get("message", "") + function_call = response.get("function_call") + name = function_call.get("name", "") + arguments = function_call.get("arguments", {}) + arguments = json.loads(arguments) + if name == "add_reaction_to_last_message": + if arguments.get("emoji"): + emoji = arguments.get("emoji") + reply = arguments.get("message", "") await add_reaction_to_last_message(message, emoji, reply) - if function_calls.get("reply_to_last_message"): - func = function_calls.get("reply_to_last_message") - if func.get("message"): - reply = func.get("message") + if name == "reply_to_last_message": + if arguments.get("message"): + reply = arguments.get("message") await reply_to_last_message(message, reply) - if function_calls.get("send_a_stock_image"): - func = function_calls.get("send_a_stock_image") - if func.get("query"): - query = func.get("query") - reply = func.get("message", "") + if name == "send_a_stock_image": + if arguments.get("query"): + query = arguments.get("query") + reply = arguments.get("message", "") await send_a_stock_image(message, query, reply) + if name == "create_a_thread": + if arguments.get("name") and arguments.get("message"): + name = arguments.get("name") + reply = arguments.get("message", "") + if isinstance(message.channel, discord.TextChannel): + await create_a_thread(message.channel, name, reply) + else: + await message.channel.send("`A server normal text channel only function has been called in a DM channel. Please retry.`", delete_after=10) + if name == "": + await message.channel.send("The function call is empty. Please retry.", delete_after=10) else: await message.channel.send(response["content"]) #type: ignore - print(response["content"]) #type: ignore async def chat_process(self, message): #if the message is from a bot, we ignore it @@ -136,8 +158,11 @@ async def chat_process(self, message): if original_message != None and original_message.author.id != self.bot.user.id: original_message = None - - if not str(message.channel.id) in channels and message.content.find("<@"+str(self.bot.user.id)+">") == -1 and original_message == None and str(message.channel.id) != str(channel_id): + is_bots_thread = False + if isinstance(message.channel, discord.Thread): + if message.channel.owner_id == self.bot.user.id: + is_bots_thread = True + if not str(message.channel.id) in channels and message.content.find("<@"+str(self.bot.user.id)+">") == -1 and original_message == None and str(message.channel.id) != str(channel_id) and not is_bots_thread: return # if the bot is not active in this guild we return diff --git a/src/prompts/gpt-3.5-turbo.txt b/src/prompts/gpt-3.5-turbo.txt index 25e1d04..7939f77 100644 --- a/src/prompts/gpt-3.5-turbo.txt +++ b/src/prompts/gpt-3.5-turbo.txt @@ -4,6 +4,9 @@ You are in a discord server. You are now called Botator. You arre funny and you You use words like "u" instead of "you" and "ur" instead of "your", etc.. because you are lazy. +You never ask the user if he needs help, you just answer to him funnyily. + +You can use function calls or answer normally. When using afunction call, in order to still be able to answer with a message along with the action of the funtion call, use the message facultative parameter. You will use emojis in your messages, but not too many to be cringe. Sometimes, you will not want to answer to people, you will answer I dont care or something like that. diff --git a/src/utils/openaicaller.py b/src/utils/openaicaller.py index fa9eb37..f204213 100644 --- a/src/utils/openaicaller.py +++ b/src/utils/openaicaller.py @@ -37,13 +37,14 @@ class bcolors: BOLD = '\033[1m' UNDERLINE = '\033[4m' -chat_models = ["gpt-4", "gpt-4-32k", "gpt-3.5-turbo", "gpt-3.5-turbo-16k"] +chat_models = ["gpt-4", "gpt-4-32k", "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0613"] text_models = ["text-davinci-003", "text-davinci-002", "text-curie-001", "text-babbage-001", "text-ada-001"] models_max_tokens = { "gpt-4": 8_192, "gpt-4-32k": 32_768, "gpt-3.5-turbo": 4_096, + "gpt-3.5-turbo-0613": 4_096, "gpt-3.5-turbo-16k": 16_384, "text-davinci-003": 4_097, "text-davinci-002": 4_097, @@ -54,17 +55,17 @@ models_max_tokens = { class openai_caller: def __init__(self, api_key=None) -> None: - pass - def set_api_key(self, key): - openai_module.api_key = key - async def generate_response(self, **kwargs): - if kwargs['model'] in chat_models: - return await self.chat_generate(**kwargs) - elif kwargs['model'] in text_models: + self.api_key = api_key + async def generate_response(self, error_call=None, **kwargs): + if error_call is None: + error_call = lambda x: 2 # do nothing + if kwargs.get("model", "") in chat_models: + return await self.chat_generate(error_call, **kwargs) + elif kwargs.get("engine", "") in text_models: raise NotImplementedError("Text models are not supported yet") else: raise ValueError("Model not found") - async def chat_generate(self, **kwargs): + async def chat_generate(self, recall_func, **kwargs): tokens = await num_tokens_from_messages(kwargs['messages'], kwargs['model']) model_max_tokens = models_max_tokens[kwargs['model']] while tokens > model_max_tokens: @@ -73,36 +74,68 @@ class openai_caller: tokens = await num_tokens_from_messages(kwargs['messages'], kwargs['model']) i = 0 response = None + kwargs['api_key'] = self.api_key while i < 10: try: - response = await openai_module.ChatCompletion.acreate(**kwargs) + response = await openai_module.ChatCompletion.acreate( + **kwargs + ) break - except APIError: + except APIError as e: + print(f"\n\n{bcolors.BOLD}{bcolors.WARNING}APIError. This is not your fault. Retrying...{bcolors.ENDC}") + await recall_func("`An APIError occurred. This is not your fault. Retrying...`") await asyncio.sleep(10) + await recall_func() i += 1 - except Timeout: + except Timeout as e: + print(f"\n\n{bcolors.BOLD}{bcolors.WARNING}The request timed out. Retrying...{bcolors.ENDC}") + await recall_func("`The request timed out. Retrying...`") await asyncio.sleep(10) + await recall_func() i += 1 - except RateLimitError: + except RateLimitError as e: + print(f"\n\n{bcolors.BOLD}{bcolors.WARNING}RateLimitError. You are being rate limited. Retrying...{bcolors.ENDC}") + await recall_func("`You are being rate limited. Retrying...`") await asyncio.sleep(10) + await recall_func() i += 1 except APIConnectionError as e: - print(e) print(f"\n\n{bcolors.BOLD}{bcolors.FAIL}APIConnectionError. There is an issue with your internet connection. Please check your connection.{bcolors.ENDC}") + await recall_func() raise e except InvalidRequestError as e: - print(e) print(f"\n\n{bcolors.BOLD}{bcolors.FAIL}InvalidRequestError. Please check your request.{bcolors.ENDC}") + await recall_func() raise e except AuthenticationError as e: - print(e) - print(f"\n\n{bcolors.BOLD}{bcolors.FAIL}AuthenticationError. Please check your API key.{bcolors.ENDC}") + print(f"\n\n{bcolors.BOLD}{bcolors.FAIL}AuthenticationError. Please check your API key and if needed, also your organization ID.{bcolors.ENDC}") + await recall_func("`AuthenticationError. Please check your API key.`") raise e - except ServiceUnavailableError: + except ServiceUnavailableError as e: + print(f"\n\n{bcolors.BOLD}{bcolors.WARNING}ServiceUnavailableError. The OpenAI API is not responding. Retrying...{bcolors.ENDC}") + await recall_func("`The OpenAI API is not responding. Retrying...`") await asyncio.sleep(10) + await recall_func() i += 1 finally: if i == 10: print(f"\n\n{bcolors.BOLD}{bcolors.FAIL}OpenAI API is not responding. Please try again later.{bcolors.ENDC}") raise TimeoutError("OpenAI API is not responding. Please try again later.") - return response # type: ignore \ No newline at end of file + return response # type: ignore + +##testing +if __name__ == "__main__": + async def main(): + openai = openai_caller(api_key="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") + response = await openai.generate_response( + model="gpt-3.5-turbo", + messages=[{"role":"user", "content":"ping"}], + max_tokens=5, + temperature=0.7, + top_p=1, + frequency_penalty=0, + presence_penalty=0, + stop=["\n", " Human:", " AI:"] + ) + print(response) + asyncio.run(main()) \ No newline at end of file