From c8361abe283ed14074ec91eb6dc35587a80d71f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller=20=28ChaoticByte=29?= Date: Mon, 13 Mar 2023 10:44:01 +0100 Subject: [PATCH] Added Bing's Chatbot, extended API and example, updated README --- README.md | 13 +++++++++ chatgpt_pyapi/bing.py | 64 +++++++++++++++++++++++++++++++++++++++++ chatgpt_pyapi/openai.py | 3 ++ example.py | 47 +++++++++++++++++++----------- 4 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 chatgpt_pyapi/bing.py diff --git a/README.md b/README.md index 43b77e0..0ae8d09 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ # ChatGPT-PyAPI A minimalistic Python API for OpenAI's ChatGPT + +## Supported APIs + +- Official ChatGPT API by OpenAI +- Unofficial API for Bing Chatbot (required `EdgeGPT` to be installed) + +### Official ChatGPT API by OpenAI + +You need an API key for the official ChatGPT API. + +### Unofficial API for Bing Chatbot + +This requires your Cookies to be exported to a json file. See [EdgeGPT's README](https://github.com/acheong08/EdgeGPT) for more infos. diff --git a/chatgpt_pyapi/bing.py b/chatgpt_pyapi/bing.py new file mode 100644 index 0000000..bae39ee --- /dev/null +++ b/chatgpt_pyapi/bing.py @@ -0,0 +1,64 @@ +# Copyright (c) 2023 Julian Müller (ChaoticByte) + +import asyncio + +from json import dumps, loads + +from EdgeGPT import Chatbot as _Chatbot +from EdgeGPT import ConversationStyle + + +class _Roles: + ASSISTANT = "assistant" + USER = "user" + +class Message: + '''Message type''' + + def __init__(self, text: str, _role:str=_Roles.USER): + assert type(text) == str + assert type(_role) == str + self.text = text + self.role = _role + + @classmethod + def from_api(cls, api_msg: dict): + '''Create a Message object from API format''' + assert type(api_msg) == dict + return cls( + api_msg["item"]["messages"][1]["adaptiveCards"][0]["body"][0]["text"], + _role=_Roles.ASSISTANT) + + def to_api(self): + '''Convert to API format''' + return self.text + + def __str__(self): + return f"Role: {self.role}, Text: {self.text}" + + +class ChatGPT: + '''ChatGPT API''' + + def __init__(self, cookies_file_path:str, conversation_style=ConversationStyle.precise): + self.bot = _Chatbot(cookiePath=cookies_file_path) + self.conversation_style = conversation_style + self._message_history = [] + self._event_loop = asyncio.get_event_loop() + + def __del__(self): + self._event_loop.run_until_complete( + self.bot.close()) + + def chat(self, message: Message) -> Message: + '''Add a message to the message history & send it to Bings Chatbot. Returns the answer as a Message instance.''' + self._message_history.append(message) + # Ask the bot + api_output = self._event_loop.run_until_complete( + self.bot.ask(message.to_api(), conversation_style=self.conversation_style)) + response_message = Message.from_api(api_output) + self._message_history.append(response_message) + return response_message + + def clear_message_history(self): + self._message_history = [] diff --git a/chatgpt_pyapi/openai.py b/chatgpt_pyapi/openai.py index 566d26f..6bf999c 100644 --- a/chatgpt_pyapi/openai.py +++ b/chatgpt_pyapi/openai.py @@ -40,6 +40,9 @@ class Message: '''Convert to API format''' return {"role": self.role, "content": self.text} + def __str__(self): + return f"Role: {self.role}, Text: {self.text}" + class ChatGPT: '''ChatGPT API''' diff --git a/example.py b/example.py index 1e474b5..7b813e9 100755 --- a/example.py +++ b/example.py @@ -3,26 +3,39 @@ # Copyright (c) 2023 Julian Müller (ChaoticByte) from os import environ +from sys import argv -from chatgpt_pyapi.openai import ChatGPT, Message, Models, Roles - -# Read the API key from a environment variable -API_KEY = environ["OPENAI_API_KEY"] +example_system_message = "Please provide the following answers as cynical as possible, but still correct." +example_questions = [ + "Who are you?", + "Could you please elaborate?" +] if __name__ == "__main__": - # Create ChatGPT API instance - cgpt = ChatGPT(API_KEY, model=Models.GPT_35_TURBO_0301) - # Provide a system message that will influence the answers - system_in = "Please provide the following answers as cynical as possible, but still correct." - # Add the message to the history, but don't send it yet - cgpt.add_to_chat(Message(system_in, role=Roles.SYSTEM)) + bing = False + if len(argv) > 1: + bing = argv[1] == "bing" + if bing: + from chatgpt_pyapi.bing import ChatGPT, Message, ConversationStyle + # Read the path to the cookies file from a environment variable + BING_COOKIES_FILE = environ["BING_COOKIES_FILE"] + # Create ChatGPT API instance (with creative answers) + cgpt = ChatGPT(BING_COOKIES_FILE, ConversationStyle.creative) + cgpt.chat(Message(example_system_message)) + else: + from chatgpt_pyapi.openai import ChatGPT, Message, Models, Roles + # Read the API key from a environment variable + API_KEY = environ["OPENAI_API_KEY"] + # Create ChatGPT API instance + cgpt = ChatGPT(API_KEY, model=Models.GPT_35_TURBO_0301) + # Provide a system message that will influence the answers + sys_msg = Message(example_system_message, role=Roles.SYSTEM) + # Add the message to the history, but don't send it yet + cgpt.add_to_chat(sys_msg) # Have a little chat :D - user_in = "Who are you?" - print(f"USER: {user_in}") - print(cgpt.chat(Message(user_in)).text) - user_in = "Could you please elaborate?" - print(f"\nUSER: {user_in}") - print(cgpt.chat(Message(user_in)).text) + for q in example_questions: + print(f"\nUSER: {q}") + print(cgpt.chat(Message(q)).text) # Print out message history print("\nMessage History:") - [print(m.to_api()) for m in cgpt._message_history] + [print(str(m)) for m in cgpt._message_history]