From f976c382889eabcd92e2402bc9041becba2032b3 Mon Sep 17 00:00:00 2001 From: Lorenzo Fontoura Date: Tue, 4 Apr 2023 18:33:58 +1000 Subject: [PATCH 01/23] refactor argument to vector --- babyagi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/babyagi.py b/babyagi.py index 85dc9560..8f552cc0 100755 --- a/babyagi.py +++ b/babyagi.py @@ -165,8 +165,8 @@ def context_agent(query: str, index: str, n: int): # Step 2: Enrich result and store in Pinecone enriched_result = {'data': result} # This is where you should enrich the result if needed result_id = f"result_{task['task_id']}" - vector = enriched_result['data'] # extract the actual result from the dictionary - index.upsert([(result_id, get_ada_embedding(vector),{"task":task['task_name'],"result":result})]) + vector = get_ada_embedding(enriched_result['data']) # get vector of the actual result extracted from the dictionary + index.upsert([(result_id, vector, {"task":task['task_name'],"result":result})]) # Step 3: Create new tasks and reprioritize task list new_tasks = task_creation_agent(OBJECTIVE,enriched_result, task["task_name"], [t["task_name"] for t in task_list]) From 3532f987744e9254afacc254e3325d1910c0651d Mon Sep 17 00:00:00 2001 From: Korben Date: Fri, 7 Apr 2023 10:54:59 +0200 Subject: [PATCH 02/23] OpenAI API Error managed If the OpenAI API doesn't answer, the script wait 10 seconds and try again --- babyagi.py | 55 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/babyagi.py b/babyagi.py index e5e04c8e..67be4bda 100755 --- a/babyagi.py +++ b/babyagi.py @@ -69,30 +69,37 @@ def get_ada_embedding(text): return openai.Embedding.create(input=[text], model="text-embedding-ada-002")["data"][0]["embedding"] def openai_call(prompt: str, model: str = OPENAI_API_MODEL, temperature: float = 0.5, max_tokens: int = 100): - if not model.startswith('gpt-'): - # Use completion API - response = openai.Completion.create( - engine=model, - prompt=prompt, - temperature=temperature, - max_tokens=max_tokens, - top_p=1, - frequency_penalty=0, - presence_penalty=0 - ) - return response.choices[0].text.strip() - else: - # Use chat completion API - messages=[{"role": "user", "content": prompt}] - response = openai.ChatCompletion.create( - model=model, - messages=messages, - temperature=temperature, - max_tokens=max_tokens, - n=1, - stop=None, - ) - return response.choices[0].message.content.strip() + while True: + try: + if not model.startswith('gpt-'): + # Use completion API + response = openai.Completion.create( + engine=model, + prompt=prompt, + temperature=temperature, + max_tokens=max_tokens, + top_p=1, + frequency_penalty=0, + presence_penalty=0 + ) + return response.choices[0].text.strip() + else: + # Use chat completion API + messages=[{"role": "user", "content": prompt}] + response = openai.ChatCompletion.create( + model=model, + messages=messages, + temperature=temperature, + max_tokens=max_tokens, + n=1, + stop=None, + ) + return response.choices[0].message.content.strip() + except openai.error.RateLimitError: + print("The OpenAI API rate limit has been exceeded. Waiting 10 seconds and trying again.") + time.sleep(10) # Wait 10 seconds and try again + else: + break def task_creation_agent(objective: str, result: Dict, task_description: str, task_list: List[str]): prompt = f"You are an task creation AI that uses the result of an execution agent to create new tasks with the following objective: {objective}, The last completed task has the result: {result}. This result was based on this task description: {task_description}. These are incomplete tasks: {', '.join(task_list)}. Based on the result, create new tasks to be completed by the AI system that do not overlap with incomplete tasks. Return the tasks as an array." From 1796e5b757412862df2209f62bedf6a66fb092ff Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Fri, 7 Apr 2023 09:33:46 -0700 Subject: [PATCH 03/23] Allow an environment argument to support extension configuration --- .gitignore | 2 +- babyagi.py | 16 +++++++++++++--- requirements.txt | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index e58e5a29..bc8f2233 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -.env +.env* .idea diff --git a/babyagi.py b/babyagi.py index e5e04c8e..42188838 100755 --- a/babyagi.py +++ b/babyagi.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import argparse import os import openai import pinecone @@ -9,8 +10,17 @@ from dotenv import load_dotenv import os -# Set Variables -load_dotenv() +# Parse arguments +parser = argparse.ArgumentParser() +parser.add_argument('-e', '--env', help='filename for env') +args = parser.parse_args() + +# Set environment variables +if args.env: + print('Using env from file:', args.env) + load_dotenv(args.env) +else: + load_dotenv() # Set API Keys OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") @@ -130,7 +140,7 @@ def context_agent(query: str, n: int): results = index.query(query_embedding, top_k=n, include_metadata=True) #print("***** RESULTS *****") #print(results) - sorted_results = sorted(results.matches, key=lambda x: x.score, reverse=True) + sorted_results = sorted(results.matches, key=lambda x: x.score, reverse=True) return [(str(item.metadata['task'])) for item in sorted_results] # Add the first task diff --git a/requirements.txt b/requirements.txt index 35ab7743..f7778cbb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ openai==0.27.2 pinecone-client==2.2.1 -python-dotenv==1.0.0 \ No newline at end of file +python-dotenv==1.0.0 +argparse==1.4.0 From 74122c5c8bdb08e4bc0b3a878dce77474b8d86f7 Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Fri, 7 Apr 2023 09:43:49 -0700 Subject: [PATCH 04/23] Use objective from environment --- babyagi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babyagi.py b/babyagi.py index 42188838..819c8697 100755 --- a/babyagi.py +++ b/babyagi.py @@ -43,7 +43,7 @@ assert YOUR_TABLE_NAME, "TABLE_NAME environment variable is missing from .env" # Project config -OBJECTIVE = sys.argv[1] if len(sys.argv) > 1 else os.getenv("OBJECTIVE", "") +OBJECTIVE = os.getenv("OBJECTIVE", "") assert OBJECTIVE, "OBJECTIVE environment variable is missing from .env" YOUR_FIRST_TASK = os.getenv("FIRST_TASK", "") From 8226e52f3157f67e6585a2e6f8a5a3f866d25a33 Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Fri, 7 Apr 2023 09:56:43 -0700 Subject: [PATCH 05/23] Support multiple env files --- babyagi.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/babyagi.py b/babyagi.py index 819c8697..f26f8bea 100755 --- a/babyagi.py +++ b/babyagi.py @@ -12,15 +12,17 @@ # Parse arguments parser = argparse.ArgumentParser() -parser.add_argument('-e', '--env', help='filename for env') +parser.add_argument('-e', '--env', nargs='+', help='filenames for env') args = parser.parse_args() -# Set environment variables +# Set environment variables (as extensions) if args.env: - print('Using env from file:', args.env) - load_dotenv(args.env) -else: - load_dotenv() + for env_path in args.env: + load_dotenv(env_path) + print('Using env from file:', env_path) + +# Load default environment variables +load_dotenv() # Set API Keys OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") From 1f2cae94b8414379b062f3c7b5684a249142ca6f Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Fri, 7 Apr 2023 09:56:43 -0700 Subject: [PATCH 06/23] Support multiple env files --- babyagi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/babyagi.py b/babyagi.py index f26f8bea..0e81a940 100755 --- a/babyagi.py +++ b/babyagi.py @@ -10,18 +10,18 @@ from dotenv import load_dotenv import os -# Parse arguments +# Parse arguments for optional extensions parser = argparse.ArgumentParser() parser.add_argument('-e', '--env', nargs='+', help='filenames for env') args = parser.parse_args() -# Set environment variables (as extensions) +# Set environment variables for optional extensions if args.env: for env_path in args.env: load_dotenv(env_path) print('Using env from file:', env_path) -# Load default environment variables +# Load default environment variables (.env) load_dotenv() # Set API Keys From 752e74d7e794ab0ba6bb31b24844469e43afd77c Mon Sep 17 00:00:00 2001 From: MalikMAlna Date: Fri, 7 Apr 2023 13:02:23 -0400 Subject: [PATCH 07/23] Formatting, removing unnecessary import, and general cleanup for consistency --- babyagi.py | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/babyagi.py b/babyagi.py index e5e04c8e..77e009f0 100755 --- a/babyagi.py +++ b/babyagi.py @@ -7,7 +7,6 @@ from collections import deque from typing import Dict, List from dotenv import load_dotenv -import os # Set Variables load_dotenv() @@ -20,7 +19,7 @@ assert OPENAI_API_MODEL, "OPENAI_API_MODEL environment variable is missing from .env" if "gpt-4" in OPENAI_API_MODEL.lower(): - print(f"\033[91m\033[1m"+"\n*****USING GPT-4. POTENTIALLY EXPENSIVE. MONITOR YOUR COSTS*****"+"\033[0m\033[0m") + print("\033[91m\033[1m"+"\n*****USING GPT-4. POTENTIALLY EXPENSIVE. MONITOR YOUR COSTS*****" + "\033[0m\033[0m") PINECONE_API_KEY = os.getenv("PINECONE_API_KEY", "") assert PINECONE_API_KEY, "PINECONE_API_KEY environment variable is missing from .env" @@ -39,7 +38,7 @@ YOUR_FIRST_TASK = os.getenv("FIRST_TASK", "") assert YOUR_FIRST_TASK, "FIRST_TASK environment variable is missing from .env" -#Print OBJECTIVE +# Print OBJECTIVE print("\033[96m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m") print(OBJECTIVE) @@ -61,13 +60,16 @@ # Task list task_list = deque([]) + def add_task(task: Dict): task_list.append(task) + def get_ada_embedding(text): text = text.replace("\n", " ") return openai.Embedding.create(input=[text], model="text-embedding-ada-002")["data"][0]["embedding"] + def openai_call(prompt: str, model: str = OPENAI_API_MODEL, temperature: float = 0.5, max_tokens: int = 100): if not model.startswith('gpt-'): # Use completion API @@ -83,7 +85,7 @@ def openai_call(prompt: str, model: str = OPENAI_API_MODEL, temperature: float = return response.choices[0].text.strip() else: # Use chat completion API - messages=[{"role": "user", "content": prompt}] + messages = [{"role": "user", "content": prompt}] response = openai.ChatCompletion.create( model=model, messages=messages, @@ -94,12 +96,14 @@ def openai_call(prompt: str, model: str = OPENAI_API_MODEL, temperature: float = ) return response.choices[0].message.content.strip() + def task_creation_agent(objective: str, result: Dict, task_description: str, task_list: List[str]): prompt = f"You are an task creation AI that uses the result of an execution agent to create new tasks with the following objective: {objective}, The last completed task has the result: {result}. This result was based on this task description: {task_description}. These are incomplete tasks: {', '.join(task_list)}. Based on the result, create new tasks to be completed by the AI system that do not overlap with incomplete tasks. Return the tasks as an array." response = openai_call(prompt) new_tasks = response.split('\n') return [{"task_name": task_name} for task_name in new_tasks] + def prioritization_agent(this_task_id: int): global task_list task_names = [t["task_name"] for t in task_list] @@ -118,21 +122,24 @@ def prioritization_agent(this_task_id: int): task_name = task_parts[1].strip() task_list.append({"task_id": task_id, "task_name": task_name}) + def execution_agent(objective: str, task: str) -> str: - context=context_agent(query=objective, n=5) - #print("\n*******RELEVANT CONTEXT******\n") - #print(context) - prompt =f"You are an AI who performs one task based on the following objective: {objective}.\nTake into account these previously completed tasks: {context}\nYour task: {task}\nResponse:" + context = context_agent(query=objective, n=5) + # print("\n*******RELEVANT CONTEXT******\n") + # print(context) + prompt = f"You are an AI who performs one task based on the following objective: {objective}.\nTake into account these previously completed tasks: {context}\nYour task: {task}\nResponse:" return openai_call(prompt, temperature=0.7, max_tokens=2000) + def context_agent(query: str, n: int): query_embedding = get_ada_embedding(query) results = index.query(query_embedding, top_k=n, include_metadata=True) - #print("***** RESULTS *****") - #print(results) + # print("***** RESULTS *****") + # print(results) sorted_results = sorted(results.matches, key=lambda x: x.score, reverse=True) return [(str(item.metadata['task'])) for item in sorted_results] + # Add the first task first_task = { "task_id": 1, @@ -147,15 +154,15 @@ def context_agent(query: str, n: int): # Print the task list print("\033[95m\033[1m"+"\n*****TASK LIST*****\n"+"\033[0m\033[0m") for t in task_list: - print(str(t['task_id'])+": "+t['task_name']) + print(str(t['task_id']) + ": " + t['task_name']) # Step 1: Pull the first task task = task_list.popleft() print("\033[92m\033[1m"+"\n*****NEXT TASK*****\n"+"\033[0m\033[0m") - print(str(task['task_id'])+": "+task['task_name']) + print(str(task['task_id']) + ": " + task['task_name']) # Send to execution function to complete the task based on the context - result = execution_agent(OBJECTIVE,task["task_name"]) + result = execution_agent(OBJECTIVE, task["task_name"]) this_task_id = int(task["task_id"]) print("\033[93m\033[1m"+"\n*****TASK RESULT*****\n"+"\033[0m\033[0m") print(result) @@ -164,10 +171,10 @@ def context_agent(query: str, n: int): enriched_result = {'data': result} # This is where you should enrich the result if needed result_id = f"result_{task['task_id']}" vector = enriched_result['data'] # extract the actual result from the dictionary - index.upsert([(result_id, get_ada_embedding(vector),{"task":task['task_name'],"result":result})]) + index.upsert([(result_id, get_ada_embedding(vector), {"task": task['task_name'], "result":result})]) # Step 3: Create new tasks and reprioritize task list - new_tasks = task_creation_agent(OBJECTIVE,enriched_result, task["task_name"], [t["task_name"] for t in task_list]) + new_tasks = task_creation_agent(OBJECTIVE, enriched_result, task["task_name"], [t["task_name"] for t in task_list]) for new_task in new_tasks: task_id_counter += 1 From 9990b26757210c3280d99cae8e945173d8e7eeb2 Mon Sep 17 00:00:00 2001 From: MalikMAlna Date: Fri, 7 Apr 2023 13:08:53 -0400 Subject: [PATCH 08/23] Some more formatting and changing new_tasks split --- babyagi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/babyagi.py b/babyagi.py index 77e009f0..25912d74 100755 --- a/babyagi.py +++ b/babyagi.py @@ -39,7 +39,7 @@ assert YOUR_FIRST_TASK, "FIRST_TASK environment variable is missing from .env" # Print OBJECTIVE -print("\033[96m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m") +print("\033[96m\033[1m" + "\n*****OBJECTIVE*****\n" + "\033[0m\033[0m") print(OBJECTIVE) # Configure OpenAI and Pinecone @@ -100,7 +100,7 @@ def openai_call(prompt: str, model: str = OPENAI_API_MODEL, temperature: float = def task_creation_agent(objective: str, result: Dict, task_description: str, task_list: List[str]): prompt = f"You are an task creation AI that uses the result of an execution agent to create new tasks with the following objective: {objective}, The last completed task has the result: {result}. This result was based on this task description: {task_description}. These are incomplete tasks: {', '.join(task_list)}. Based on the result, create new tasks to be completed by the AI system that do not overlap with incomplete tasks. Return the tasks as an array." response = openai_call(prompt) - new_tasks = response.split('\n') + new_tasks = response.split('\n') if '\n' in response else [response] return [{"task_name": task_name} for task_name in new_tasks] From e81ab6798248d5ab0df666dd85a9168815ee650c Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Fri, 7 Apr 2023 10:15:13 -0700 Subject: [PATCH 09/23] Ordering --- babyagi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/babyagi.py b/babyagi.py index 0e81a940..9f794a57 100755 --- a/babyagi.py +++ b/babyagi.py @@ -15,15 +15,15 @@ parser.add_argument('-e', '--env', nargs='+', help='filenames for env') args = parser.parse_args() +# Load default environment variables (.env) +load_dotenv() + # Set environment variables for optional extensions if args.env: for env_path in args.env: load_dotenv(env_path) print('Using env from file:', env_path) -# Load default environment variables (.env) -load_dotenv() - # Set API Keys OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") assert OPENAI_API_KEY, "OPENAI_API_KEY environment variable is missing from .env" From 65842f27312b55f235f422b6ba2e0eaa46e334f1 Mon Sep 17 00:00:00 2001 From: MalikMAlna Date: Fri, 7 Apr 2023 13:35:19 -0400 Subject: [PATCH 10/23] Last minute tweaks from sync --- babyagi.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/babyagi.py b/babyagi.py index 18d5382a..14a11732 100755 --- a/babyagi.py +++ b/babyagi.py @@ -51,7 +51,11 @@ assert YOUR_FIRST_TASK, "FIRST_TASK environment variable is missing from .env" # Print OBJECTIVE +<<<<<<< HEAD print("\033[96m\033[1m" + "\n*****OBJECTIVE*****\n" + "\033[0m\033[0m") +======= +print("\033[96m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m") +>>>>>>> 8a37c69 (Last minute tweaks from sync) print(OBJECTIVE) # Configure OpenAI and Pinecone @@ -148,7 +152,7 @@ def context_agent(query: str, n: int): results = index.query(query_embedding, top_k=n, include_metadata=True) # print("***** RESULTS *****") # print(results) - sorted_results = sorted(results.matches, key=lambda x: x.score, reverse=True) + sorted_results = sorted(results.matches, key=lambda x: x.score, reverse=True) return [(str(item.metadata['task'])) for item in sorted_results] From 56fdfb583dc210db61c188f61aa5ac7d75f76d33 Mon Sep 17 00:00:00 2001 From: Franci Penov Date: Fri, 7 Apr 2023 10:47:03 -0700 Subject: [PATCH 11/23] Adding some comments to .env.example --- .env.example | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.env.example b/.env.example index 3f7871fd..3da8e0f8 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,9 @@ +# cp .env.example .env +# Edit your .env file with your own values +# Don't commit your .env file to git/push to GitHub! +# Don't modify/delete .env.example unless adding extensions to the project +# which require new variable to be added to the .env file + # API CONFIG OPENAI_API_KEY= OPENAI_API_MODEL=gpt-3.5-turbo # alternatively, gpt-4, text-davinci-003, etc From 94374873b72db1dcee01e8563a4de69ce5d28079 Mon Sep 17 00:00:00 2001 From: Franci Penov Date: Thu, 6 Apr 2023 17:11:33 -0700 Subject: [PATCH 12/23] Adding a results browser tool --- tools/results_browser.py | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tools/results_browser.py diff --git a/tools/results_browser.py b/tools/results_browser.py new file mode 100644 index 00000000..5eced3bd --- /dev/null +++ b/tools/results_browser.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +import os +import argparse +import openai +import pinecone +from dotenv import load_dotenv + +load_dotenv() + +OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") +assert OPENAI_API_KEY, "OPENAI_API_KEY environment variable is missing from .env" + +PINECONE_API_KEY = os.getenv("PINECONE_API_KEY", "") +assert PINECONE_API_KEY, "PINECONE_API_KEY environment variable is missing from .env" + +PINECONE_ENVIRONMENT = os.getenv("PINECONE_ENVIRONMENT", "us-east1-gcp") +assert PINECONE_ENVIRONMENT, "PINECONE_ENVIRONMENT environment variable is missing from .env" + +# Table config +PINECONE_TABLE_NAME = os.getenv("TABLE_NAME", "") +assert PINECONE_TABLE_NAME, "TABLE_NAME environment variable is missing from .env" + +# Function to query records from the Pinecone index +def query_records(index, query, top_k=1000): + results = index.query(query, top_k=top_k, include_metadata=True) + return [f"{task.metadata['task']}:\n{task.metadata['result']}\n------------------" for task in results.matches] + +# Get embedding for the text +def get_ada_embedding(text): + text = text.replace("\n", " ") + return openai.Embedding.create(input=[text], model="text-embedding-ada-002")["data"][0]["embedding"] + +def main(): + # Parse command-line arguments + parser = argparse.ArgumentParser(description="Query Pinecone index using a string.") + parser.add_argument('objective', nargs='*', metavar='', help=''' + main objective description. Doesn\'t need to be quoted. + if not specified, get objective from environment. + ''', default=[os.getenv("OBJECTIVE", "")]) + args = parser.parse_args() + + # Initialize Pinecone + pinecone.init(api_key=PINECONE_API_KEY) + + # Connect to the objective index + index = pinecone.Index(PINECONE_TABLE_NAME) + + # Query records from the index + query = get_ada_embedding(' '.join(args.objective).strip()) + retrieved_tasks = query_records(index, query) + for r in retrieved_tasks: + print(r) + +if __name__ == "__main__": + main() From 8024290c62c73066b9678f22c16fa0bce07a29eb Mon Sep 17 00:00:00 2001 From: Franci Penov Date: Thu, 6 Apr 2023 18:57:17 -0700 Subject: [PATCH 13/23] Simple objective results browser --- tools/results_browser.py | 89 +++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/tools/results_browser.py b/tools/results_browser.py index 5eced3bd..028a6f19 100644 --- a/tools/results_browser.py +++ b/tools/results_browser.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 import os +import curses import argparse import openai import pinecone from dotenv import load_dotenv +import textwrap load_dotenv() @@ -23,14 +25,62 @@ # Function to query records from the Pinecone index def query_records(index, query, top_k=1000): results = index.query(query, top_k=top_k, include_metadata=True) - return [f"{task.metadata['task']}:\n{task.metadata['result']}\n------------------" for task in results.matches] + return [{"name": f"{task.metadata['task']}", "result": f"{task.metadata['result']}"} for task in results.matches] # Get embedding for the text def get_ada_embedding(text): - text = text.replace("\n", " ") return openai.Embedding.create(input=[text], model="text-embedding-ada-002")["data"][0]["embedding"] -def main(): +def draw_tasks(stdscr, tasks, scroll_pos, selected): + y = 0 + h, w = stdscr.getmaxyx() + for idx, task in enumerate(tasks[scroll_pos:], start=scroll_pos): + if y >= h: + break + task_name = f'{task["name"]}' + truncated_str = task_name[:w-1] + if idx == selected: + stdscr.addstr(y, 0, truncated_str, curses.A_REVERSE) + else: + stdscr.addstr(y, 0, truncated_str) + y += 1 + +def draw_result(stdscr, task): + task_name = f'Task: {task["name"]}' + task_result = f'Result: {task["result"]}' + + _, w = stdscr.getmaxyx() + task_name_wrapped = textwrap.wrap(task_name, width=w) + + for i, line in enumerate(task_name_wrapped): + stdscr.addstr(i, 0, line) + + y, _ = stdscr.getyx() + stdscr.addstr(y+1, 0, '------------------') + stdscr.addstr(y+2, 0, task_result) + +def draw_summary(stdscr, objective, tasks, start, num): + stdscr.box() + summary_text = f'{len(tasks)} tasks ({start}-{num}) | {objective}' + stdscr.addstr(1, 1, summary_text[:stdscr.getmaxyx()[1] - 2]) + +def main(stdscr): + # Initialize Pinecone + pinecone.init(api_key=PINECONE_API_KEY) + + # Connect to the objective index + index = pinecone.Index(PINECONE_TABLE_NAME) + + curses.curs_set(0) + stdscr.timeout(1000) + + h, w = stdscr.getmaxyx() + left_w = w // 2 + visible_lines = h - 3 + + scroll_pos = 0 + selected = 0 + # Parse command-line arguments parser = argparse.ArgumentParser(description="Query Pinecone index using a string.") parser.add_argument('objective', nargs='*', metavar='', help=''' @@ -39,17 +89,28 @@ def main(): ''', default=[os.getenv("OBJECTIVE", "")]) args = parser.parse_args() - # Initialize Pinecone - pinecone.init(api_key=PINECONE_API_KEY) + # Query records from the index + objective = ' '.join(args.objective).strip().replace("\n", " ") + retrieved_tasks = query_records(index, get_ada_embedding(objective)) - # Connect to the objective index - index = pinecone.Index(PINECONE_TABLE_NAME) + while True: + stdscr.clear() + draw_tasks(stdscr.subwin(h-3, left_w, 0, 0), retrieved_tasks, scroll_pos, selected) + draw_result(stdscr.subwin(h, w - left_w, 0, left_w), retrieved_tasks[selected]) + draw_summary(stdscr.subwin(3, left_w, h - 3, 0), objective, retrieved_tasks, scroll_pos+1, scroll_pos+h-3) - # Query records from the index - query = get_ada_embedding(' '.join(args.objective).strip()) - retrieved_tasks = query_records(index, query) - for r in retrieved_tasks: - print(r) + stdscr.refresh() + key = stdscr.getch() + + if key == ord('q') or key == 27: + break + elif key == curses.KEY_UP and selected > 0: + selected -= 1 + if selected < scroll_pos: + scroll_pos -= 1 + elif key == curses.KEY_DOWN and selected < len(retrieved_tasks) - 1: + selected += 1 + if selected - scroll_pos >= visible_lines: + scroll_pos += 1 -if __name__ == "__main__": - main() +curses.wrapper(main) \ No newline at end of file From 28af2efc83e2d47b97a2529db473d66737ab9547 Mon Sep 17 00:00:00 2001 From: MalikMAlna Date: Fri, 7 Apr 2023 14:09:11 -0400 Subject: [PATCH 14/23] Last minute tweaks from sync --- babyagi.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/babyagi.py b/babyagi.py index 14a11732..f6498827 100755 --- a/babyagi.py +++ b/babyagi.py @@ -51,11 +51,7 @@ assert YOUR_FIRST_TASK, "FIRST_TASK environment variable is missing from .env" # Print OBJECTIVE -<<<<<<< HEAD print("\033[96m\033[1m" + "\n*****OBJECTIVE*****\n" + "\033[0m\033[0m") -======= -print("\033[96m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m") ->>>>>>> 8a37c69 (Last minute tweaks from sync) print(OBJECTIVE) # Configure OpenAI and Pinecone From ee4b5ec1da602b9e1eabe5ea34fefaa769539013 Mon Sep 17 00:00:00 2001 From: MalikMAlna Date: Fri, 7 Apr 2023 14:10:38 -0400 Subject: [PATCH 15/23] Formatting with spacing --- babyagi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/babyagi.py b/babyagi.py index f6498827..e761ea01 100755 --- a/babyagi.py +++ b/babyagi.py @@ -164,7 +164,7 @@ def context_agent(query: str, n: int): while True: if task_list: # Print the task list - print("\033[95m\033[1m"+"\n*****TASK LIST*****\n"+"\033[0m\033[0m") + print("\033[95m\033[1m" + "\n*****TASK LIST*****\n" + "\033[0m\033[0m") for t in task_list: print(str(t['task_id']) + ": " + t['task_name']) @@ -176,7 +176,7 @@ def context_agent(query: str, n: int): # Send to execution function to complete the task based on the context result = execution_agent(OBJECTIVE, task["task_name"]) this_task_id = int(task["task_id"]) - print("\033[93m\033[1m"+"\n*****TASK RESULT*****\n"+"\033[0m\033[0m") + print("\033[93m\033[1m" + "\n*****TASK RESULT*****\n" + "\033[0m\033[0m") print(result) # Step 2: Enrich result and store in Pinecone From 3a98059286f4a72abf4dc9475f7a6ed4acbc9a99 Mon Sep 17 00:00:00 2001 From: MalikMAlna Date: Fri, 7 Apr 2023 14:12:04 -0400 Subject: [PATCH 16/23] Adding venv/ to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bc8f2233..30742e03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .env* .idea +venv/ From aeb651bbb27c37f6259641fb13cd77ab847a1825 Mon Sep 17 00:00:00 2001 From: Thomas <126921480+tmcpa@users.noreply.github.com> Date: Fri, 7 Apr 2023 11:17:56 -0700 Subject: [PATCH 17/23] Remove default pinecone env. --- babyagi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babyagi.py b/babyagi.py index 9f794a57..de80b412 100755 --- a/babyagi.py +++ b/babyagi.py @@ -37,7 +37,7 @@ PINECONE_API_KEY = os.getenv("PINECONE_API_KEY", "") assert PINECONE_API_KEY, "PINECONE_API_KEY environment variable is missing from .env" -PINECONE_ENVIRONMENT = os.getenv("PINECONE_ENVIRONMENT", "us-east1-gcp") +PINECONE_ENVIRONMENT = os.getenv("PINECONE_ENVIRONMENT", "") assert PINECONE_ENVIRONMENT, "PINECONE_ENVIRONMENT environment variable is missing from .env" # Table config From 41cfa942d8ec9f003209ca3570845aca0c95d40e Mon Sep 17 00:00:00 2001 From: Yohei Nakajima Date: Fri, 7 Apr 2023 12:29:01 -0700 Subject: [PATCH 18/23] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..a43bb23b --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +babyagi.org \ No newline at end of file From 7ef516d40d881254e979d8b4aa350e06c1a4edaa Mon Sep 17 00:00:00 2001 From: Franci Penov Date: Wed, 5 Apr 2023 21:48:17 -0700 Subject: [PATCH 19/23] Adding a mod to do more fancy args parsing --- .env.example | 10 ++++++- .gitignore | 11 +++++++- README.md | 9 +++--- argsparser.py | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ babyagi.py | 62 ++++++++++++++++++---------------------- 5 files changed, 128 insertions(+), 42 deletions(-) create mode 100644 argsparser.py diff --git a/.env.example b/.env.example index 3f7871fd..96e1969e 100644 --- a/.env.example +++ b/.env.example @@ -9,4 +9,12 @@ TABLE_NAME=test-table # PROJECT CONFIG OBJECTIVE=Solve world hunger -FIRST_TASK=Develop a task list +# For backwards compatibility +# FIRST_TASK can be used instead of INITIAL_TASK +INITIAL_TASK=Develop a task list + +# Extensions +# List additional extensions to load +DOTENV_EXTENSIONS= +# Set to true to enable command line args support +ENABLE_COMMAND_LINE_ARGS=false diff --git a/.gitignore b/.gitignore index bc8f2233..c56f4fd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,11 @@ +__pycache__/ +*.py[cod] +*$py.class + .env* -.idea +env/ +.venv +venv/ + +.vscode/ +.idea/ diff --git a/README.md b/README.md index c7c0b55b..23a9734b 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,12 @@ To use the script, you will need to follow these steps: 3. Set your OpenAI and Pinecone API keys in the OPENAI_API_KEY, OPENAPI_API_MODEL, and PINECONE_API_KEY variables. 4. Set the Pinecone environment in the PINECONE_ENVIRONMENT variable. 5. Set the name of the table where the task results will be stored in the TABLE_NAME variable. -6. Set the objective of the task management system in the OBJECTIVE variable. Alternatively you can pass it to the script as a quote argument. -``` -./babyagi.py [""] -``` -7. Set the first task of the system in the FIRST_TASK variable. +6. (Optional) Set the objective of the task management system in the OBJECTIVE variable. +7. (Optional) Set the first task of the system in the INITIAL_TASK variable. 8. Run the script. +All optional values above can also be specified on the command line. + # Warning This script is designed to be run continuously as part of a task management system. Running this script continuously can result in high API usage, so please use it responsibly. Additionally, the script requires the OpenAI and Pinecone APIs to be set up correctly, so make sure you have set up the APIs before running the script. diff --git a/argsparser.py b/argsparser.py new file mode 100644 index 00000000..bfa4e138 --- /dev/null +++ b/argsparser.py @@ -0,0 +1,78 @@ +import os +import sys +import argparse +from dotenv import load_dotenv + +def load_dotenv_extensions(dotenv_files): + for dotenv_file in dotenv_files: + load_dotenv(dotenv_file) + +# Extract the env filenames in the -e flag only +# Ignore any other arguments +def parse_dotenv_extensions(argv): + env_argv = [] + if '-e' in argv: + tmp_argv = argv[argv.index('-e') + 1:] + parsed_args = [] + for arg in tmp_argv: + if arg.startswith('-'): + break + parsed_args.append(arg) + env_argv = ['-e'] + parsed_args + + parser = argparse.ArgumentParser() + parser.add_argument('-e', '--env', nargs='+', help=''' + filenames for additional env variables to load + ''', default=os.getenv("DOTENV_EXTENSIONS", "").split(' ')) + + return parser.parse_args(env_argv).env + +def parse_arguments(): + # Check if we need to load any additional env files + # This allows us to override the default .env file + # and update the default values for the command line arguments + load_dotenv_extensions(parse_dotenv_extensions(sys.argv)) + + # Now parse the full command line arguments + parser = argparse.ArgumentParser( + add_help=False, + ) + parser.add_argument('objective', nargs='*', metavar='', help=''' + main objective description. Doesn\'t need to be quoted. + if not specified, get objective from environment. + ''', default=[os.getenv("OBJECTIVE", "")]) + parser.add_argument('-t', '--task', metavar='', help=''' + initial task description. must be quoted. + if not specified, get initial_task from environment. + ''', default=os.getenv("INITIAL_TASK", os.getenv("FIRST_TASK", ""))) + parser.add_argument('-4', '--gpt-4', dest='openai_api_model', action='store_const', const="gpt-4", help=''' + use GPT-4 instead of the default GPT-3 model. + ''', default=os.getenv("OPENAI_API_MODEL", "gpt-3.5-turbo")) + # This will parse -e again, which we want, because we need + # to load those in the main file later as well + parser.add_argument('-e', '--env', nargs='+', help=''' + filenames for additional env variables to load + ''', default=os.getenv("DOTENV_EXTENSIONS", "")) + parser.add_argument('-h', '-?', '--help', action='help', help=''' + show this help message and exit + ''') + + args = parser.parse_args() + + openai_api_model = args.openai_api_model + + dotenv_extensions = args.env + + objective = ' '.join(args.objective).strip() + if not objective: + print("\033[91m\033[1m"+"No objective specified or found in environment.\n"+"\033[0m\033[0m") + parser.print_help() + parser.exit() + + initial_task = args.task + if not initial_task: + print("\033[91m\033[1m"+"No initial task specified or found in environment.\n"+"\033[0m\033[0m") + parser.print_help() + parser.exit() + + return objective, initial_task, openai_api_model, dotenv_extensions \ No newline at end of file diff --git a/babyagi.py b/babyagi.py index 9f794a57..5c13c961 100755 --- a/babyagi.py +++ b/babyagi.py @@ -1,59 +1,51 @@ #!/usr/bin/env python3 -import argparse import os +import time import openai import pinecone -import time -import sys from collections import deque from typing import Dict, List from dotenv import load_dotenv -import os - -# Parse arguments for optional extensions -parser = argparse.ArgumentParser() -parser.add_argument('-e', '--env', nargs='+', help='filenames for env') -args = parser.parse_args() # Load default environment variables (.env) load_dotenv() -# Set environment variables for optional extensions -if args.env: - for env_path in args.env: - load_dotenv(env_path) - print('Using env from file:', env_path) - # Set API Keys OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") assert OPENAI_API_KEY, "OPENAI_API_KEY environment variable is missing from .env" OPENAI_API_MODEL = os.getenv("OPENAI_API_MODEL", "gpt-3.5-turbo") -assert OPENAI_API_MODEL, "OPENAI_API_MODEL environment variable is missing from .env" - -if "gpt-4" in OPENAI_API_MODEL.lower(): - print(f"\033[91m\033[1m"+"\n*****USING GPT-4. POTENTIALLY EXPENSIVE. MONITOR YOUR COSTS*****"+"\033[0m\033[0m") PINECONE_API_KEY = os.getenv("PINECONE_API_KEY", "") assert PINECONE_API_KEY, "PINECONE_API_KEY environment variable is missing from .env" PINECONE_ENVIRONMENT = os.getenv("PINECONE_ENVIRONMENT", "us-east1-gcp") -assert PINECONE_ENVIRONMENT, "PINECONE_ENVIRONMENT environment variable is missing from .env" # Table config YOUR_TABLE_NAME = os.getenv("TABLE_NAME", "") assert YOUR_TABLE_NAME, "TABLE_NAME environment variable is missing from .env" -# Project config +# Run configuration +DOTENV_EXTENSIONS = os.getenv("DOTENV_EXTENSIONS", "").split(' ') + +# Goal configuation OBJECTIVE = os.getenv("OBJECTIVE", "") -assert OBJECTIVE, "OBJECTIVE environment variable is missing from .env" +INITIAL_TASK = os.getenv("INITIAL_TASK", os.getenv("FIRST_TASK", "")) + +ENABLE_COMMAND_LINE_ARGS = os.getenv("ENABLE_COMMAND_LINE_ARGS", "false").lower() == "true" +if ENABLE_COMMAND_LINE_ARGS: + from argsparser import parse_arguments, load_dotenv_extensions + OBJECTIVE, INITIAL_TASK, OPENAI_API_MODEL, DOTENV_EXTENSIONS = parse_arguments() + # Load environment variables for optional extensions + load_dotenv_extensions(DOTENV_EXTENSIONS) + +if "gpt-4" in OPENAI_API_MODEL.lower(): + print("\033[91m\033[1m"+"\n*****USING GPT-4. POTENTIALLY EXPENSIVE. MONITOR YOUR COSTS*****"+"\033[0m\033[0m") -YOUR_FIRST_TASK = os.getenv("FIRST_TASK", "") -assert YOUR_FIRST_TASK, "FIRST_TASK environment variable is missing from .env" +print("\033[94m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m") +print(f"{OBJECTIVE}") -#Print OBJECTIVE -print("\033[96m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m") -print(OBJECTIVE) +print("\033[93m\033[1m"+"\nInitial task:"+"\033[0m\033[0m"+f" {INITIAL_TASK}") # Configure OpenAI and Pinecone openai.api_key = OPENAI_API_KEY @@ -148,7 +140,7 @@ def context_agent(query: str, n: int): # Add the first task first_task = { "task_id": 1, - "task_name": YOUR_FIRST_TASK + "task_name": INITIAL_TASK } add_task(first_task) @@ -178,13 +170,13 @@ def context_agent(query: str, n: int): vector = enriched_result['data'] # extract the actual result from the dictionary index.upsert([(result_id, get_ada_embedding(vector),{"task":task['task_name'],"result":result})]) - # Step 3: Create new tasks and reprioritize task list - new_tasks = task_creation_agent(OBJECTIVE,enriched_result, task["task_name"], [t["task_name"] for t in task_list]) + # Step 3: Create new tasks and reprioritize task list + new_tasks = task_creation_agent(OBJECTIVE,enriched_result, task["task_name"], [t["task_name"] for t in task_list]) - for new_task in new_tasks: - task_id_counter += 1 - new_task.update({"task_id": task_id_counter}) - add_task(new_task) - prioritization_agent(this_task_id) + for new_task in new_tasks: + task_id_counter += 1 + new_task.update({"task_id": task_id_counter}) + add_task(new_task) + prioritization_agent(this_task_id) time.sleep(1) # Sleep before checking the task list again From 5c1f454a6af8890b4abccb0f7a4c6fc71e01481c Mon Sep 17 00:00:00 2001 From: Franci Penov Date: Thu, 6 Apr 2023 17:05:07 -0700 Subject: [PATCH 20/23] Fixing a typo in the model arg action --- babyagi.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/babyagi.py b/babyagi.py index 5c13c961..7c12c96b 100755 --- a/babyagi.py +++ b/babyagi.py @@ -25,20 +25,27 @@ YOUR_TABLE_NAME = os.getenv("TABLE_NAME", "") assert YOUR_TABLE_NAME, "TABLE_NAME environment variable is missing from .env" -# Run configuration -DOTENV_EXTENSIONS = os.getenv("DOTENV_EXTENSIONS", "").split(' ') - # Goal configuation OBJECTIVE = os.getenv("OBJECTIVE", "") INITIAL_TASK = os.getenv("INITIAL_TASK", os.getenv("FIRST_TASK", "")) +DOTENV_EXTENSIONS = os.getenv("DOTENV_EXTENSIONS", "").split(' ') + +# Command line arguments extension +# Can override any of the above environment variables ENABLE_COMMAND_LINE_ARGS = os.getenv("ENABLE_COMMAND_LINE_ARGS", "false").lower() == "true" if ENABLE_COMMAND_LINE_ARGS: from argsparser import parse_arguments, load_dotenv_extensions OBJECTIVE, INITIAL_TASK, OPENAI_API_MODEL, DOTENV_EXTENSIONS = parse_arguments() - # Load environment variables for optional extensions + +# Load additional environment variables for enabled extensions +if DOTENV_EXTENSIONS: load_dotenv_extensions(DOTENV_EXTENSIONS) +# TODO: There's still work to be done here to enable people to get +# defaults from dotenv extensions # but also provide command line +# arguments to override them + if "gpt-4" in OPENAI_API_MODEL.lower(): print("\033[91m\033[1m"+"\n*****USING GPT-4. POTENTIALLY EXPENSIVE. MONITOR YOUR COSTS*****"+"\033[0m\033[0m") From 70260044e42cd88965b9c5f92526c3c266896700 Mon Sep 17 00:00:00 2001 From: Franci Penov Date: Fri, 7 Apr 2023 17:06:42 -0700 Subject: [PATCH 21/23] Splitting the dotenv extension from the argparse extension --- babyagi.py | 3 ++- argsparser.py => extensions/argparseext.py | 14 ++++++-------- extensions/dotenvext.py | 5 +++++ 3 files changed, 13 insertions(+), 9 deletions(-) rename argsparser.py => extensions/argparseext.py (88%) create mode 100644 extensions/dotenvext.py diff --git a/babyagi.py b/babyagi.py index 7c12c96b..05c30be7 100755 --- a/babyagi.py +++ b/babyagi.py @@ -35,11 +35,12 @@ # Can override any of the above environment variables ENABLE_COMMAND_LINE_ARGS = os.getenv("ENABLE_COMMAND_LINE_ARGS", "false").lower() == "true" if ENABLE_COMMAND_LINE_ARGS: - from argsparser import parse_arguments, load_dotenv_extensions + from extensions.argparseext import parse_arguments OBJECTIVE, INITIAL_TASK, OPENAI_API_MODEL, DOTENV_EXTENSIONS = parse_arguments() # Load additional environment variables for enabled extensions if DOTENV_EXTENSIONS: + from extensions.dotenvext import load_dotenv_extensions load_dotenv_extensions(DOTENV_EXTENSIONS) # TODO: There's still work to be done here to enable people to get diff --git a/argsparser.py b/extensions/argparseext.py similarity index 88% rename from argsparser.py rename to extensions/argparseext.py index bfa4e138..49d8266b 100644 --- a/argsparser.py +++ b/extensions/argparseext.py @@ -1,11 +1,6 @@ import os import sys import argparse -from dotenv import load_dotenv - -def load_dotenv_extensions(dotenv_files): - for dotenv_file in dotenv_files: - load_dotenv(dotenv_file) # Extract the env filenames in the -e flag only # Ignore any other arguments @@ -28,10 +23,13 @@ def parse_dotenv_extensions(argv): return parser.parse_args(env_argv).env def parse_arguments(): + dotenv_extensions = parse_dotenv_extensions(sys.argv) # Check if we need to load any additional env files # This allows us to override the default .env file - # and update the default values for the command line arguments - load_dotenv_extensions(parse_dotenv_extensions(sys.argv)) + # and update the default values for any command line arguments + if dotenv_extensions: + from extensions.dotenvext import load_dotenv_extensions + load_dotenv_extensions(parse_dotenv_extensions(sys.argv)) # Now parse the full command line arguments parser = argparse.ArgumentParser( @@ -52,7 +50,7 @@ def parse_arguments(): # to load those in the main file later as well parser.add_argument('-e', '--env', nargs='+', help=''' filenames for additional env variables to load - ''', default=os.getenv("DOTENV_EXTENSIONS", "")) + ''', default=os.getenv("DOTENV_EXTENSIONS", "").split(' ')) parser.add_argument('-h', '-?', '--help', action='help', help=''' show this help message and exit ''') diff --git a/extensions/dotenvext.py b/extensions/dotenvext.py new file mode 100644 index 00000000..0db80aea --- /dev/null +++ b/extensions/dotenvext.py @@ -0,0 +1,5 @@ +from dotenv import load_dotenv + +def load_dotenv_extensions(dotenv_files): + for dotenv_file in dotenv_files: + load_dotenv(dotenv_file) From c9c27d61272d6ca7148157e81845a6850858987f Mon Sep 17 00:00:00 2001 From: Franci Penov Date: Fri, 7 Apr 2023 17:09:55 -0700 Subject: [PATCH 22/23] Some clarifications around .end files usage --- .env.example | 2 +- .gitignore | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 96e1969e..d8415134 100644 --- a/.env.example +++ b/.env.example @@ -14,7 +14,7 @@ OBJECTIVE=Solve world hunger INITIAL_TASK=Develop a task list # Extensions -# List additional extensions to load +# List additional extensions to load (except .env.example!) DOTENV_EXTENSIONS= # Set to true to enable command line args support ENABLE_COMMAND_LINE_ARGS=false diff --git a/.gitignore b/.gitignore index c56f4fd5..37a4938c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ __pycache__/ *.py[cod] *$py.class -.env* +.env +.env.* env/ .venv venv/ From 87c8965e7ecc09de3f06e4ec062af755dc7ba33b Mon Sep 17 00:00:00 2001 From: madan ankapura Date: Fri, 7 Apr 2023 18:48:27 -0700 Subject: [PATCH 23/23] Update openai to 0.27.4 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f7778cbb..78b6f719 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -openai==0.27.2 +openai==0.27.4 pinecone-client==2.2.1 python-dotenv==1.0.0 argparse==1.4.0