From 1e892bfb0519e6070c45d6f5b8338cc9f268c899 Mon Sep 17 00:00:00 2001 From: Tom Viner Date: Mon, 3 Apr 2023 00:07:18 +0100 Subject: [PATCH 01/16] don't depend on the path script is run from --- scripts/data.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/data.py b/scripts/data.py index 19473557..62a36e12 100644 --- a/scripts/data.py +++ b/scripts/data.py @@ -1,7 +1,12 @@ +from pathlib import Path + +FOLDER = Path(__file__).parent + + def load_prompt(): try: # Load the promt from data/prompt.txt - with open("data/prompt.txt", "r") as prompt_file: + with open(FOLDER / "data/prompt.txt", "r") as prompt_file: prompt = prompt_file.read() return prompt From 962a5bb76c1592f07a13248007c8ef5c775f404d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CPhilip?= Date: Mon, 3 Apr 2023 19:44:12 +0100 Subject: [PATCH 02/16] =?UTF-8?q?Fix=20Issue=20with=20command=20hallucinat?= =?UTF-8?q?ion=20=F0=9F=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes an issue where it hallucinates on "COMMANDS" 💭 --- scripts/data/prompt.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/data/prompt.txt b/scripts/data/prompt.txt index d17fa27a..bffbcc14 100644 --- a/scripts/data/prompt.txt +++ b/scripts/data/prompt.txt @@ -2,6 +2,7 @@ CONSTRAINTS: 1. ~4000 word limit for memory. Your memory is short, so immidiately save important information to long term memory and code to files. 2. No user assistance +3. Exclusively use the commands listed in double quotes e.g. "command name" COMMANDS: From 6306a033cc95090a5f02203451ed6dd38c416c36 Mon Sep 17 00:00:00 2001 From: Rafael Moraes Date: Mon, 3 Apr 2023 15:11:15 -0400 Subject: [PATCH 03/16] Fixed googlesearch dependency issue Swapped the googlesearch package for the duckduckgo-search. It uses the ddg instant answer API and works very similarly to the googlesearch one. --- requirements-alternative.txt | 14 -------------- requirements.txt | 2 +- scripts/commands.py | 4 ++-- 3 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 requirements-alternative.txt diff --git a/requirements-alternative.txt b/requirements-alternative.txt deleted file mode 100644 index a2f2723d..00000000 --- a/requirements-alternative.txt +++ /dev/null @@ -1,14 +0,0 @@ -# I wasn't having any luck installing the requirements.txt file in Mac or Linux -# But this seems to work. -# The biggest difference is docker 5 instead of 6, because of this silliness: -# -# The conflict is caused by: -# The user requested requests>=2.26.0 -# docker 6.0.1 depends on requests>=2.26.0 -# googlesearch-python 1.1.0 depends on requests==2.25.1 -docker==5.0.3 - -# I'd love to fix this in a cleaner way - -# Now go ahead and install the rest of what requirements.txt says: --r requirements.txt diff --git a/requirements.txt b/requirements.txt index 5f51bdf5..0fcdfb45 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,5 +8,5 @@ readability-lxml==0.8.1 requests tiktoken==0.3.3 docker -googlesearch-python +duckduckgo-search # Googlesearch python seems to be a bit cursed, anyone good at fixing thigns like this? \ No newline at end of file diff --git a/scripts/commands.py b/scripts/commands.py index 2e332711..2d98a2b2 100644 --- a/scripts/commands.py +++ b/scripts/commands.py @@ -9,7 +9,7 @@ import ai_functions as ai from file_operations import read_file, write_to_file, append_to_file, delete_file from execute_code import execute_python_file from json_parser import fix_and_parse_json -from googlesearch import search +from duckduckgo_search import ddg cfg = Config() @@ -103,7 +103,7 @@ def get_datetime(): def google_search(query, num_results=8): search_results = [] - for j in search(query, num_results=num_results): + for j in ddg(query, max_results=num_results): search_results.append(j) return json.dumps(search_results, ensure_ascii=False, indent=4) From 79f0882dfcf50bc5ab9ca29e2ed3eb628650facc Mon Sep 17 00:00:00 2001 From: kminer Date: Mon, 3 Apr 2023 15:35:01 -0600 Subject: [PATCH 04/16] fix: OpenAPI key variable name typo --- scripts/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config.py b/scripts/config.py index 44d99bff..8a9ba00c 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -59,7 +59,7 @@ class Config(metaclass=Singleton): self.smart_token_limit = value def set_openai_api_key(self, value: str): - self.apiopenai_api_key_key = value + self.openai_api_key = value def set_elevenlabs_api_key(self, value: str): self.elevenlabs_api_key = value From 8a08b0c01b5be1b70e58a1d6817d4f85c54465ef Mon Sep 17 00:00:00 2001 From: Preston Jensen Date: Mon, 3 Apr 2023 19:20:42 -0600 Subject: [PATCH 05/16] ask questions on websites --- scripts/browse.py | 53 +++++++++++++---------------------------- scripts/commands.py | 12 +++++----- scripts/data/prompt.txt | 2 +- 3 files changed, 24 insertions(+), 43 deletions(-) diff --git a/scripts/browse.py b/scripts/browse.py index f096c5f3..510f9c29 100644 --- a/scripts/browse.py +++ b/scripts/browse.py @@ -74,30 +74,25 @@ def split_text(text, max_length=8192): yield "\n".join(current_chunk) -def summarize_text(text, is_website=True): - if text == "": +def create_message(chunk, question): + return { + "role": "user", + "content": f"\"\"\"{chunk}\"\"\" Using the above text, please answer the following question: \"{question}\" -- if the question cannot be answered using the text, please summarize the text." + } + +def summarize_text(text, question): + if not text: return "Error: No text to summarize" - print("Text length: " + str(len(text)) + " characters") + text_length = len(text) + print(f"Text length: {text_length} characters") + summaries = [] chunks = list(split_text(text)) for i, chunk in enumerate(chunks): - print("Summarizing chunk " + str(i + 1) + " / " + str(len(chunks))) - if is_website: - messages = [ - { - "role": "user", - "content": "Please summarize the following website text, do not describe the general website, but instead concisely extract the specific information this subpage contains.: " + - chunk}, - ] - else: - messages = [ - { - "role": "user", - "content": "Please summarize the following text, focusing on extracting concise and specific information: " + - chunk}, - ] + print(f"Summarizing chunk {i + 1} / {len(chunks)}") + messages = [create_message(chunk, question)] summary = create_chat_completion( model=cfg.fast_llm_model, @@ -105,25 +100,11 @@ def summarize_text(text, is_website=True): max_tokens=300, ) summaries.append(summary) - print("Summarized " + str(len(chunks)) + " chunks.") + + print(f"Summarized {len(chunks)} chunks.") combined_summary = "\n".join(summaries) - - # Summarize the combined summary - if is_website: - messages = [ - { - "role": "user", - "content": "Please summarize the following website text, do not describe the general website, but instead concisely extract the specific information this subpage contains.: " + - combined_summary}, - ] - else: - messages = [ - { - "role": "user", - "content": "Please summarize the following text, focusing on extracting concise and specific infomation: " + - combined_summary}, - ] + messages = [create_message(combined_summary, question)] final_summary = create_chat_completion( model=cfg.fast_llm_model, @@ -131,4 +112,4 @@ def summarize_text(text, is_website=True): max_tokens=300, ) - return final_summary + return final_summary \ No newline at end of file diff --git a/scripts/commands.py b/scripts/commands.py index 8ad95336..ed789c8e 100644 --- a/scripts/commands.py +++ b/scripts/commands.py @@ -72,7 +72,7 @@ def execute_command(command_name, arguments): elif command_name == "delete_agent": return delete_agent(arguments["key"]) elif command_name == "get_text_summary": - return get_text_summary(arguments["url"]) + return get_text_summary(arguments["url"], arguments["question"]) elif command_name == "get_hyperlinks": return get_hyperlinks(arguments["url"]) elif command_name == "read_file": @@ -84,7 +84,7 @@ def execute_command(command_name, arguments): elif command_name == "delete_file": return delete_file(arguments["file"]) elif command_name == "browse_website": - return browse_website(arguments["url"]) + return browse_website(arguments["url"], arguments["question"]) # TODO: Change these to take in a file rather than pasted code, if # non-file is given, return instructions "Input should be a python # filepath, write your code to file and try again" @@ -152,8 +152,8 @@ def google_official_search(query, num_results=8): # Return the list of search result URLs return search_results_links -def browse_website(url): - summary = get_text_summary(url) +def browse_website(url, question): + summary = get_text_summary(url, question) links = get_hyperlinks(url) # Limit links to 5 @@ -165,9 +165,9 @@ def browse_website(url): return result -def get_text_summary(url): +def get_text_summary(url, question): text = browse.scrape_text(url) - summary = browse.summarize_text(text) + summary = browse.summarize_text(text, question) return """ "Result" : """ + summary diff --git a/scripts/data/prompt.txt b/scripts/data/prompt.txt index d17fa27a..1596c810 100644 --- a/scripts/data/prompt.txt +++ b/scripts/data/prompt.txt @@ -9,7 +9,7 @@ COMMANDS: 2. Memory Add: "memory_add", args: "string": "" 3. Memory Delete: "memory_del", args: "key": "" 4. Memory Overwrite: "memory_ovr", args: "key": "", "string": "" -5. Browse Website: "browse_website", args: "url": "" +5. Browse Website: "browse_website", args: "url": "", "question": "" 6. Start GPT Agent: "start_agent", args: "name": , "task": "", "prompt": "" 7. Message GPT Agent: "message_agent", args: "key": "", "message": "" 8. List GPT Agents: "list_agents", args: "" From 2af9cf853aac6b91a7fac26dfccc28d1c6bfa4cb Mon Sep 17 00:00:00 2001 From: Preston Jensen Date: Mon, 3 Apr 2023 20:12:11 -0600 Subject: [PATCH 06/16] human feedback in manual mode --- scripts/main.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 97c05d7d..03f656b0 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -303,7 +303,7 @@ while True: Fore.CYAN, f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}") print( - "Enter 'y' to authorise command or 'n' to exit program...", + f"Enter 'y' to authorise command or 'n' to exit program, or enter feedback for {ai_name}...", flush=True) while True: console_input = input(Fore.MAGENTA + "Input:" + Style.RESET_ALL) @@ -314,16 +314,18 @@ while True: user_input = "EXIT" break else: - continue + user_input = console_input + command_name = "human_feedback" + break - if user_input != "GENERATE NEXT COMMAND JSON": - print("Exiting...", flush=True) - break - - print_to_console( + if user_input == "GENERATE NEXT COMMAND JSON": + print_to_console( "-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-=", Fore.MAGENTA, "") + elif user_input == "EXIT": + print("Exiting...", flush=True) + break else: # Print command print_to_console( @@ -332,10 +334,12 @@ while True: f"COMMAND = {Fore.CYAN}{command_name}{Style.RESET_ALL} ARGUMENTS = {Fore.CYAN}{arguments}{Style.RESET_ALL}") # Execute command - if command_name.lower() != "error": - result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}" - else: + if command_name.lower() == "error": result = f"Command {command_name} threw the following error: " + arguments + elif command_name == "human_feedback": + result = f"Human feedback: {user_input}" + else: + result = f"Command {command_name} returned: {cmd.execute_command(command_name, arguments)}" # Check if there's a result from the command append it to the message # history @@ -347,3 +351,4 @@ while True: chat.create_chat_message( "system", "Unable to execute command")) print_to_console("SYSTEM: ", Fore.YELLOW, "Unable to execute command") + From 82da7f1681a1c2cb5dad310e396589b8a3d3ce71 Mon Sep 17 00:00:00 2001 From: yousefissa Date: Mon, 3 Apr 2023 22:19:32 -0700 Subject: [PATCH 07/16] fix assistant thoughts failure on string type --- scripts/main.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 97c05d7d..a1c08018 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -52,6 +52,14 @@ def print_assistant_thoughts(assistant_reply): # Parse and print Assistant response assistant_reply_json = fix_and_parse_json(assistant_reply) + # Check if assistant_reply_json is a string and attempt to parse it into a JSON object + if isinstance(assistant_reply_json, str): + try: + assistant_reply_json = json.loads(assistant_reply_json) + except json.JSONDecodeError as e: + print_to_console("Error: Invalid JSON\n", Fore.RED, assistant_reply) + assistant_reply_json = {} + assistant_thoughts_reasoning = None assistant_thoughts_plan = None assistant_thoughts_speak = None @@ -90,10 +98,6 @@ def print_assistant_thoughts(assistant_reply): except json.decoder.JSONDecodeError: print_to_console("Error: Invalid JSON\n", Fore.RED, assistant_reply) - # All other errors, return "Error: + error message" - except Exception as e: - call_stack = traceback.format_exc() - print_to_console("Error: \n", Fore.RED, call_stack) def load_variables(config_file="config.yaml"): From 570c161e5e78a7edee74aacfc1164efa26680d1d Mon Sep 17 00:00:00 2001 From: yousefissa Date: Mon, 3 Apr 2023 22:21:42 -0700 Subject: [PATCH 08/16] add final exception handling back --- scripts/main.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/main.py b/scripts/main.py index a1c08018..86afec39 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -98,6 +98,10 @@ def print_assistant_thoughts(assistant_reply): except json.decoder.JSONDecodeError: print_to_console("Error: Invalid JSON\n", Fore.RED, assistant_reply) + # All other errors, return "Error: + error message" + except Exception as e: + call_stack = traceback.format_exc() + print_to_console("Error: \n", Fore.RED, call_stack) def load_variables(config_file="config.yaml"): From 68e4af8685dac029fc86ab9c43dcd451c1d96758 Mon Sep 17 00:00:00 2001 From: Master Blood Date: Mon, 3 Apr 2023 22:38:01 -0700 Subject: [PATCH 09/16] Added a default (free) library for text to speech Adds the gTTS (Google Text-to-Speech) Python library as a fallback for text-to-speech conversion in the speak.py file. The changes were made to ensure that users can still convert text to speech even if the ElevenLabs API key is not set or if the API encounters an error. Additionally, the requirements.txt file has been updated to include the new gTTS dependency. --- requirements.txt | 1 + scripts/speak.py | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 063931a9..7961106b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ pyyaml==6.0 readability-lxml==0.8.1 requests tiktoken==0.3.3 +gTTS==2.3.1 docker googlesearch-python google-api-python-client #(https://developers.google.com/custom-search/v1/overview) diff --git a/scripts/speak.py b/scripts/speak.py index 2fbcbed2..6fef41f8 100644 --- a/scripts/speak.py +++ b/scripts/speak.py @@ -3,6 +3,8 @@ from playsound import playsound import requests from config import Config cfg = Config() +import gtts + # TODO: Nicer names for these ids voices = ["ErXwobaYiN019PkySvjV", "EXAVITQu4vr4xnSDxMaL"] @@ -12,10 +14,9 @@ tts_headers = { "xi-api-key": cfg.elevenlabs_api_key } -def say_text(text, voice_index=0): +def eleven_labs_speech(text, voice_index=0): tts_url = "https://api.elevenlabs.io/v1/text-to-speech/{voice_id}".format( voice_id=voices[voice_index]) - formatted_message = {"text": text} response = requests.post( tts_url, headers=tts_headers, json=formatted_message) @@ -24,8 +25,24 @@ def say_text(text, voice_index=0): with open("speech.mpeg", "wb") as f: f.write(response.content) playsound("speech.mpeg") - # Delete audio file os.remove("speech.mpeg") + return True else: print("Request failed with status code:", response.status_code) print("Response content:", response.content) + return False + +def gtts_speech(text): + tts = gtts.gTTS(text) + tts.save("speech.mp3") + playsound("speech.mp3") + os.remove("speech.mp3") + +def say_text(text, voice_index=0): + if not cfg.elevenlabs_api_key: + gtts_speech(text) + else: + success = eleven_labs_speech() + if not success: + gtts_speech(text) + From 4650882d971a8edd2ac3ae29eef9bbdb210baeeb Mon Sep 17 00:00:00 2001 From: Zhaofeng Miao <522856232@qq.com> Date: Tue, 4 Apr 2023 16:37:23 +0800 Subject: [PATCH 10/16] fix(prompt): fix typos --- scripts/data/prompt.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/data/prompt.txt b/scripts/data/prompt.txt index d17fa27a..2cb73a8d 100644 --- a/scripts/data/prompt.txt +++ b/scripts/data/prompt.txt @@ -1,6 +1,6 @@ CONSTRAINTS: -1. ~4000 word limit for memory. Your memory is short, so immidiately save important information to long term memory and code to files. +1. ~4000 word limit for memory. Your memory is short, so immediately save important information to long term memory and code to files. 2. No user assistance COMMANDS: @@ -34,9 +34,9 @@ RESOURCES: PERFORMANCE EVALUATION: 1. Continuously review and analyze your actions to ensure you are performing to the best of your abilities. -2. Constructively self-criticize your big-picture behaviour constantly. +2. Constructively self-criticize your big-picture behavior constantly. 3. Reflect on past decisions and strategies to refine your approach. -4. Every command has a cost, so be smart and efficent. Aim to complete tasks in the least number of steps. +4. Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps. You should only respond in JSON format as described below @@ -58,4 +58,4 @@ RESPONSE FORMAT: } } -Ensure the response can be parsed by Python json.loads \ No newline at end of file +Ensure the response can be parsed by Python json.loads From 4c66cd6f4a4e81aee56a87a1331ba7f92b70857c Mon Sep 17 00:00:00 2001 From: Toran Bruce Richards Date: Tue, 4 Apr 2023 10:00:40 +0100 Subject: [PATCH 11/16] Renames FOLDER to SRC_DIR --- scripts/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/data.py b/scripts/data.py index 62a36e12..f4d6eb0e 100644 --- a/scripts/data.py +++ b/scripts/data.py @@ -1,6 +1,6 @@ from pathlib import Path -FOLDER = Path(__file__).parent +SRC_DIR = Path(__file__).parent def load_prompt(): From 6d86444b6f67d853e6ce31015c0d179169896ade Mon Sep 17 00:00:00 2001 From: Toran Bruce Richards Date: Tue, 4 Apr 2023 10:00:53 +0100 Subject: [PATCH 12/16] Renames FOLDER to SRC_DIR --- scripts/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/data.py b/scripts/data.py index f4d6eb0e..bb4b296e 100644 --- a/scripts/data.py +++ b/scripts/data.py @@ -6,7 +6,7 @@ SRC_DIR = Path(__file__).parent def load_prompt(): try: # Load the promt from data/prompt.txt - with open(FOLDER / "data/prompt.txt", "r") as prompt_file: + with open(SRC_DIR/ "data/prompt.txt", "r") as prompt_file: prompt = prompt_file.read() return prompt From 8b3c2fee2e7530fb77f5493fffa6cc9c4918508d Mon Sep 17 00:00:00 2001 From: Toran Bruce Richards Date: Tue, 4 Apr 2023 10:03:30 +0100 Subject: [PATCH 13/16] Update scripts/data.py --- scripts/data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/data.py b/scripts/data.py index 7969d69c..a6ffdadf 100644 --- a/scripts/data.py +++ b/scripts/data.py @@ -11,7 +11,6 @@ def load_prompt(): # Load the promt from data/prompt.txt with open(SRC_DIR/ "data/prompt.txt", "r") as prompt_file: - prompt = prompt_file.read() return prompt From 4d4ff658abceeb5b38a2fe8dc43ce2749d82cf4a Mon Sep 17 00:00:00 2001 From: Toran Bruce Richards Date: Tue, 4 Apr 2023 10:04:02 +0100 Subject: [PATCH 14/16] Update scripts/data.py --- scripts/data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/data.py b/scripts/data.py index a6ffdadf..72a6bbfc 100644 --- a/scripts/data.py +++ b/scripts/data.py @@ -9,7 +9,6 @@ def load_prompt(): data_dir = file_dir / "data" prompt_file = data_dir / "prompt.txt" # Load the promt from data/prompt.txt - with open(SRC_DIR/ "data/prompt.txt", "r") as prompt_file: prompt = prompt_file.read() From ae60025f7c2d339e7a1463546b06fd448df26016 Mon Sep 17 00:00:00 2001 From: Toran Bruce Richards Date: Tue, 4 Apr 2023 12:20:59 +0100 Subject: [PATCH 15/16] =?UTF-8?q?Updates=20Sponsors=20List=20=F0=9F=92=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5848c585..d66a6022 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,11 @@ Your support is greatly appreciated Development of this free, open-source project is made possible by all the contributors and sponsors. If you'd like to sponsor this project and have your avatar or company logo appear below click here. 💖

-nocodeclarity  tjarmain  tekelsey  robinicus  digisomni   +thepok  SpacingLily  m  zkonduit  maxxflyer  tekelsey  nocodeclarity  tjarmain  alexisneuhaus  jaumebalust  robinicus  digisomni  

+

-alexisneuhaus  iokode  jaumebalust   +alexisneuhaus  iokode  jaumebalust  nova-land  robinicus  Void-n-Null  ritesh24  merwanehamadi  raulmarindev  siduppal  goosecubedaddy  pleabargain  

From e1d3cc94921efab79db2608e3ff62aae39493228 Mon Sep 17 00:00:00 2001 From: Toran Bruce Richards Date: Tue, 4 Apr 2023 13:09:33 +0100 Subject: [PATCH 16/16] Fixes: TypeError: eleven_labs_speech() missing 1 required positional argument: 'text' --- scripts/speak.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/speak.py b/scripts/speak.py index 6fef41f8..f6242a37 100644 --- a/scripts/speak.py +++ b/scripts/speak.py @@ -42,7 +42,7 @@ def say_text(text, voice_index=0): if not cfg.elevenlabs_api_key: gtts_speech(text) else: - success = eleven_labs_speech() + success = eleven_labs_speech(text) if not success: gtts_speech(text)