Browse Source

Updating the readme.

pull/33/head
Daniel Miessler 1 year ago
parent
commit
c3e80f12b6
  1. 14
      README.md
  2. 54
      client/fabric
  3. 65
      client/utils.py

14
README.md

@ -22,9 +22,13 @@
Since the start of 2023 and GenAI we've seen a massive number of AI applications for accomplishing tasks. It's powerful, but **it's not easy to integrate this functionality into our lives.** Since the start of 2023 and GenAI we've seen a massive number of AI applications for accomplishing tasks. It's powerful, but **it's not easy to integrate this functionality into our lives.**
_In other words, AI doesn't have a capabilities problem—it has an **integration** problem._ ```markdown
<p align="center">
<h4></h4>_In other words, AI doesn't have a capabilities problem—it has an **integration** problem._</h4>
</p>
```
Fabric was created to address that problem by allowing everyone to leverage AI throughout our life and work. Fabric was created to address this by enabling everyone to granularly apply AI to everyday challenges.
### Too many prompts ### Too many prompts
@ -53,7 +57,7 @@ There are three main ways to get started with Fabric.
### 1. Just use the patterns (prompts) ### 1. Just use the patterns (prompts)
If you're not looking to do anything fancy, and you just want a lot of great prompts, you can navigate to the [`/patterns`](https://github.com/danielmiessler/fabric/tree/main/patterns) directory and start exploring! If you're not looking to do anything fancy, and you just want a lot of great prompts, you can navigate to the [`/patterns`](https://github.com/danielmiessler/fabric/tree/main/patterns) directory and start exploring!
You can use any of those in any AI application that you have! You can use any of those in any AI application that you have!
@ -61,7 +65,7 @@ You can use any of those in any AI application that you have!
If you want your very own Fabric server, head over to the [`/server/`](https://github.com/danielmiessler/fabric/tree/main/server) directory and set up your own Fabric Mill with your own patterns running! You can then use the [`/client/standalone_client_examples`](https://github.com/danielmiessler/fabric/tree/main/client/standalone_client_examples) to connect to it. If you want your very own Fabric server, head over to the [`/server/`](https://github.com/danielmiessler/fabric/tree/main/server) directory and set up your own Fabric Mill with your own patterns running! You can then use the [`/client/standalone_client_examples`](https://github.com/danielmiessler/fabric/tree/main/client/standalone_client_examples) to connect to it.
### 3. The standalone client ### 3. The standalone client
We're almost done with a universal client that will let you do all sorts of cool stuff, including: We're almost done with a universal client that will let you do all sorts of cool stuff, including:
@ -198,6 +202,7 @@ One of the coolest parts of the project is that it's **command-line native**!
Each pattern (prompt) you see in the `/patterns` directory can be used in any AI application you use, but you can also set up your own server using the `/server` code and then call APIs directly! Each pattern (prompt) you see in the `/patterns` directory can be used in any AI application you use, but you can also set up your own server using the `/server` code and then call APIs directly!
Once you're set up, you can do things like: Once you're set up, you can do things like:
```bash ```bash
# Take any idea from `stdin` and send it to the `/write_essay` API! # Take any idea from `stdin` and send it to the `/write_essay` API!
cat "An idea that coding is like speaking with rules." | write_essay cat "An idea that coding is like speaking with rules." | write_essay
@ -213,7 +218,6 @@ Fabric is themed off of, well… _fabric_—as in…woven materials. So, think b
- The optional server-side functionality of `fabric` is called the **Mill**. - The optional server-side functionality of `fabric` is called the **Mill**.
- The optional client-side scripts within `fabric` are called **Looms**. - The optional client-side scripts within `fabric` are called **Looms**.
## More Documentation ## More Documentation
> [!IMPORTANT]\ > [!IMPORTANT]\

54
client/fabric

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/Users/daniel/Cloud/Development/fabric/client/.venv/bin/python3
from utils import Standalone, Update from utils import Standalone, Update
import argparse import argparse
@ -11,42 +11,54 @@ script_directory = os.path.dirname(os.path.realpath(__file__))
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='An open source framework for augmenting humans using AI.') description="An open source framework for augmenting humans using AI."
parser.add_argument('--text', '-t', help='Text to extract summary from') )
parser.add_argument("--text", "-t", help="Text to extract summary from")
parser.add_argument( parser.add_argument(
'--copy', '-c', help='Copy the response to the clipboard', action='store_true') "--copy", "-c", help="Copy the response to the clipboard", action="store_true"
parser.add_argument('--output', '-o', help='Save the response to a file', )
nargs='?', const='analyzepaper.txt', default=None)
parser.add_argument( parser.add_argument(
'--stream', '-s', help='Use this option if you are piping output to another app. The output will not be streamed', action='store_true') "--output",
"-o",
help="Save the response to a file",
nargs="?",
const="analyzepaper.txt",
default=None,
)
parser.add_argument( parser.add_argument(
'--list', '-l', help='List available patterns', action='store_true') "--stream",
"-s",
help="Use this option if you are piping output to another app. The output will not be streamed",
action="store_true",
)
parser.add_argument( parser.add_argument(
'--update', '-u', help='Update patterns', action='store_true') "--list", "-l", help="List available 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("--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")
args = parser.parse_args() args = parser.parse_args()
home_holder = os.path.expanduser('~') home_holder = os.path.expanduser("~")
config = os.path.join(home_holder, '.config', 'fabric') config = os.path.join(home_holder, ".config", "fabric")
config_patterns_directory = os.path.join(config, 'patterns') config_patterns_directory = os.path.join(config, "patterns")
env_file = os.path.join(config, '.env') env_file = os.path.join(config, ".env")
if not os.path.exists(config): if not os.path.exists(config):
os.makedirs(config) os.makedirs(config)
if args.apikey: if args.apikey:
with open(env_file, 'w') as f: with open(env_file, "w") as f:
f.write(f'OPENAI_API_KEY={args.apikey}') f.write(f"OPENAI_API_KEY={args.apikey}")
print(f'OpenAI API key set to {args.apikey}') print(f"OpenAI API key set to {args.apikey}")
sys.exit() sys.exit()
if not os.path.exists(env_file): if not os.path.exists(env_file):
print('No API key found. Use the --apikey option to set the key') print("No API key found. Use the --apikey option to set the key")
sys.exit() sys.exit()
if not os.path.exists(config_patterns_directory): if not os.path.exists(config_patterns_directory):
Update() Update()
sys.exit() sys.exit()
if args.update: if args.update:
Update() Update()
print('patterns updated:') print("patterns updated:")
sys.exit() sys.exit()
standalone = Standalone(args, args.pattern) standalone = Standalone(args, args.pattern)
if args.list: if args.list:
@ -56,7 +68,7 @@ if __name__ == "__main__":
print(d) print(d)
sys.exit() sys.exit()
except FileNotFoundError: except FileNotFoundError:
print('No patterns found') print("No patterns found")
sys.exit() sys.exit()
if args.text is not None: if args.text is not None:
text = args.text text = args.text

65
client/utils.py

@ -6,11 +6,11 @@ import sys
current_directory = os.path.dirname(os.path.realpath(__file__)) current_directory = os.path.dirname(os.path.realpath(__file__))
config_directory = os.path.expanduser("~/.config/fabric") config_directory = os.path.expanduser("~/.config/fabric")
env_file = os.path.join(config_directory, '.env') env_file = os.path.join(config_directory, ".env")
class Standalone: class Standalone:
def __init__(self, args, pattern=''): def __init__(self, args, pattern=""):
try: try:
with open(env_file, "r") as f: with open(env_file, "r") as f:
apikey = f.read().split("=")[1] apikey = f.read().split("=")[1]
@ -24,11 +24,11 @@ class Standalone:
def streamMessage(self, input_data: str): def streamMessage(self, input_data: str):
wisdomFilePath = os.path.join( wisdomFilePath = os.path.join(
config_directory, f"patterns/{self.pattern}/system.md") config_directory, f"patterns/{self.pattern}/system.md"
)
user_message = {"role": "user", "content": f"{input_data}"} user_message = {"role": "user", "content": f"{input_data}"}
wisdom_File = os.path.join( wisdom_File = os.path.join(current_directory, wisdomFilePath)
current_directory, wisdomFilePath) buffer = ""
buffer = ''
if self.pattern: if self.pattern:
try: try:
with open(wisdom_File, "r") as f: with open(wisdom_File, "r") as f:
@ -36,29 +36,29 @@ class Standalone:
system_message = {"role": "system", "content": system} system_message = {"role": "system", "content": system}
messages = [system_message, user_message] messages = [system_message, user_message]
except FileNotFoundError: except FileNotFoundError:
print('pattern not found') print("pattern not found")
return return
else: else:
messages = [user_message] messages = [user_message]
try: try:
stream = self.client.chat.completions.create( stream = self.client.chat.completions.create(
model="gpt-4-1106-preview", model="gpt-4-turbo-preview",
messages=messages, messages=messages,
temperature=0.0, temperature=0.0,
top_p=1, top_p=1,
frequency_penalty=0.1, frequency_penalty=0.1,
presence_penalty=0.1, presence_penalty=0.1,
stream=True stream=True,
) )
for chunk in stream: for chunk in stream:
if chunk.choices[0].delta.content is not None: if chunk.choices[0].delta.content is not None:
char = chunk.choices[0].delta.content char = chunk.choices[0].delta.content
buffer += char buffer += char
if char not in ['\n', ' ']: if char not in ["\n", " "]:
print(char, end='') print(char, end="")
elif char == ' ': elif char == " ":
print(' ', end='') # Explicitly handle spaces print(" ", end="") # Explicitly handle spaces
elif char == '\n': elif char == "\n":
print() # Handle newlines print() # Handle newlines
sys.stdout.flush() sys.stdout.flush()
except Exception as e: except Exception as e:
@ -66,15 +66,15 @@ class Standalone:
if self.args.copy: if self.args.copy:
pyperclip.copy(buffer) pyperclip.copy(buffer)
if self.args.output: if self.args.output:
with open(self.args.output, 'w') as f: with open(self.args.output, "w") as f:
f.write(buffer) f.write(buffer)
def sendMessage(self, input_data: str): def sendMessage(self, input_data: str):
wisdomFilePath = os.path.join( wisdomFilePath = os.path.join(
config_directory, f"patterns/{self.pattern}/system.md") config_directory, f"patterns/{self.pattern}/system.md"
)
user_message = {"role": "user", "content": f"{input_data}"} user_message = {"role": "user", "content": f"{input_data}"}
wisdom_File = os.path.join( wisdom_File = os.path.join(current_directory, wisdomFilePath)
current_directory, wisdomFilePath)
if self.pattern: if self.pattern:
try: try:
with open(wisdom_File, "r") as f: with open(wisdom_File, "r") as f:
@ -82,18 +82,18 @@ class Standalone:
system_message = {"role": "system", "content": system} system_message = {"role": "system", "content": system}
messages = [system_message, user_message] messages = [system_message, user_message]
except FileNotFoundError: except FileNotFoundError:
print('pattern not found') print("pattern not found")
return return
else: else:
messages = [user_message] messages = [user_message]
try: try:
response = self.client.chat.completions.create( response = self.client.chat.completions.create(
model="gpt-4-1106-preview", model="gpt-4-turbo-preview",
messages=messages, messages=messages,
temperature=0.0, temperature=0.0,
top_p=1, top_p=1,
frequency_penalty=0.1, frequency_penalty=0.1,
presence_penalty=0.1 presence_penalty=0.1,
) )
print(response.choices[0].message.content) print(response.choices[0].message.content)
except Exception as e: except Exception as e:
@ -101,7 +101,7 @@ class Standalone:
if self.args.copy: if self.args.copy:
pyperclip.copy(response.choices[0].message.content) pyperclip.copy(response.choices[0].message.content)
if self.args.output: if self.args.output:
with open(self.args.output, 'w') as f: with open(self.args.output, "w") as f:
f.write(response.choices[0].message.content) f.write(response.choices[0].message.content)
@ -110,12 +110,10 @@ class Update:
# Initialize with the root API URL # Initialize with the root API URL
self.root_api_url = "https://api.github.com/repos/danielmiessler/fabric/contents/patterns?ref=main" self.root_api_url = "https://api.github.com/repos/danielmiessler/fabric/contents/patterns?ref=main"
self.config_directory = os.path.expanduser("~/.config/fabric") self.config_directory = os.path.expanduser("~/.config/fabric")
self.pattern_directory = os.path.join( self.pattern_directory = os.path.join(self.config_directory, "patterns")
self.config_directory, 'patterns')
# Ensure local directory exists # Ensure local directory exists
os.makedirs(self.pattern_directory, exist_ok=True) os.makedirs(self.pattern_directory, exist_ok=True)
self.get_github_directory_contents( self.get_github_directory_contents(self.root_api_url, self.pattern_directory)
self.root_api_url, self.pattern_directory)
def download_file(self, url, local_path): def download_file(self, url, local_path):
""" """
@ -123,21 +121,22 @@ class Update:
""" """
response = requests.get(url) response = requests.get(url)
response.raise_for_status() # This will raise an exception for HTTP error codes response.raise_for_status() # This will raise an exception for HTTP error codes
with open(local_path, 'wb') as f: with open(local_path, "wb") as f:
f.write(response.content) f.write(response.content)
def process_item(self, item, local_dir): 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. Process an individual item, downloading if it's a file, or processing further if it's a directory.
""" """
if item['type'] == 'file': if item["type"] == "file":
print(f"Downloading file: {item['name']} to {local_dir}") print(f"Downloading file: {item['name']} to {local_dir}")
self.download_file(item['download_url'], self.download_file(
os.path.join(local_dir, item['name'])) item["download_url"], os.path.join(local_dir, item["name"])
elif item['type'] == 'dir': )
new_dir = 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) os.makedirs(new_dir, exist_ok=True)
self.get_github_directory_contents(item['url'], new_dir) self.get_github_directory_contents(item["url"], new_dir)
def get_github_directory_contents(self, api_url, local_dir): def get_github_directory_contents(self, api_url, local_dir):
""" """

Loading…
Cancel
Save