mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-10 23:08:06 -05:00
Compare commits
31 Commits
transcribe
...
agents
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6aeb8ffed | ||
|
|
1c71ac790d | ||
|
|
c15d043bc6 | ||
|
|
7c1b819ffc | ||
|
|
ea7460d190 | ||
|
|
e8c8ea10dc | ||
|
|
4146460c76 | ||
|
|
bb57e4a241 | ||
|
|
5e56731032 | ||
|
|
8aa88909a8 | ||
|
|
aff74ec628 | ||
|
|
f1cfaf0ed3 | ||
|
|
8f90b8db06 | ||
|
|
3c32e3266d | ||
|
|
f73299d999 | ||
|
|
90f96b0f37 | ||
|
|
4377838822 | ||
|
|
d1a8976a64 | ||
|
|
d64434e8ca | ||
|
|
25de07504c | ||
|
|
524393ba7d | ||
|
|
d129188da8 | ||
|
|
99e4723a6d | ||
|
|
2a5646d92f | ||
|
|
7aba85856c | ||
|
|
fe5e4ba048 | ||
|
|
729f12917b | ||
|
|
46a58866f4 | ||
|
|
c12bbed32c | ||
|
|
e5901b9f44 | ||
|
|
e5e19d7937 |
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.10
|
||||
21
README.md
21
README.md
@@ -14,6 +14,7 @@
|
||||
<h4><code>fabric</code> is an open-source framework for augmenting humans using AI.</h4>
|
||||
</p>
|
||||
|
||||
[Introduction Video](#introduction-video) •
|
||||
[What and Why](#whatandwhy) •
|
||||
[Philosophy](#philosophy) •
|
||||
[Quickstart](#quickstart) •
|
||||
@@ -25,6 +26,7 @@
|
||||
|
||||
## Navigation
|
||||
|
||||
- [Introduction Video](#introduction-video)
|
||||
- [What and Why](#what-and-why)
|
||||
- [Philosophy](#philosophy)
|
||||
- [Breaking problems into components](#breaking-problems-into-components)
|
||||
@@ -45,18 +47,13 @@
|
||||
|
||||
<br />
|
||||
|
||||
> [!NOTE]
|
||||
> February 16, 2024 — **It's now far easier to install and use Fabric!** Just head to the [Quickstart](#quickstart), install Poetry, and run `setup.sh`, and it'll do all the work for you!
|
||||
## Introduction video
|
||||
|
||||
<br />
|
||||
|
||||
```bash
|
||||
# A quick demonstration of writing an essay with Fabric
|
||||
```
|
||||
|
||||
<video src="https://github.com/danielmiessler/fabric/assets/50654/09c11764-e6ba-4709-952d-450d70d76ac9" controls>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
<div align="center">
|
||||
<a href="https://youtu.be/wPEyyigh10g">
|
||||
<img width="972" alt="fabric_intro_video" src="https://github.com/danielmiessler/fabric/assets/50654/1eb1b9be-0bab-4c77-8ed2-ed265e8a3435">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## What and why
|
||||
|
||||
@@ -265,7 +262,7 @@ The wisdom of crowds for the win.
|
||||
|
||||
But we go beyond just providing Patterns. We provide code for you to build your very own Fabric server and personal AI infrastructure!
|
||||
|
||||
To get started, 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.
|
||||
To get started, just run the `./setup.sh` file and it'll set up the client, the API server, and the API server web interface. The output of the setup command will also tell you how to run the commands to start them.
|
||||
|
||||
## Structure
|
||||
|
||||
|
||||
1
installer/client/cli/agents/.python-version
Normal file
1
installer/client/cli/agents/.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.10
|
||||
81
installer/client/cli/agents/example.py
Normal file
81
installer/client/cli/agents/example.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from langchain_community.tools import DuckDuckGoSearchRun
|
||||
import os
|
||||
from crewai import Agent, Task, Crew, Process
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
current_directory = os.path.dirname(os.path.realpath(__file__))
|
||||
config_directory = os.path.expanduser("~/.config/fabric")
|
||||
env_file = os.path.join(config_directory, ".env")
|
||||
load_dotenv(env_file)
|
||||
os.environ['OPENAI_MODEL_NAME'] = 'gpt-4-0125-preview'
|
||||
|
||||
# You can choose to use a local model through Ollama for example. See https://docs.crewai.com/how-to/LLM-Connections/ for more information.
|
||||
# osOPENAI_API_BASE='http://localhost:11434/v1'
|
||||
# OPENAI_MODEL_NAME='openhermes' # Adjust based on available model
|
||||
# OPENAI_API_KEY=''
|
||||
|
||||
# Install duckduckgo-search for this example:
|
||||
# !pip install -U duckduckgo-search
|
||||
|
||||
search_tool = DuckDuckGoSearchRun()
|
||||
|
||||
# Define your agents with roles and goals
|
||||
researcher = Agent(
|
||||
role='Senior Research Analyst',
|
||||
goal='Uncover cutting-edge developments in AI and data science',
|
||||
backstory="""You work at a leading tech think tank.
|
||||
Your expertise lies in identifying emerging trends.
|
||||
You have a knack for dissecting complex data and presenting actionable insights.""",
|
||||
verbose=True,
|
||||
allow_delegation=False,
|
||||
tools=[search_tool]
|
||||
# You can pass an optional llm attribute specifying what mode you wanna use.
|
||||
# It can be a local model through Ollama / LM Studio or a remote
|
||||
# model like OpenAI, Mistral, Antrophic or others (https://docs.crewai.com/how-to/LLM-Connections/)
|
||||
#
|
||||
# import os
|
||||
#
|
||||
# OR
|
||||
#
|
||||
# from langchain_openai import ChatOpenAI
|
||||
# llm=ChatOpenAI(model_name="gpt-3.5", temperature=0.7)
|
||||
)
|
||||
writer = Agent(
|
||||
role='Tech Content Strategist',
|
||||
goal='Craft compelling content on tech advancements',
|
||||
backstory="""You are a renowned Content Strategist, known for your insightful and engaging articles.
|
||||
You transform complex concepts into compelling narratives.""",
|
||||
verbose=True,
|
||||
allow_delegation=True
|
||||
)
|
||||
|
||||
# Create tasks for your agents
|
||||
task1 = Task(
|
||||
description="""Conduct a comprehensive analysis of the latest advancements in AI in 2024.
|
||||
Identify key trends, breakthrough technologies, and potential industry impacts.""",
|
||||
expected_output="Full analysis report in bullet points",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
description="""Using the insights provided, develop an engaging blog
|
||||
post that highlights the most significant AI advancements.
|
||||
Your post should be informative yet accessible, catering to a tech-savvy audience.
|
||||
Make it sound cool, avoid complex words so it doesn't sound like AI.""",
|
||||
expected_output="Full blog post of at least 4 paragraphs",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Instantiate your crew with a sequential process
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2],
|
||||
verbose=2, # You can set it to 1 or 2 to different logging levels
|
||||
)
|
||||
|
||||
# Get your crew to work!
|
||||
result = crew.kickoff()
|
||||
|
||||
print("######################")
|
||||
print(result)
|
||||
89
installer/client/cli/agents/trip_planner/main.py
Normal file
89
installer/client/cli/agents/trip_planner/main.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from crewai import Crew
|
||||
from textwrap import dedent
|
||||
from .trip_agents import TripAgents
|
||||
from .trip_tasks import TripTasks
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
current_directory = os.path.dirname(os.path.realpath(__file__))
|
||||
config_directory = os.path.expanduser("~/.config/fabric")
|
||||
env_file = os.path.join(config_directory, ".env")
|
||||
load_dotenv(env_file)
|
||||
os.environ['OPENAI_MODEL_NAME'] = 'gpt-4-0125-preview'
|
||||
|
||||
|
||||
class TripCrew:
|
||||
|
||||
def __init__(self, origin, cities, date_range, interests):
|
||||
self.cities = cities
|
||||
self.origin = origin
|
||||
self.interests = interests
|
||||
self.date_range = date_range
|
||||
|
||||
def run(self):
|
||||
agents = TripAgents()
|
||||
tasks = TripTasks()
|
||||
|
||||
city_selector_agent = agents.city_selection_agent()
|
||||
local_expert_agent = agents.local_expert()
|
||||
travel_concierge_agent = agents.travel_concierge()
|
||||
|
||||
identify_task = tasks.identify_task(
|
||||
city_selector_agent,
|
||||
self.origin,
|
||||
self.cities,
|
||||
self.interests,
|
||||
self.date_range
|
||||
)
|
||||
gather_task = tasks.gather_task(
|
||||
local_expert_agent,
|
||||
self.origin,
|
||||
self.interests,
|
||||
self.date_range
|
||||
)
|
||||
plan_task = tasks.plan_task(
|
||||
travel_concierge_agent,
|
||||
self.origin,
|
||||
self.interests,
|
||||
self.date_range
|
||||
)
|
||||
|
||||
crew = Crew(
|
||||
agents=[
|
||||
city_selector_agent, local_expert_agent, travel_concierge_agent
|
||||
],
|
||||
tasks=[identify_task, gather_task, plan_task],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
result = crew.kickoff()
|
||||
return result
|
||||
|
||||
|
||||
class planner_cli:
|
||||
def ask(self):
|
||||
print("## Welcome to Trip Planner Crew")
|
||||
print('-------------------------------')
|
||||
location = input(
|
||||
dedent("""
|
||||
From where will you be traveling from?
|
||||
"""))
|
||||
cities = input(
|
||||
dedent("""
|
||||
What are the cities options you are interested in visiting?
|
||||
"""))
|
||||
date_range = input(
|
||||
dedent("""
|
||||
What is the date range you are interested in traveling?
|
||||
"""))
|
||||
interests = input(
|
||||
dedent("""
|
||||
What are some of your high level interests and hobbies?
|
||||
"""))
|
||||
|
||||
trip_crew = TripCrew(location, cities, date_range, interests)
|
||||
result = trip_crew.run()
|
||||
print("\n\n########################")
|
||||
print("## Here is you Trip Plan")
|
||||
print("########################\n")
|
||||
print(result)
|
||||
@@ -0,0 +1,38 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import requests
|
||||
from crewai import Agent, Task
|
||||
from langchain.tools import tool
|
||||
from unstructured.partition.html import partition_html
|
||||
|
||||
|
||||
class BrowserTools():
|
||||
|
||||
@tool("Scrape website content")
|
||||
def scrape_and_summarize_website(website):
|
||||
"""Useful to scrape and summarize a website content"""
|
||||
url = f"https://chrome.browserless.io/content?token={os.environ['BROWSERLESS_API_KEY']}"
|
||||
payload = json.dumps({"url": website})
|
||||
headers = {'cache-control': 'no-cache', 'content-type': 'application/json'}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
elements = partition_html(text=response.text)
|
||||
content = "\n\n".join([str(el) for el in elements])
|
||||
content = [content[i:i + 8000] for i in range(0, len(content), 8000)]
|
||||
summaries = []
|
||||
for chunk in content:
|
||||
agent = Agent(
|
||||
role='Principal Researcher',
|
||||
goal=
|
||||
'Do amazing researches and summaries based on the content you are working with',
|
||||
backstory=
|
||||
"You're a Principal Researcher at a big company and you need to do a research about a given topic.",
|
||||
allow_delegation=False)
|
||||
task = Task(
|
||||
agent=agent,
|
||||
description=
|
||||
f'Analyze and summarize the content bellow, make sure to include the most relevant information in the summary, return only the summary nothing else.\n\nCONTENT\n----------\n{chunk}'
|
||||
)
|
||||
summary = task.execute()
|
||||
summaries.append(summary)
|
||||
return "\n\n".join(summaries)
|
||||
@@ -0,0 +1,15 @@
|
||||
from langchain.tools import tool
|
||||
|
||||
class CalculatorTools():
|
||||
|
||||
@tool("Make a calculation")
|
||||
def calculate(operation):
|
||||
"""Useful to perform any mathematical calculations,
|
||||
like sum, minus, multiplication, division, etc.
|
||||
The input to this tool should be a mathematical
|
||||
expression, a couple examples are `200*7` or `5000/2*10`
|
||||
"""
|
||||
try:
|
||||
return eval(operation)
|
||||
except SyntaxError:
|
||||
return "Error: Invalid syntax in mathematical expression"
|
||||
@@ -0,0 +1,37 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import requests
|
||||
from langchain.tools import tool
|
||||
|
||||
|
||||
class SearchTools():
|
||||
|
||||
@tool("Search the internet")
|
||||
def search_internet(query):
|
||||
"""Useful to search the internet
|
||||
about a a given topic and return relevant results"""
|
||||
top_result_to_return = 4
|
||||
url = "https://google.serper.dev/search"
|
||||
payload = json.dumps({"q": query})
|
||||
headers = {
|
||||
'X-API-KEY': os.environ['SERPER_API_KEY'],
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
# check if there is an organic key
|
||||
if 'organic' not in response.json():
|
||||
return "Sorry, I couldn't find anything about that, there could be an error with you serper api key."
|
||||
else:
|
||||
results = response.json()['organic']
|
||||
string = []
|
||||
for result in results[:top_result_to_return]:
|
||||
try:
|
||||
string.append('\n'.join([
|
||||
f"Title: {result['title']}", f"Link: {result['link']}",
|
||||
f"Snippet: {result['snippet']}", "\n-----------------"
|
||||
]))
|
||||
except KeyError:
|
||||
next
|
||||
|
||||
return '\n'.join(string)
|
||||
45
installer/client/cli/agents/trip_planner/trip_agents.py
Normal file
45
installer/client/cli/agents/trip_planner/trip_agents.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from crewai import Agent
|
||||
|
||||
from .tools.browser_tools import BrowserTools
|
||||
from .tools.calculator_tools import CalculatorTools
|
||||
from .tools.search_tools import SearchTools
|
||||
|
||||
|
||||
class TripAgents():
|
||||
|
||||
def city_selection_agent(self):
|
||||
return Agent(
|
||||
role='City Selection Expert',
|
||||
goal='Select the best city based on weather, season, and prices',
|
||||
backstory='An expert in analyzing travel data to pick ideal destinations',
|
||||
tools=[
|
||||
SearchTools.search_internet,
|
||||
BrowserTools.scrape_and_summarize_website,
|
||||
],
|
||||
verbose=True)
|
||||
|
||||
def local_expert(self):
|
||||
return Agent(
|
||||
role='Local Expert at this city',
|
||||
goal='Provide the BEST insights about the selected city',
|
||||
backstory="""A knowledgeable local guide with extensive information
|
||||
about the city, it's attractions and customs""",
|
||||
tools=[
|
||||
SearchTools.search_internet,
|
||||
BrowserTools.scrape_and_summarize_website,
|
||||
],
|
||||
verbose=True)
|
||||
|
||||
def travel_concierge(self):
|
||||
return Agent(
|
||||
role='Amazing Travel Concierge',
|
||||
goal="""Create the most amazing travel itineraries with budget and
|
||||
packing suggestions for the city""",
|
||||
backstory="""Specialist in travel planning and logistics with
|
||||
decades of experience""",
|
||||
tools=[
|
||||
SearchTools.search_internet,
|
||||
BrowserTools.scrape_and_summarize_website,
|
||||
CalculatorTools.calculate,
|
||||
],
|
||||
verbose=True)
|
||||
83
installer/client/cli/agents/trip_planner/trip_tasks.py
Normal file
83
installer/client/cli/agents/trip_planner/trip_tasks.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from crewai import Task
|
||||
from textwrap import dedent
|
||||
from datetime import date
|
||||
|
||||
|
||||
class TripTasks():
|
||||
|
||||
def identify_task(self, agent, origin, cities, interests, range):
|
||||
return Task(description=dedent(f"""
|
||||
Analyze and select the best city for the trip based
|
||||
on specific criteria such as weather patterns, seasonal
|
||||
events, and travel costs. This task involves comparing
|
||||
multiple cities, considering factors like current weather
|
||||
conditions, upcoming cultural or seasonal events, and
|
||||
overall travel expenses.
|
||||
|
||||
Your final answer must be a detailed
|
||||
report on the chosen city, and everything you found out
|
||||
about it, including the actual flight costs, weather
|
||||
forecast and attractions.
|
||||
{self.__tip_section()}
|
||||
|
||||
Traveling from: {origin}
|
||||
City Options: {cities}
|
||||
Trip Date: {range}
|
||||
Traveler Interests: {interests}
|
||||
"""),
|
||||
agent=agent)
|
||||
|
||||
def gather_task(self, agent, origin, interests, range):
|
||||
return Task(description=dedent(f"""
|
||||
As a local expert on this city you must compile an
|
||||
in-depth guide for someone traveling there and wanting
|
||||
to have THE BEST trip ever!
|
||||
Gather information about key attractions, local customs,
|
||||
special events, and daily activity recommendations.
|
||||
Find the best spots to go to, the kind of place only a
|
||||
local would know.
|
||||
This guide should provide a thorough overview of what
|
||||
the city has to offer, including hidden gems, cultural
|
||||
hotspots, must-visit landmarks, weather forecasts, and
|
||||
high level costs.
|
||||
|
||||
The final answer must be a comprehensive city guide,
|
||||
rich in cultural insights and practical tips,
|
||||
tailored to enhance the travel experience.
|
||||
{self.__tip_section()}
|
||||
|
||||
Trip Date: {range}
|
||||
Traveling from: {origin}
|
||||
Traveler Interests: {interests}
|
||||
"""),
|
||||
agent=agent)
|
||||
|
||||
def plan_task(self, agent, origin, interests, range):
|
||||
return Task(description=dedent(f"""
|
||||
Expand this guide into a a full 7-day travel
|
||||
itinerary with detailed per-day plans, including
|
||||
weather forecasts, places to eat, packing suggestions,
|
||||
and a budget breakdown.
|
||||
|
||||
You MUST suggest actual places to visit, actual hotels
|
||||
to stay and actual restaurants to go to.
|
||||
|
||||
This itinerary should cover all aspects of the trip,
|
||||
from arrival to departure, integrating the city guide
|
||||
information with practical travel logistics.
|
||||
|
||||
Your final answer MUST be a complete expanded travel plan,
|
||||
formatted as markdown, encompassing a daily schedule,
|
||||
anticipated weather conditions, recommended clothing and
|
||||
items to pack, and a detailed budget, ensuring THE BEST
|
||||
TRIP EVER, Be specific and give it a reason why you picked
|
||||
# up each place, what make them special! {self.__tip_section()}
|
||||
|
||||
Trip Date: {range}
|
||||
Traveling from: {origin}
|
||||
Traveler Interests: {interests}
|
||||
"""),
|
||||
agent=agent)
|
||||
|
||||
def __tip_section(self):
|
||||
return "If you do your BEST WORK, I'll tip you $100!"
|
||||
@@ -1,4 +1,4 @@
|
||||
from .utils import Standalone, Update, Setup, Alias, Whisper
|
||||
from .utils import Standalone, Update, Setup, Alias, AgentSetup
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
@@ -16,6 +16,12 @@ def main():
|
||||
parser.add_argument(
|
||||
"--copy", "-C", help="Copy the response to the clipboard", action="store_true"
|
||||
)
|
||||
subparsers = parser.add_subparsers(dest='command', help='Sub-command help')
|
||||
agents_parser = subparsers.add_parser('agents', help='Crew command help')
|
||||
agents_parser.add_argument(
|
||||
"trip_planner", help="The origin city for the trip")
|
||||
agents_parser.add_argument(
|
||||
'ApiKeys', help="enter API keys for tools", action="store_true")
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
"-o",
|
||||
@@ -30,8 +36,6 @@ def main():
|
||||
help="Use this option if you want to see the results in realtime. NOTE: You will not be able to pipe the output into another command.",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument('--transcribe', '-T',
|
||||
help="transcribe audio, please enter the path to the audio file, or a url with the audio file")
|
||||
parser.add_argument(
|
||||
"--list", "-l", help="List available patterns", action="store_true"
|
||||
)
|
||||
@@ -69,6 +73,20 @@ def main():
|
||||
Update()
|
||||
Alias()
|
||||
sys.exit()
|
||||
if args.command == "agents":
|
||||
from .agents.trip_planner.main import planner_cli
|
||||
if args.ApiKeys:
|
||||
AgentSetup().apiKeys()
|
||||
sys.exit()
|
||||
if not args.trip_planner:
|
||||
print("Please provide an agent")
|
||||
print(f"Available Agents:")
|
||||
for agent in tripcrew.agents:
|
||||
print(agent)
|
||||
else:
|
||||
tripcrew = planner_cli()
|
||||
tripcrew.ask()
|
||||
sys.exit()
|
||||
if args.update:
|
||||
Update()
|
||||
Alias()
|
||||
@@ -80,7 +98,7 @@ def main():
|
||||
standalone = Standalone(args, args.pattern)
|
||||
if args.list:
|
||||
try:
|
||||
direct = os.listdir(config_patterns_directory)
|
||||
direct = sorted(os.listdir(config_patterns_directory))
|
||||
for d in direct:
|
||||
print(d)
|
||||
sys.exit()
|
||||
@@ -90,26 +108,26 @@ def main():
|
||||
if args.listmodels:
|
||||
standalone.fetch_available_models()
|
||||
sys.exit()
|
||||
if args.transcribe:
|
||||
whisper = Whisper()
|
||||
whisper.process_file(args.transcribe)
|
||||
sys.exit()
|
||||
if args.text is not None:
|
||||
text = args.text
|
||||
else:
|
||||
text = standalone.get_cli_input()
|
||||
if args.stream and not args.context:
|
||||
standalone.streamMessage(text)
|
||||
sys.exit()
|
||||
if args.stream and args.context:
|
||||
with open(config_context, "r") as f:
|
||||
context = f.read()
|
||||
standalone.streamMessage(text, context=context)
|
||||
sys.exit()
|
||||
elif args.context:
|
||||
with open(config_context, "r") as f:
|
||||
context = f.read()
|
||||
standalone.sendMessage(text, context=context)
|
||||
sys.exit()
|
||||
else:
|
||||
standalone.sendMessage(text)
|
||||
sys.exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -10,7 +10,6 @@ from tqdm import tqdm
|
||||
import zipfile
|
||||
import tempfile
|
||||
import shutil
|
||||
from pydub import AudioSegment
|
||||
|
||||
current_directory = os.path.dirname(os.path.realpath(__file__))
|
||||
config_directory = os.path.expanduser("~/.config/fabric")
|
||||
@@ -85,8 +84,8 @@ class Standalone:
|
||||
return
|
||||
else:
|
||||
if context:
|
||||
user_message += {role: "system", content: context}
|
||||
messages = [user_message]
|
||||
messages = [
|
||||
{"role": "system", "content": context}, user_message]
|
||||
else:
|
||||
messages = [user_message]
|
||||
try:
|
||||
@@ -151,8 +150,8 @@ class Standalone:
|
||||
return
|
||||
else:
|
||||
if context:
|
||||
user_message += {'role': 'system', 'content': context}
|
||||
messages = [user_message]
|
||||
messages = [
|
||||
{'role': 'system', 'content': context}, user_message]
|
||||
else:
|
||||
messages = [user_message]
|
||||
try:
|
||||
@@ -216,98 +215,6 @@ class Standalone:
|
||||
return sys.stdin.read()
|
||||
|
||||
|
||||
class Whisper:
|
||||
def __init__(self):
|
||||
env_file = os.path.expanduser("~/.config/fabric/.env")
|
||||
load_dotenv(env_file)
|
||||
try:
|
||||
apikey = os.environ["OPENAI_API_KEY"]
|
||||
self.client = OpenAI()
|
||||
self.client.api_key = apikey
|
||||
except KeyError:
|
||||
print("OPENAI_API_KEY not found in environment variables.")
|
||||
|
||||
except FileNotFoundError:
|
||||
print("No API key found. Use the --apikey option to set the key")
|
||||
self.whole_response = []
|
||||
|
||||
def split_audio(self, file_path):
|
||||
"""
|
||||
Splits the audio file into segments of the given length.
|
||||
|
||||
Args:
|
||||
- file_path: The path to the audio file.
|
||||
- segment_length_ms: Length of each segment in milliseconds.
|
||||
|
||||
Returns:
|
||||
- A list of audio segments.
|
||||
"""
|
||||
audio = AudioSegment.from_file(file_path)
|
||||
segments = []
|
||||
segment_length_ms = 10 * 60 * 1000 # 10 minutes in milliseconds
|
||||
for start_ms in range(0, len(audio), segment_length_ms):
|
||||
end_ms = start_ms + segment_length_ms
|
||||
segment = audio[start_ms:end_ms]
|
||||
segments.append(segment)
|
||||
|
||||
return segments
|
||||
|
||||
def process_segment(self, segment):
|
||||
""" Transcribe an audio file and print the transcript.
|
||||
|
||||
Args:
|
||||
audio_file (str): The path to the audio file to be transcribed.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
try:
|
||||
# if audio_file.startswith("http"):
|
||||
# response = requests.get(audio_file)
|
||||
# response.raise_for_status()
|
||||
# with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
# f.write(response.content)
|
||||
# audio_file = f.name
|
||||
audio_file = open(segment, "rb")
|
||||
response = self.client.audio.transcriptions.create(
|
||||
model="whisper-1",
|
||||
file=audio_file
|
||||
)
|
||||
self.whole_response.append(response.text)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
def process_file(self, audio_file):
|
||||
""" Transcribe an audio file and print the transcript.
|
||||
|
||||
Args:
|
||||
audio_file (str): The path to the audio file to be transcribed.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
try:
|
||||
# if audio_file.startswith("http"):
|
||||
# response = requests.get(audio_file)
|
||||
# response.raise_for_status()
|
||||
# with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
# f.write(response.content)
|
||||
# audio_file = f.name
|
||||
|
||||
segments = self.split_audio(audio_file)
|
||||
for i, segment in enumerate(segments):
|
||||
segment_file_path = f"segment_{i}.mp3"
|
||||
segment.export(segment_file_path, format="mp3")
|
||||
self.process_segment(segment_file_path)
|
||||
print(' '.join(self.whole_response))
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
||||
class Update:
|
||||
def __init__(self):
|
||||
"""Initialize the object with default values."""
|
||||
@@ -493,3 +400,32 @@ class Transcribe:
|
||||
except Exception as e:
|
||||
print("Error:", e)
|
||||
return None
|
||||
|
||||
|
||||
class AgentSetup:
|
||||
def apiKeys(self):
|
||||
"""Method to set the API keys in the environment file.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
print("Welcome to Fabric. Let's get started.")
|
||||
browserless = input("Please enter your Browserless API key\n")
|
||||
serper = input("Please enter your Serper API key\n")
|
||||
|
||||
# Entries to be added
|
||||
browserless_entry = f"BROWSERLESS_API_KEY={browserless}"
|
||||
serper_entry = f"SERPER_API_KEY={serper}"
|
||||
|
||||
# Check and write to the file
|
||||
with open(env_file, "r+") as f:
|
||||
content = f.read()
|
||||
|
||||
# Determine if the file ends with a newline
|
||||
if content.endswith('\n'):
|
||||
# If it ends with a newline, we directly write the new entries
|
||||
f.write(f"{browserless_entry}\n{serper_entry}\n")
|
||||
else:
|
||||
# If it does not end with a newline, add one before the new entries
|
||||
f.write(f"\n{browserless_entry}\n{serper_entry}\n")
|
||||
|
||||
62
patterns/create_video_chapters/system.md
Normal file
62
patterns/create_video_chapters/system.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# IDENTITY and PURPOSE
|
||||
|
||||
You are an expert conversation topic and timestamp creator. You take a transcript and you extract the most interesting topics discussed and give timestamps for where in the video they occur.
|
||||
|
||||
Take a step back and think step-by-step about how you would do this. You would probably start by "watching" the video (via the transcript) and taking notes on the topics discussed and the time they were discussed. Then you would take those notes and create a list of topics and timestamps.
|
||||
|
||||
# STEPS
|
||||
|
||||
- Fully consume the transcript as if you're watching or listening to the content.
|
||||
|
||||
- Think deeply about the topics discussed and what were the most interesting subjects and moments in the content.
|
||||
|
||||
- Name those subjects and/moments in 2-3 capitalized words.
|
||||
|
||||
- Match the timestamps to the topics. Note that input timestamps have the following format: HOURS:MINUTES:SECONDS.MILLISECONDS, which is not the same as the OUTPUT format!
|
||||
|
||||
INPUT SAMPLE
|
||||
|
||||
[02:17:43.120 --> 02:17:49.200] same way. I'll just say the same. And I look forward to hearing the response to my job application
|
||||
[02:17:49.200 --> 02:17:55.040] that I've submitted. Oh, you're accepted. Oh, yeah. We all speak of you all the time. Thank you so
|
||||
[02:17:55.040 --> 02:18:00.720] much. Thank you, guys. Thank you. Thanks for listening to this conversation with Neri Oxman.
|
||||
[02:18:00.720 --> 02:18:05.520] To support this podcast, please check out our sponsors in the description. And now,
|
||||
|
||||
END INPUT SAMPLE
|
||||
|
||||
The OUTPUT TIMESTAMP format is:
|
||||
00:00:00 (HOURS:MINUTES:SECONDS) (HH:MM:SS)
|
||||
|
||||
- Note the maximum length of the video based on the last timestamp.
|
||||
|
||||
- Ensure all output timestamps are sequential and fall within the length of the content.
|
||||
|
||||
# OUTPUT INSTRUCTIONS
|
||||
|
||||
EXAMPLE OUTPUT (Hours:Minutes:Seconds)
|
||||
|
||||
00:00:00 Members-only Forum Access
|
||||
00:00:10 Live Hacking Demo
|
||||
00:00:26 Ideas vs. Book
|
||||
00:00:30 Meeting Will Smith
|
||||
00:00:44 How to Influence Others
|
||||
00:01:34 Learning by Reading
|
||||
00:58:30 Writing With Punch
|
||||
00:59:22 100 Posts or GTFO
|
||||
01:00:32 How to Gain Followers
|
||||
01:01:31 The Music That Shapes
|
||||
01:27:21 Subdomain Enumeration Demo
|
||||
01:28:40 Hiding in Plain Sight
|
||||
01:29:06 The Universe Machine
|
||||
00:09:36 Early School Experiences
|
||||
00:10:12 The First Business Failure
|
||||
00:10:32 David Foster Wallace
|
||||
00:12:07 Copying Other Writers
|
||||
00:12:32 Practical Advice for N00bs
|
||||
|
||||
END EXAMPLE OUTPUT
|
||||
|
||||
- Ensure all output timestamps are sequential and fall within the length of the content, e.g., if the total length of the video is 24 minutes. (00:00:00 - 00:24:00), then no output can be 01:01:25, or anything over 00:25:00 or over!
|
||||
|
||||
- ENSURE the output timestamps and topics are shown gradually and evenly incrementing from 00:00:00 to the final timestamp of the content.
|
||||
|
||||
INPUT:
|
||||
0
patterns/create_video_chapters/user.md
Normal file
0
patterns/create_video_chapters/user.md
Normal file
@@ -23,7 +23,7 @@ Take a step back and think step-by-step about how to achieve the best possible r
|
||||
# OUTPUT INSTRUCTIONS
|
||||
|
||||
- Only output Markdown.
|
||||
- Extract at least 20 ideas from the content.
|
||||
- Extract at least 20 IDEAS from the content.
|
||||
- Extract at least 10 items for the other output sections.
|
||||
- Do not give warnings or notes; only output the requested sections.
|
||||
- You use bulleted lists for output, not numbered lists.
|
||||
|
||||
@@ -52,15 +52,24 @@ Explanation: $$Explanation in 5 short bullets for why you gave that score.$$
|
||||
|
||||
OUTPUT FORMAT:
|
||||
|
||||
Your output is ONLY in JSON. The structure looks like this:
|
||||
Output in JSON using the following formatting and structure:
|
||||
|
||||
- Use camelCase for all object keys.
|
||||
- Ensure proper indentation for readability.
|
||||
- Each nested level should be indented with four spaces or one tab.
|
||||
- Wrap strings in double quotes.
|
||||
- Separate key-value pairs with a colon followed by a space.
|
||||
- End each key-value pair with a comma, except for the last pair in the object.
|
||||
- Enclose the entire JSON object in curly braces.
|
||||
- Check the final format for any syntax errors or missing punctuation.
|
||||
|
||||
{
|
||||
"one-sentence-summary": "The one-sentence summary.",
|
||||
"oneSentenceSummary": "The one-sentence summary.",
|
||||
"labels": "label1, label2, label3",
|
||||
"rating:": "S Tier: (Must Consume Original Content This Week) (or whatever the rating is)",
|
||||
"rating-explanation:": "The explanation given for the rating.",
|
||||
"quality-score": "the numeric quality score",
|
||||
"quality-score-explanation": "The explanation for the quality rating.",
|
||||
"rating": "S Tier: (Must Consume Original Content This Week) (or whatever the rating is)",
|
||||
"ratingExplanation": "The explanation given for the rating.",
|
||||
"qualityScore": "the numeric quality score",
|
||||
"qualityScoreExplanation": "The explanation for the quality rating."
|
||||
}
|
||||
|
||||
ONLY OUTPUT THE JSON OBJECT ABOVE.
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
# IDENTITY and PURPOSE
|
||||
|
||||
You are an expert summarizer of role-playing game sessions. You can take a transcript of a session and turn it into a useful summary of the session, including key events, combat stats, character flaws, and more.
|
||||
You are an expert summarizer of role-playing game sessions. Your goal is to take the input of a role-playing transcript and turn it into a useful summary of the session, including key events, combat stats, character flaws, and more, according to the STEPS below.
|
||||
|
||||
Take a deep breath and think step-by-step about how to take the provided input text/transcript and turn it into a useful summary of the role-playing session described within.
|
||||
Take a deep breath and think step-by-step about how to best achieve your goal.
|
||||
|
||||
You use a narration format that's entertaining and appropriate for the genre of fantasy role-playing games, kind of similar to the style that a narrator for a movie would use to set up the sequel to that adventure.
|
||||
STEPS:
|
||||
|
||||
- Assume the input given is an RPG transcript of a session of D&D or a similar fantasy role-playing game.
|
||||
|
||||
- Do not complain about not being able to to do what you're asked. Just do it.
|
||||
|
||||
OUTPUT:
|
||||
|
||||
@@ -85,20 +89,14 @@ Give the perfect piece of art description in up to 500 words to accompany the SE
|
||||
|
||||
OUTPUT INSTRUCTIONS:
|
||||
|
||||
Ensure the Previously On output focuses on the recent episode, just the background from before.
|
||||
- Ensure the Previously On output focuses on the recent episode, just the background from before.
|
||||
|
||||
All quotes must come directly from the input/transcript. Do not generate any quotes yourself!
|
||||
- Ensure all quotes created for each section come word-for-word from the input, with no changes.
|
||||
|
||||
Ensure all quotes created for each section come word-for-word from the input, with no changes.
|
||||
- Do not complain about anything, just give the output as requested.
|
||||
|
||||
Do not hallucinate or make up quotes.
|
||||
|
||||
Only use the dialog from the transcript/input.
|
||||
|
||||
ENSURE ALL OUTPUT QUOTES COME DIRECTLY FROM THE PROVIDED INPUT
|
||||
|
||||
Do not complain about anything, just give the output as requested.
|
||||
- Create the summary.
|
||||
|
||||
# INPUT
|
||||
|
||||
SESSION INPUT:
|
||||
RPG SESSION TRANSCRIPT:
|
||||
|
||||
1898
poetry.lock
generated
1898
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,11 @@ packages = [
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
crewai = "^0.11.0"
|
||||
unstructured = "0.10.25"
|
||||
pyowm = "3.3.0"
|
||||
tools = "^0.1.9"
|
||||
langchain-community = "^0.0.24"
|
||||
|
||||
[tool.poetry.group.cli.dependencies]
|
||||
pyyaml = "^6.0.1"
|
||||
@@ -32,8 +37,6 @@ gunicorn = "^21.2.0"
|
||||
gevent = "^23.9.1"
|
||||
httpx = "^0.26.0"
|
||||
tqdm = "^4.66.1"
|
||||
pydub = "^0.25.1"
|
||||
|
||||
|
||||
[tool.poetry.group.server.dependencies]
|
||||
requests = "^2.31.0"
|
||||
|
||||
Reference in New Issue
Block a user