From 1e892bfb0519e6070c45d6f5b8338cc9f268c899 Mon Sep 17 00:00:00 2001 From: Tom Viner Date: Mon, 3 Apr 2023 00:07:18 +0100 Subject: [PATCH 01/24] 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 194735578ed0..62a36e125051 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 4416aa1aa1c0dba9e37bf6a2694e28aa6bbedf88 Mon Sep 17 00:00:00 2001 From: yousefissa Date: Mon, 3 Apr 2023 08:48:43 -0700 Subject: [PATCH 02/24] create file dir if it doesnt exist during write_to_file --- scripts/file_operations.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/file_operations.py b/scripts/file_operations.py index 62b3dc4b7dfe..d7c7a1b082b6 100644 --- a/scripts/file_operations.py +++ b/scripts/file_operations.py @@ -29,13 +29,14 @@ def read_file(filename): def write_to_file(filename, text): - try: - filepath = safe_join(working_directory, filename) - with open(filepath, "w") as f: - f.write(text) - return "File written to successfully." - except Exception as e: - return "Error: " + str(e) + filepath = safe_join(working_directory, filename) + directory = os.path.dirname(filepath) + if not os.path.exists(directory): + os.makedirs(directory) + with open(filepath, "w") as f: + f.write(text) + return "File written to successfully." + def append_to_file(filename, text): From 9ef4fab084633e4289226a6dd059a598085ec876 Mon Sep 17 00:00:00 2001 From: yousefissa Date: Mon, 3 Apr 2023 08:50:07 -0700 Subject: [PATCH 03/24] error handling back --- scripts/file_operations.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/file_operations.py b/scripts/file_operations.py index d7c7a1b082b6..81ad471577b5 100644 --- a/scripts/file_operations.py +++ b/scripts/file_operations.py @@ -29,14 +29,16 @@ def read_file(filename): def write_to_file(filename, text): - filepath = safe_join(working_directory, filename) - directory = os.path.dirname(filepath) - if not os.path.exists(directory): - os.makedirs(directory) - with open(filepath, "w") as f: - f.write(text) - return "File written to successfully." - + try: + filepath = safe_join(working_directory, filename) + directory = os.path.dirname(filepath) + if not os.path.exists(directory): + os.makedirs(directory) + with open(filepath, "w") as f: + f.write(text) + return "File written to successfully." + except Exception as e: + return "Error: " + str(e) def append_to_file(filename, text): 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 04/24] =?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 d17fa27a1c7f..bffbcc14fff3 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 8a5c9800e7a2e782bf2b472741a3b272bf42b7d3 Mon Sep 17 00:00:00 2001 From: yousefissa Date: Mon, 3 Apr 2023 13:00:50 -0700 Subject: [PATCH 05/24] fix assistant plan variables being referenced before assignment --- scripts/main.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 4e7997436989..2304baf4540a 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -52,6 +52,10 @@ def print_assistant_thoughts(assistant_reply): # Parse and print Assistant response assistant_reply_json = fix_and_parse_json(assistant_reply) + assistant_thoughts_reasoning = None + assistant_thoughts_plan = None + assistant_thoughts_speak = None + assistant_thoughts_criticism = None try: assistant_thoughts = assistant_reply_json.get("thoughts") if assistant_thoughts: @@ -66,7 +70,7 @@ def print_assistant_thoughts(assistant_reply): assistant_thoughts_plan = None assistant_thoughts_criticism = None assistant_thoughts_speak = None - except Exception as e: + except Exception: assistant_thoughts_text = "The AI's response was unreadable." print_to_console( @@ -86,7 +90,7 @@ def print_assistant_thoughts(assistant_reply): elif isinstance(assistant_thoughts_plan, dict): assistant_thoughts_plan = str(assistant_thoughts_plan) # Split the input_string using the newline character and dash - + lines = assistant_thoughts_plan.split('\n') # Iterate through the lines and print each one with a bullet @@ -111,6 +115,7 @@ def print_assistant_thoughts(assistant_reply): call_stack = traceback.format_exc() print_to_console("Error: \n", Fore.RED, call_stack) + def load_variables(config_file="config.yaml"): # Load variables from yaml file if it exists try: From f2ba7f21c510fabe226fac661df0e9112674708a Mon Sep 17 00:00:00 2001 From: russellocean Date: Mon, 3 Apr 2023 16:44:10 -0400 Subject: [PATCH 06/24] Added support for Google Custom Search API This pull request adds functionality to the project to allow for a choice between the original Google search method and the Google Custom Search API. The google_search method uses the original method of scraping the HTML from the search results page, using googlesearch-python, while the google_official_search method uses the Google Custom Search API to retrieve search results. How to test: To test the functionality, ensure that you have valid API keys and search engine IDs for both the Google search method and the Google Custom Search API. You can set these values in your environment variables as described in the README.md file. Additional Notes: This pull request only adds functionality and makes improvements to existing code. No new features or major changes have been introduced. --- .DS_Store | Bin 0 -> 8196 bytes .env.template | 4 --- README.md | 52 ++++++++++++++++++++++++++++++----- auto_gpt_workspace/.DS_Store | Bin 0 -> 6148 bytes requirements.txt | 1 + scripts/commands.py | 45 +++++++++++++++++++++++++++++- scripts/config.py | 11 ++++++-- 7 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 .DS_Store delete mode 100644 .env.template create mode 100644 auto_gpt_workspace/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2287363ff8124dfd2cf4b68bc7738e40b201829b GIT binary patch literal 8196 zcmeHM&2G~`5T0#QoU{T(6-WhvWQl7U(m$k%OPVH!O2DB(Z~zqSB(zo>JH$=`iX!C> zyaKPlod@AvIKel&P82%{LLi~4-IaE~{h1kiznQf&4iSk`udze4MMP;-#_R@~1%=nS z&XtvDW)mo&PbaQlw_V@HI6Eh;Co}_^0nLDBKr^5jxCjj3oy{e^G8Q8oE0m88G%^JMrZ6oF`tqkg(BuhVF~YGz%%BLR3RJ2hN-;!~IS8eW^I6cy@LGoTrmXMl6}6y>Q&9`)n-yZDH;FF$3GiY#|V z4uuK19|<{QB1h-cBReilM>w=MW~{DHr5#xJ$fqtf6FOfLI-6v{atPTPbUNtOXdpFP z6ku#oJ!wPS`x_hfAm~J2G``s#*9pQx;k#H_O|4xsjEu2iysn=6gKB7ny`W@uU-Iag z@4NP-Z`seC=Af3ndF*?k<#^4mRB#$ih`f5?cnyD0@_Sw*kh)d1kjbPowd|eYaC>KW z?=WW`6!u3sb9lI0$eH_l4@aX+`qupik4|eXx9$0#q<2U}k4Cz##?$sQdVj=NzuNU& z-#ddm+ghhGIIU9)(b1*1@VuL3mAy&%8E@W(j0GRCN4oHl2ehDB!(0=yA^IMC7QpKt zu+k=JD)f}9REbLyA|rNv19!}k(UENsm*yCVNoVL3c8{>nC%`=J zrjgL#GcdcqyBwYL4%QvnYs-@pVn5s1jf*QYS04Jj(>_Ld^xiK#GqZNHOYJVym%PuO zO#^pOhYd%bhQz)lOTUr6Fj0Q+k5QgrAra4O(mNcR34UZ;%<==L>!KOBS5T32oG!&r+1@W}twQ8$Y5HGRTgI6PZP^nE@G#Im`N$sH&@&NimK8UZQ zGrL<+t2Ysq8JPVh^OI!14Z9ft5cNT)3Qz)o0xDt7#o-g7IO&w+tY-#M=zH`ah2$_& z?I4=UX2)-2fY#1|1lrJt5Ze{ zbv1}PiLUicz;z35v$Q-KtyVWScgnI>sg28Ww6jqu%dO4r@z^aauB`7KHE*KZSl#P4 z2Z3LymU)X4ctGO=3wM4$j#PYwkxA7gn~@n{2AF}r&Vb$53dO%Z5q^JWfEoC9255hf zsDz%y%%I*naL_FPVjkUE(59b8s*x5wi|~n xW=UtQM7=~Mp}frCYY7_qD8^hmikDEepkI=K=vmARq6dY41T+miFatlzzzfnIS;hbW literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index 5f51bdf579d1..e1a98ee72605 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,5 @@ requests tiktoken==0.3.3 docker googlesearch-python +google-api-python-client # If using Google's Custom Search JSON API (https://developers.google.com/custom-search/v1/overview) Won't result in a 403 error # 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 2e332711bc53..f94fdc41f6e1 100644 --- a/scripts/commands.py +++ b/scripts/commands.py @@ -10,6 +10,9 @@ from execute_code import execute_python_file from json_parser import fix_and_parse_json from googlesearch import search +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError + cfg = Config() @@ -44,7 +47,13 @@ def get_command(response): def execute_command(command_name, arguments): try: if command_name == "google": - return google_search(arguments["input"]) + print("Using Google search method") + # Check if the Google API key is set and use the official search method + # If the API key is not set or has only whitespaces, use the unofficial search method + if cfg.google_api_key and (cfg.google_api_key.strip() if cfg.google_api_key else None): + return google_official_search(arguments["input"]) + else: + return google_search(arguments["input"]) elif command_name == "memory_add": return commit_memory(arguments["string"]) elif command_name == "memory_del": @@ -108,6 +117,40 @@ def google_search(query, num_results=8): return json.dumps(search_results, ensure_ascii=False, indent=4) +def google_official_search(query, num_results=8): + from googleapiclient.discovery import build + from googleapiclient.errors import HttpError + import json + + try: + # Get the Google API key and Custom Search Engine ID from the config file + api_key = cfg.google_api_key + custom_search_engine_id = cfg.custom_search_engine_id + + # Initialize the Custom Search API service + service = build("customsearch", "v1", developerKey=api_key) + + # Send the search query and retrieve the results + result = service.cse().list(q=query, cx=custom_search_engine_id, num=num_results).execute() + + # Extract the search result items from the response + search_results = result.get("items", []) + + # Create a list of only the URLs from the search results + search_results_links = [item["link"] for item in search_results] + + except HttpError as e: + # Handle errors in the API call + error_details = json.loads(e.content.decode()) + + # Check if the error is related to an invalid or missing API key + if error_details.get("error", {}).get("code") == 403 and "invalid API key" in error_details.get("error", {}).get("message", ""): + return "Error: The provided Google API key is invalid or missing." + else: + return f"Error: {e}" + + # Return the list of search result URLs + return search_results_links def browse_website(url): summary = get_text_summary(url) diff --git a/scripts/config.py b/scripts/config.py index 44d99bffd0fb..51e11757420c 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -35,11 +35,13 @@ def __init__(self): self.openai_api_key = os.getenv("OPENAI_API_KEY") self.elevenlabs_api_key = os.getenv("ELEVENLABS_API_KEY") + + self.google_api_key = os.getenv("GOOGLE_API_KEY") + self.custom_search_engine_id = os.getenv("CUSTOM_SEARCH_ENGINE_ID") # Initialize the OpenAI API client openai.api_key = self.openai_api_key - def set_continuous_mode(self, value: bool): self.continuous_mode = value @@ -63,6 +65,9 @@ def set_openai_api_key(self, value: str): def set_elevenlabs_api_key(self, value: str): self.elevenlabs_api_key = value - - + def set_google_api_key(self, value: str): + self.google_api_key = value + + def set_custom_search_engine_id(self, value: str): + self.custom_search_engine_id = value \ No newline at end of file From 30d07d9102b528ee7d0a324d860904f2211339b6 Mon Sep 17 00:00:00 2001 From: russellocean Date: Mon, 3 Apr 2023 16:49:05 -0400 Subject: [PATCH 07/24] Added google-api-python-client to requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e1a98ee72605..063931a95126 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,5 +9,5 @@ requests tiktoken==0.3.3 docker googlesearch-python -google-api-python-client # If using Google's Custom Search JSON API (https://developers.google.com/custom-search/v1/overview) Won't result in a 403 error +google-api-python-client #(https://developers.google.com/custom-search/v1/overview) # Googlesearch python seems to be a bit cursed, anyone good at fixing thigns like this? \ No newline at end of file From cb6e8ee665deca39db20fde78a976693776d9aa3 Mon Sep 17 00:00:00 2001 From: russellocean Date: Mon, 3 Apr 2023 16:58:55 -0400 Subject: [PATCH 08/24] Template update and Added .DS_Store to .gitignore --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 2287363ff8124dfd2cf4b68bc7738e40b201829b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM&2G~`5T0#QoU{T(6-WhvWQl7U(m$k%OPVH!O2DB(Z~zqSB(zo>JH$=`iX!C> zyaKPlod@AvIKel&P82%{LLi~4-IaE~{h1kiznQf&4iSk`udze4MMP;-#_R@~1%=nS z&XtvDW)mo&PbaQlw_V@HI6Eh;Co}_^0nLDBKr^5jxCjj3oy{e^G8Q8oE0m88G%^JMrZ6oF`tqkg(BuhVF~YGz%%BLR3RJ2hN-;!~IS8eW^I6cy@LGoTrmXMl6}6y>Q&9`)n-yZDH;FF$3GiY#|V z4uuK19|<{QB1h-cBReilM>w=MW~{DHr5#xJ$fqtf6FOfLI-6v{atPTPbUNtOXdpFP z6ku#oJ!wPS`x_hfAm~J2G``s#*9pQx;k#H_O|4xsjEu2iysn=6gKB7ny`W@uU-Iag z@4NP-Z`seC=Af3ndF*?k<#^4mRB#$ih`f5?cnyD0@_Sw*kh)d1kjbPowd|eYaC>KW z?=WW`6!u3sb9lI0$eH_l4@aX+`qupik4|eXx9$0#q<2U}k4Cz##?$sQdVj=NzuNU& z-#ddm+ghhGIIU9)(b1*1@VuL3mAy&%8E@W(j0GRCN4oHl2ehDB!(0=yA^IMC7QpKt zu+k=JD)f}9REbLyA|rNv19!}k(UENsm*yCVNoVL3c8{>nC%`=J zrjgL#GcdcqyBwYL4%QvnYs-@pVn5s1jf*QYS04Jj(>_Ld^xiK#GqZNHOYJVym%PuO zO#^pOhYd%bhQz)lOTUr6Fj0Q+k5QgrAra4O(mNcR34UZ;%<==L>!KOB Date: Mon, 3 Apr 2023 17:07:53 -0400 Subject: [PATCH 09/24] Delete .DS_Store --- auto_gpt_workspace/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 auto_gpt_workspace/.DS_Store diff --git a/auto_gpt_workspace/.DS_Store b/auto_gpt_workspace/.DS_Store deleted file mode 100644 index aa6e57de2aafac3a20e6c9f853a58e8eaf02c8e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5T32oG!&r+1@W}twQ8$Y5HGRTgI6PZP^nE@G#Im`N$sH&@&NimK8UZQ zGrL<+t2Ysq8JPVh^OI!14Z9ft5cNT)3Qz)o0xDt7#o-g7IO&w+tY-#M=zH`ah2$_& z?I4=UX2)-2fY#1|1lrJt5Ze{ zbv1}PiLUicz;z35v$Q-KtyVWScgnI>sg28Ww6jqu%dO4r@z^aauB`7KHE*KZSl#P4 z2Z3LymU)X4ctGO=3wM4$j#PYwkxA7gn~@n{2AF}r&Vb$53dO%Z5q^JWfEoC9255hf zsDz%y%%I*naL_FPVjkUE(59b8s*x5wi|~n xW=UtQM7=~Mp}frCYY7_qD8^hmikDEepkI=K=vmARq6dY41T+miFatlzzzfnIS;hbW From 064a2af9b594de65107abd4f00eb91079e14d51e Mon Sep 17 00:00:00 2001 From: russellocean Date: Mon, 3 Apr 2023 17:29:55 -0400 Subject: [PATCH 10/24] Added back .env.template --- .env.template | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .env.template diff --git a/.env.template b/.env.template new file mode 100644 index 000000000000..c64d85028f02 --- /dev/null +++ b/.env.template @@ -0,0 +1,6 @@ +OPENAI_API_KEY=your-openai-api-key +ELEVENLABS_API_KEY=your-elevenlabs-api-key +SMART_LLM_MODEL="gpt-4" +FAST_LLM_MODEL="gpt-3.5-turbo" +GOOGLE_API_KEY= +CUSTOM_SEARCH_ENGINE_ID= \ No newline at end of file From 79f0882dfcf50bc5ab9ca29e2ed3eb628650facc Mon Sep 17 00:00:00 2001 From: kminer Date: Mon, 3 Apr 2023 15:35:01 -0600 Subject: [PATCH 11/24] 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 44d99bffd0fb..8a9ba00ccf05 100644 --- a/scripts/config.py +++ b/scripts/config.py @@ -59,7 +59,7 @@ def set_smart_token_limit(self, value: int): 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 04c43432c24da884e476e996dda3269f65f446e4 Mon Sep 17 00:00:00 2001 From: yousefissa Date: Mon, 3 Apr 2023 14:53:19 -0700 Subject: [PATCH 12/24] cleanup method --- scripts/main.py | 70 ++++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/scripts/main.py b/scripts/main.py index 2304baf4540a..01b972c50a37 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -49,68 +49,44 @@ def print_assistant_thoughts(assistant_reply): global ai_name global cfg try: - # Parse and print Assistant response assistant_reply_json = fix_and_parse_json(assistant_reply) assistant_thoughts_reasoning = None assistant_thoughts_plan = None assistant_thoughts_speak = None assistant_thoughts_criticism = None - try: - assistant_thoughts = assistant_reply_json.get("thoughts") - if assistant_thoughts: - assistant_thoughts_text = assistant_thoughts.get("text") - assistant_thoughts_reasoning = assistant_thoughts.get("reasoning") - assistant_thoughts_plan = assistant_thoughts.get("plan") - assistant_thoughts_criticism = assistant_thoughts.get("criticism") - assistant_thoughts_speak = assistant_thoughts.get("speak") - else: - assistant_thoughts_text = None - assistant_thoughts_reasoning = None - assistant_thoughts_plan = None - assistant_thoughts_criticism = None - assistant_thoughts_speak = None - except Exception: - assistant_thoughts_text = "The AI's response was unreadable." + assistant_thoughts = assistant_reply_json.get("thoughts", {}) + assistant_thoughts_text = assistant_thoughts.get("text") + + if assistant_thoughts: + assistant_thoughts_reasoning = assistant_thoughts.get("reasoning") + assistant_thoughts_plan = assistant_thoughts.get("plan") + assistant_thoughts_criticism = assistant_thoughts.get("criticism") + assistant_thoughts_speak = assistant_thoughts.get("speak") + + print_to_console(f"{ai_name.upper()} THOUGHTS:", Fore.YELLOW, assistant_thoughts_text) + print_to_console("REASONING:", Fore.YELLOW, assistant_thoughts_reasoning) - print_to_console( - f"{ai_name.upper()} THOUGHTS:", - Fore.YELLOW, - assistant_thoughts_text) - print_to_console( - "REASONING:", - Fore.YELLOW, - assistant_thoughts_reasoning) if assistant_thoughts_plan: print_to_console("PLAN:", Fore.YELLOW, "") - if assistant_thoughts_plan: - # If it's a list, join it into a string - if isinstance(assistant_thoughts_plan, list): - assistant_thoughts_plan = "\n".join(assistant_thoughts_plan) - elif isinstance(assistant_thoughts_plan, dict): - assistant_thoughts_plan = str(assistant_thoughts_plan) - # Split the input_string using the newline character and dash - - lines = assistant_thoughts_plan.split('\n') - - # Iterate through the lines and print each one with a bullet - # point - for line in lines: - # Remove any "-" characters from the start of the line - line = line.lstrip("- ") - print_to_console("- ", Fore.GREEN, line.strip()) - print_to_console( - "CRITICISM:", - Fore.YELLOW, - assistant_thoughts_criticism) + if isinstance(assistant_thoughts_plan, list): + assistant_thoughts_plan = "\n".join(assistant_thoughts_plan) + elif isinstance(assistant_thoughts_plan, dict): + assistant_thoughts_plan = str(assistant_thoughts_plan) + + lines = assistant_thoughts_plan.split('\n') + for line in lines: + line = line.lstrip("- ") + print_to_console("- ", Fore.GREEN, line.strip()) + + print_to_console("CRITICISM:", Fore.YELLOW, assistant_thoughts_criticism) - # Speak the assistant's thoughts if cfg.speak_mode and assistant_thoughts_speak: speak.say_text(assistant_thoughts_speak) 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) From 8753eba22cd23b0ceff97f95a27f3ff43929176f Mon Sep 17 00:00:00 2001 From: yousefissa Date: Mon, 3 Apr 2023 14:55:30 -0700 Subject: [PATCH 13/24] comments --- scripts/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/main.py b/scripts/main.py index 01b972c50a37..97c05d7dbda2 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -49,6 +49,7 @@ def print_assistant_thoughts(assistant_reply): global ai_name global cfg try: + # Parse and print Assistant response assistant_reply_json = fix_and_parse_json(assistant_reply) assistant_thoughts_reasoning = None @@ -69,24 +70,27 @@ def print_assistant_thoughts(assistant_reply): if assistant_thoughts_plan: print_to_console("PLAN:", Fore.YELLOW, "") + # If it's a list, join it into a string if isinstance(assistant_thoughts_plan, list): assistant_thoughts_plan = "\n".join(assistant_thoughts_plan) elif isinstance(assistant_thoughts_plan, dict): assistant_thoughts_plan = str(assistant_thoughts_plan) + # Split the input_string using the newline character and dashes lines = assistant_thoughts_plan.split('\n') for line in lines: line = line.lstrip("- ") print_to_console("- ", Fore.GREEN, line.strip()) print_to_console("CRITICISM:", Fore.YELLOW, assistant_thoughts_criticism) - + # Speak the assistant's thoughts if cfg.speak_mode and assistant_thoughts_speak: speak.say_text(assistant_thoughts_speak) 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) From 7e529e19d9b97c2e99720bd6f1bc829f7c5e8597 Mon Sep 17 00:00:00 2001 From: Toran Bruce Richards Date: Tue, 4 Apr 2023 00:24:22 +0100 Subject: [PATCH 14/24] Removes print. --- scripts/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/commands.py b/scripts/commands.py index f94fdc41f6e1..8ad95336462f 100644 --- a/scripts/commands.py +++ b/scripts/commands.py @@ -47,7 +47,7 @@ def get_command(response): def execute_command(command_name, arguments): try: if command_name == "google": - print("Using Google search method") + # Check if the Google API key is set and use the official search method # If the API key is not set or has only whitespaces, use the unofficial search method if cfg.google_api_key and (cfg.google_api_key.strip() if cfg.google_api_key else None): From 8a08b0c01b5be1b70e58a1d6817d4f85c54465ef Mon Sep 17 00:00:00 2001 From: Preston Jensen Date: Mon, 3 Apr 2023 19:20:42 -0600 Subject: [PATCH 15/24] 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 f096c5f3e23c..510f9c29d5f3 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.") - combined_summary = "\n".join(summaries) + print(f"Summarized {len(chunks)} chunks.") - # 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}, - ] + combined_summary = "\n".join(summaries) + 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 8ad95336462f..ed789c8e9292 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 d17fa27a1c7f..1596c81053d1 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 16/24] 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 97c05d7dbda2..03f656b0721d 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -303,7 +303,7 @@ def parse_arguments(): 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 @@ def parse_arguments(): user_input = "EXIT" break else: - continue - - if user_input != "GENERATE NEXT COMMAND JSON": - print("Exiting...", flush=True) - break + user_input = console_input + command_name = "human_feedback" + 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 @@ def parse_arguments(): 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 @@ def parse_arguments(): 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 17/24] 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 97c05d7dbda2..a1c08018a404 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 18/24] 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 a1c08018a404..86afec397bf7 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 19/24] 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 063931a95126..7961106b6c8a 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 2fbcbed26f51..6fef41f83e87 100644 --- a/scripts/speak.py +++ b/scripts/speak.py @@ -3,6 +3,8 @@ import requests from config import Config cfg = Config() +import gtts + # TODO: Nicer names for these ids voices = ["ErXwobaYiN019PkySvjV", "EXAVITQu4vr4xnSDxMaL"] @@ -12,10 +14,9 @@ "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 20/24] 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 d17fa27a1c7f..2cb73a8d32d9 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 21/24] 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 62a36e125051..f4d6eb0e5fe6 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 22/24] 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 f4d6eb0e5fe6..bb4b296e4dba 100644 --- a/scripts/data.py +++ b/scripts/data.py @@ -6,7 +6,7 @@ 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 23/24] Update scripts/data.py --- scripts/data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/data.py b/scripts/data.py index 7969d69c3007..a6ffdadf0c69 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 24/24] Update scripts/data.py --- scripts/data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/data.py b/scripts/data.py index a6ffdadf0c69..72a6bbfc64c0 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()