From a2a84ef22eab7697e2c2f7f0921cbfc0acccdd7d Mon Sep 17 00:00:00 2001 From: jad2121 Date: Sat, 3 Feb 2024 10:37:19 -0500 Subject: [PATCH] added --setup --- client/__pycache__/utils.cpython-38.pyc | Bin 4825 -> 0 bytes client/fabric | 18 ++--- client/requirements.txt | 3 +- client/utils.py | 100 +++++++++++++++++------- 4 files changed, 84 insertions(+), 37 deletions(-) delete mode 100644 client/__pycache__/utils.cpython-38.pyc diff --git a/client/__pycache__/utils.cpython-38.pyc b/client/__pycache__/utils.cpython-38.pyc deleted file mode 100644 index ee1eba8eb36db2e24d76bb3eabc75b69a0096fd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4825 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 diff --git a/client/fabric b/client/fabric index 6176fc2..e48e3eb 100755 --- a/client/fabric +++ b/client/fabric @@ -1,6 +1,6 @@ #!/Users/daniel/Cloud/Development/fabric/client/.venv/bin/python3 -from utils import Standalone, Update +from utils import Standalone, Update, Setup import argparse import sys import os @@ -34,9 +34,11 @@ if __name__ == "__main__": parser.add_argument( "--list", "-l", help="List available patterns", action="store_true" ) - parser.add_argument("--update", "-u", help="Update patterns", action="store_true") + parser.add_argument( + "--update", "-u", help="Update patterns", action="store_true") parser.add_argument("--pattern", "-p", help="The pattern (prompt) to use") - parser.add_argument("--apikey", "-a", help="Add an OpenAI key") + parser.add_argument( + "--setup", help="Set up your fabric instance", action="store_true") args = parser.parse_args() home_holder = os.path.expanduser("~") @@ -45,13 +47,11 @@ if __name__ == "__main__": env_file = os.path.join(config, ".env") if not os.path.exists(config): os.makedirs(config) - if args.apikey: - with open(env_file, "w") as f: - f.write(f"OPENAI_API_KEY={args.apikey}") - print(f"OpenAI API key set to {args.apikey}") + if args.setup: + Setup().run() sys.exit() - if not os.path.exists(env_file): - print("No API key found. Use the --apikey option to set the key") + if not os.path.exists(env_file) or not os.path.exists(config_patterns_directory): + print("Please run --setup to set up your API key and download patterns.") sys.exit() if not os.path.exists(config_patterns_directory): Update() diff --git a/client/requirements.txt b/client/requirements.txt index 92914af..46e7ebe 100644 --- a/client/requirements.txt +++ b/client/requirements.txt @@ -13,4 +13,5 @@ flask-socketio flask-sock gunicorn gevent -httpx \ No newline at end of file +httpx +tqdm \ No newline at end of file diff --git a/client/utils.py b/client/utils.py index e8fbe9b..53ba6f8 100644 --- a/client/utils.py +++ b/client/utils.py @@ -4,6 +4,8 @@ from openai import OpenAI import pyperclip import sys from dotenv import load_dotenv +from requests.exceptions import HTTPError +from tqdm import tqdm current_directory = os.path.dirname(os.path.realpath(__file__)) config_directory = os.path.expanduser("~/.config/fabric") @@ -12,7 +14,8 @@ env_file = os.path.join(config_directory, ".env") class Standalone: def __init__(self, args, pattern="", env_file="~/.config/fabric/.env"): - env_file = os.path.expanduser(env_file) # Expand the tilde to the full path + # Expand the tilde to the full path + env_file = os.path.expanduser(env_file) load_dotenv(env_file) try: apikey = os.environ["OPENAI_API_KEY"] @@ -116,43 +119,86 @@ class Standalone: class Update: def __init__(self): - # Initialize with the root API URL self.root_api_url = "https://api.github.com/repos/danielmiessler/fabric/contents/patterns?ref=main" self.config_directory = os.path.expanduser("~/.config/fabric") - self.pattern_directory = os.path.join(self.config_directory, "patterns") - # Ensure local directory exists + self.pattern_directory = os.path.join( + self.config_directory, "patterns") os.makedirs(self.pattern_directory, exist_ok=True) - self.get_github_directory_contents(self.root_api_url, self.pattern_directory) + self.update_patterns() # Call the update process from a method. + + def update_patterns(self): + try: + self.progress_bar = tqdm(desc="Downloading files", unit="file") + self.get_github_directory_contents( + self.root_api_url, self.pattern_directory) + # Close progress bar on success before printing the message. + self.progress_bar.close() + except HTTPError as e: + # Ensure progress bar is closed on HTTPError as well. + self.progress_bar.close() + if e.response.status_code == 403: + print("GitHub API rate limit exceeded. Please wait before trying again.") + sys.exit() + else: + print(f"Failed to download patterns due to an HTTP error: {e}") + sys.exit() # Exit after handling the error. def download_file(self, url, local_path): - """ - Download a file from a URL to a local path. - """ - response = requests.get(url) - response.raise_for_status() # This will raise an exception for HTTP error codes - with open(local_path, "wb") as f: - f.write(response.content) + try: + response = requests.get(url) + response.raise_for_status() + with open(local_path, "wb") as f: + f.write(response.content) + self.progress_bar.update(1) + except HTTPError as e: + print(f"Failed to download file {url}. HTTP error: {e}") + sys.exit() def process_item(self, item, local_dir): - """ - Process an individual item, downloading if it's a file, or processing further if it's a directory. - """ if item["type"] == "file": - print(f"Downloading file: {item['name']} to {local_dir}") - self.download_file( - item["download_url"], os.path.join(local_dir, item["name"]) - ) + self.download_file(item["download_url"], + os.path.join(local_dir, item["name"])) elif item["type"] == "dir": new_dir = os.path.join(local_dir, item["name"]) os.makedirs(new_dir, exist_ok=True) self.get_github_directory_contents(item["url"], new_dir) def get_github_directory_contents(self, api_url, local_dir): - """ - Fetches the contents of a directory in a GitHub repository and downloads files, recursively handling directories. - """ - response = requests.get(api_url) - response.raise_for_status() # This will raise an exception for HTTP error codes - jsonList = response.json() - for item in jsonList: - self.process_item(item, local_dir) + try: + response = requests.get(api_url) + response.raise_for_status() + jsonList = response.json() + for item in jsonList: + self.process_item(item, local_dir) + except HTTPError as e: + if e.response.status_code == 403: + print("GitHub API rate limit exceeded. Please wait before trying again.") + self.progress_bar.close() # Ensure the progress bar is cleaned up properly + else: + print( + f"Failed to fetch directory contents due to an HTTP error: {e}") + + +class Setup: + def __init__(self): + self.config_directory = os.path.expanduser("~/.config/fabric") + self.pattern_directory = os.path.join( + self.config_directory, "patterns") + os.makedirs(self.pattern_directory, exist_ok=True) + self.env_file = os.path.join(self.config_directory, ".env") + + def api_key(self, api_key): + if not os.path.exists(self.env_file): + with open(self.env_file, "w") as f: + f.write(f"OPENAI_API_KEY={api_key}") + print(f"OpenAI API key set to {api_key}") + + def patterns(self): + Update() + sys.exit() + + def run(self): + print("Welcome to Fabric. Let's get started.") + apikey = input("Please enter your OpenAI API key\n") + self.api_key(apikey.strip()) + self.patterns()