diff --git a/README.md b/README.md index 23a9734b..65993e55 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ This README will cover the following: * [How to use the script](#how-to-use) +* [Suported Models](#supported-models) + * [Warning about running the script continuously](#continous-script-warning) # How It Works The script works by running an infinite loop that does the following steps: @@ -42,6 +44,18 @@ To use the script, you will need to follow these steps: All optional values above can also be specified on the command line. +# Supported Models + +This script works with all OpenAI models, as well as Llama through Llama.cpp. Default model is **gpt-3.5-turbo**. To use a different model, specify it through OPENAI_API_MODEL or use the command line. + +## Llama + +Download the latest version of [Llama.cpp](https://github.com/ggerganov/llama.cpp) and follow instructions to make it. You will also need the Llama model weights. + + - **Under no circumstances share IPFS, magnet links, or any other links to model downloads anywhere in this respository, including in issues, discussions or pull requests. They will be immediately deleted.** + +After that link `llama/main` to llama.cpp/main and `models` to the folder where you have the Llama model weights. Then run the script with `OPENAI_API_MODEL=llama` or `-l` argument. + # 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/babyagi.py b/babyagi.py index a0ffdf0e..5b342076 100755 --- a/babyagi.py +++ b/babyagi.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import subprocess import time from collections import deque from typing import Dict, List @@ -118,7 +119,12 @@ def openai_call( ): while True: try: - if not model.startswith("gpt-"): + if model.startswith("llama"): + # Spawn a subprocess to run llama.cpp + cmd = cmd = ["llama/main", "-p", prompt] + result = subprocess.run(cmd, shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE, text=True) + return result.stdout.strip() + elif not model.startswith("gpt-"): # Use completion API response = openai.Completion.create( engine=model, @@ -130,11 +136,6 @@ def openai_call( presence_penalty=0, ) return response.choices[0].text.strip() - elif model.startswith("llama"): - # Spawn a subprocess to run llama.cpp - cmd = cmd = ["llama/main", "-p", prompt] - result = subprocess.run(cmd, shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE, text=True) - return result.stdout.strip() else: # Use chat completion API messages = [{"role": "user", "content": prompt}] diff --git a/extensions/argparseext.py b/extensions/argparseext.py index 49d8266b..f6b61be2 100644 --- a/extensions/argparseext.py +++ b/extensions/argparseext.py @@ -43,9 +43,13 @@ def parse_arguments(): 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. + group = parser.add_mutually_exclusive_group() + group.add_argument('-4', '--gpt-4', dest='openai_api_model', action='store_const', const="gpt-4", help=''' + use GPT-4 instead of the default model. ''', default=os.getenv("OPENAI_API_MODEL", "gpt-3.5-turbo")) + group.add_argument('-l', '--llama', dest='openai_api_model', action='store_const', const="llama", help=''' + use LLaMa instead of the default model. Requires llama.cpp. + ''') # 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=''' diff --git a/extensions/argsparser.py b/extensions/argsparser.py deleted file mode 100644 index 809a94fb..00000000 --- a/extensions/argsparser.py +++ /dev/null @@ -1,102 +0,0 @@ -import os -import argparse -import importlib - -def parse_arguments(): - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=""" -cooperative mode enables multiple instances of babyagi to work towards the same objective. - * none - (default) no cooperation, each instance works on its own list of tasks - * local - local machine cooperation - uses ray to share the list of tasks for an objective - * distributed - distributed cooperation (not implemented yet) - uses pinecone to share the list of tasks for an objective - -examples: - * start solving world hunger by creating initial list of tasks using GPT-4: - %(prog)s -m local -t "Create initial list of tasks" -4 Solve world hunger - * join the work on solving world hunger using GPT-3: - %(prog)s -m local -j Solve world hunger -""" - ) - 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('-n', '--name', required=False, help=''' - babyagi instance name. - if not specified, get baby_name from environment. - ''', default=os.getenv("BABY_NAME", "BabyAGI")) - parser.add_argument('-m', '--mode', choices=['n', 'none', 'l', 'local', 'd', 'distributed'], help=''' - cooperative mode type - ''', default='none') - group = parser.add_mutually_exclusive_group() - group.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", ""))) - group.add_argument('-j', '--join', action='store_true', help=''' - join an existing objective. - install cooperative requirements. - ''') - group2 = parser.add_mutually_exclusive_group() - group2.add_argument('-4', '--gpt-4', dest='use_gpt4', action='store_true', help=''' - use GPT-4 instead of GPT-3 - ''') - group2.add_argument('-l', '--llama', dest='use_llama', action='store_true', help=''' - use LLaMa instead of GPT-3 - ''') - parser.add_argument('-h', '-?', '--help', action='help', help=''' - show this help message and exit - ''') - - args = parser.parse_args() - - baby_name = args.name - if not baby_name: - print("\033[91m\033[1m"+"BabyAGI instance name missing\n"+"\033[0m\033[0m") - parser.print_help() - parser.exit() - - use_gpt4 = args.use_gpt4 - use_llama = args.use_llama - - def can_import(module_name): - try: - importlib.import_module(module_name) - return True - except ImportError: - return False - - module_name = "ray" - cooperative_mode = args.mode - if cooperative_mode in ['l', 'local'] and not can_import(module_name): - print("\033[91m\033[1m"+f"Local cooperative mode requires package {module_name}\nInstall: pip install -r requirements-cooperative.txt\n"+"\033[0m\033[0m") - parser.print_help() - parser.exit() - elif cooperative_mode in ['d', 'distributed']: - print("\033[91m\033[1m"+"Distributed cooperative mode is not implemented yet\n"+"\033[0m\033[0m") - parser.print_help() - parser.exit() - - join_existing_objective = args.join - if join_existing_objective and cooperative_mode in ['n', 'none']: - print("\033[91m\033[1m"+f"Joining existing objective requires local or distributed cooperative mode\n"+"\033[0m\033[0m") - parser.print_help() - parser.exit() - - 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 and not join_existing_objective: - 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, use_gpt4, use_llama, baby_name, cooperative_mode, join_existing_objective \ No newline at end of file diff --git a/extensions/ray_objectives.py b/extensions/ray_objectives.py deleted file mode 100644 index 7fcd037f..00000000 --- a/extensions/ray_objectives.py +++ /dev/null @@ -1,41 +0,0 @@ -import logging -import ray -from collections import deque - -ACTOR_NAME="BabyAGI Objectives" - -try: - ray.init(address="auto", namespace="babyagi", logging_level=logging.FATAL, ignore_reinit_error=True) -except: - ray.init(namespace="babyagi", logging_level=logging.FATAL, ignore_reinit_error=True) - -@ray.remote -class CooperativeObjectivesListStorageActor: - def __init__(self): - self.objectives = deque([]) - - def append(self, objective: str): - if not objective in self.objectives: - self.objectives.append(objective) - - def is_empty(self): - return False if self.objectives else True - - def get_objective_names(self): - return [t for t in self.objectives] - -class CooperativeObjectivesListStorage: - def __init__(self): - try: - self.actor = ray.get_actor(name=ACTOR_NAME, namespace="babyagi") - except ValueError: - self.actor = CooperativeObjectivesListStorageActor.options(name=ACTOR_NAME, namespace="babyagi", lifetime="detached").remote() - - def append(self, objective: str): - self.actor.append.remote(objective) - - def is_empty(self): - return ray.get(self.actor.is_empty.remote()) - - def get_objective_names(self): - return ray.get(self.actor.get_objective_names.remote()) diff --git a/extensions/ray_tasks.py b/extensions/ray_tasks.py deleted file mode 100644 index ba49b510..00000000 --- a/extensions/ray_tasks.py +++ /dev/null @@ -1,69 +0,0 @@ -import sys -import logging -import ray -from collections import deque -from typing import Dict, List - -from pathlib import Path -sys.path.append(str(Path(__file__).resolve().parent.parent)) -from extensions.ray_objectives import CooperativeObjectivesListStorage - -try: - ray.init(address="auto", namespace="babyagi", logging_level=logging.FATAL, ignore_reinit_error=True) -except: - ray.init(namespace="babyagi", logging_level=logging.FATAL, ignore_reinit_error=True) - -@ray.remote -class CooperativeTaskListStorageActor: - def __init__(self): - self.tasks = deque([]) - self.task_id_counter = 0 - - def append(self, task: Dict): - self.tasks.append(task) - - def replace(self, tasks: List[Dict]): - self.tasks = deque(tasks) - - def popleft(self): - return self.tasks.popleft() - - def is_empty(self): - return False if self.tasks else True - - def next_task_id(self): - self.task_id_counter += 1 - return self.task_id_counter - - def get_task_names(self): - return [t["task_name"] for t in self.tasks] - -class CooperativeTaskListStorage: - def __init__(self, name: str): - self.name = name - - try: - self.actor = ray.get_actor(name=self.name, namespace="babyagi") - except ValueError: - self.actor = CooperativeTaskListStorageActor.options(name=self.name, namespace="babyagi", lifetime="detached").remote() - - objectives = CooperativeObjectivesListStorage() - objectives.append(self.name) - - def append(self, task: Dict): - self.actor.append.remote(task) - - def replace(self, tasks: List[Dict]): - self.actor.replace.remote(tasks) - - def popleft(self): - return ray.get(self.actor.popleft.remote()) - - def is_empty(self): - return ray.get(self.actor.is_empty.remote()) - - def next_task_id(self): - return ray.get(self.actor.next_task_id.remote()) - - def get_task_names(self): - return ray.get(self.actor.get_task_names.remote())