Merge pull request #169 from crewAIInc/flow-examples

Flow examples
This commit is contained in:
João Moura
2024-10-04 13:29:20 -03:00
committed by GitHub
54 changed files with 7861 additions and 0 deletions

3
email_auto_responder_flow/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.env
__pycache__/
credentials.json

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -0,0 +1,99 @@
# Email Auto Responder Flow
Welcome to the Email Auto Responder Flow project, powered by [crewAI](https://crewai.com). This example demonstrates how you can leverage Flows from crewAI to automate the process of checking emails and creating draft responses. By utilizing Flows, the process becomes much simpler and more efficient.
## Background
In this project, we've taken one of our old example repositories, [CrewAI-LangGraph](https://github.com/crewAIInc/crewAI-examples/tree/main/CrewAI-LangGraph), and repurposed it to now use Flows. This showcases the power and simplicity of Flows in orchestrating AI agents to automate tasks like checking emails and creating drafts. Flows provide a more straightforward and powerful alternative to LangGraph, making it easier to build and manage complex workflows.
### High-Level Diagram
Below is a high-level diagram of the Email Auto Responder Flow:
![High-level Diagram](./Email_Flow.png)
This diagram illustrates the flow of tasks from fetching new emails to generating draft responses.
## Overview
This flow will guide you through the process of setting up an automated email responder. Here's a brief overview of what will happen in this flow:
1. **Fetch New Emails**: The flow starts by using the `EmailFilterCrew` to check for new emails. It updates the state with any new emails and their IDs.
2. **Generate Draft Responses**: Once new emails are fetched, the flow formats these emails and uses the `EmailFilterCrew` to generate draft responses for each email.
This flow is a great example of using Flows as a background worker that runs continuously to help you out. By following this flow, you can efficiently automate the process of checking emails and generating draft responses, leveraging the power of multiple AI agents to handle different aspects of the email processing workflow.
## Installation
Ensure you have Python >=3.10 <=3.13 installed on your system. This project uses [Poetry](https://python-poetry.org/) for dependency management and package handling, offering a seamless setup and execution experience.
First, if you haven't already, install Poetry:
```bash
pip install poetry
```
Next, navigate to your project directory and install the dependencies:
1. First lock the dependencies and then install them:
```bash
crewai install
```
### Customizing & Dependencies
**Add your `OPENAI_API_KEY` into the `.env` file**
**Add your `SERPER_API_KEY` into the `.env` file**
**Add your `TAVILY_API_KEY` into the `.env` file**
**Add your `MY_EMAIL` into the `.env` file**
To customize the behavior of the email auto responder, you can update the agents and tasks defined in the `EmailFilterCrew`. If you want to adjust the flow itself, you will need to modify the flow in `main.py`.
- **Agents and Tasks**: Modify `src/email_auto_responder_flow/crews/email_filter_crew/email_filter_crew.py` to define your agents and tasks. This is where you can customize how emails are filtered and how draft responses are generated.
- **Flow Adjustments**: Modify `src/email_auto_responder_flow/main.py` to adjust the flow. This is where you can change how the flow orchestrates the different crews and tasks.
### Setting Up Google Credentials
To enable the email auto responder to access your Gmail account, you need to set up a `credentials.json` file. Follow these steps:
1. **Set Up Google Account**: Follow the [Google instructions](https://developers.google.com/gmail/api/quickstart/python#authorize_credentials_for_a_desktop_application) to set up your Google account and obtain the `credentials.json` file.
2. **Download and Place `credentials.json`**: Once youve downloaded the file, name it `credentials.json` and place it in the root of the project.
## Running the Project
To kickstart your crew of AI agents and begin task execution, run this from the root folder of your project:
```bash
crewai run
```
This command initializes the email_auto_responder_flow, assembling the agents and assigning them tasks as defined in your configuration.
When you kickstart the flow, it will orchestrate multiple crews to perform the tasks. The flow will first fetch new emails, then create and run a crew to generate draft responses.
## Understanding Your Flow
The email_auto_responder_flow is composed of multiple AI agents, each with unique roles, goals, and tools. These agents collaborate on a series of tasks, defined in `config/tasks.yaml`, leveraging their collective skills to achieve complex objectives. The `config/agents.yaml` file outlines the capabilities and configurations of each agent in your flow.
### Flow Structure
1. **EmailFilterCrew**: This crew is responsible for checking for new emails and updating the state with any new emails and their IDs.
2. **Generate Draft Responses**: Once new emails are fetched, this step formats the emails and uses the `EmailFilterCrew` to generate draft responses for each email.
By understanding the flow structure, you can see how multiple crews are orchestrated to work together, each handling a specific part of the email processing workflow. This modular approach allows for efficient and scalable email automation.
## Support
For support, questions, or feedback regarding the Email Auto Responder Flow or crewAI:
- Visit our [documentation](https://docs.crewai.com)
- Reach out to us through our [GitHub repository](https://github.com/joaomdmoura/crewai)
- [Join our Discord](https://discord.com/invite/X4JWnZnxPb)
- [Chat with our docs](https://chatg.pt/DWjSBZn)
Let's create wonders together with the power and simplicity of crewAI.

View File

@@ -0,0 +1,23 @@
[tool.poetry]
name = "email_auto_responder_flow"
version = "0.1.0"
description = "email_auto_responder_flow using crewAI"
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = ">=3.10,<=3.13"
crewai = { extras = ["tools"], version = ">=0.67.1,<1.0.0" }
asyncio = "*"
langchain-tools = "^0.1.34"
crewai-tools = "^0.12.0"
google-auth-oauthlib = "^1.2.1"
google-api-python-client = "^2.145.0"
[tool.poetry.scripts]
email_auto_responder_flow = "email_auto_responder_flow.main:main"
run_flow = "email_auto_responder_flow.main:main"
plot_flow = "email_auto_responder_flow.main:plot"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@@ -0,0 +1,9 @@
email_followup_agent:
role: >
HR Coordinator
goal: >
Compose personalized follow-up emails to candidates based on their bio and whether they are being pursued for the job.
If we are proceeding, request availability for a Zoom call. Otherwise, send a polite rejection email.
backstory: >
You are an HR professional with excellent communication skills and a talent for crafting personalized and thoughtful
emails to job candidates. You understand the importance of maintaining a positive and professional tone in all correspondence.

View File

@@ -0,0 +1,26 @@
send_followup_email:
description: >
Compose personalized follow-up emails for candidates who applied to a specific job.
You will use the candidate's name, bio, and whether the company wants to proceed with them to generate the email.
If the candidate is proceeding, ask them for their availability for a Zoom call in the upcoming days.
If not, send a polite rejection email.
CANDIDATE DETAILS
-----------------
Candidate ID: {candidate_id}
Name: {name}
Bio:
{bio}
PROCEEDING WITH CANDIDATE: {proceed_with_candidate}
ADDITIONAL INSTRUCTIONS
-----------------------
- If we are proceeding, ask for their availability for a Zoom call within the next few days.
- If we are not proceeding, send a polite rejection email, acknowledging their effort in applying and appreciating their time.
expected_output: >
A personalized email based on the candidate's information. It should be professional and respectful,
either inviting them for a Zoom call or letting them know we are pursuing other candidates.
agent: email_followup_agent

View File

@@ -0,0 +1,77 @@
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool
from langchain_community.tools.gmail.get_thread import GmailGetThread
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from email_auto_responder_flow.tools.create_draft import CreateDraftTool
@CrewBase
class EmailFilterCrew:
"""Email Filter Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
llm = ChatOpenAI(model="gpt-4o")
@agent
def email_filter_agent(self) -> Agent:
search_tool = SerperDevTool()
return Agent(
config=self.agents_config["email_filter_agent"],
tools=[search_tool],
llm=self.llm,
verbose=True,
allow_delegation=True,
)
@agent
def email_action_agent(self) -> Agent:
gmail = GmailGetThread()
return Agent(
config=self.agents_config["email_action_agent"],
llm=self.llm,
verbose=True,
tools=[
GmailGetThread(api_resource=gmail.api_resource),
TavilySearchResults(),
],
)
@agent
def email_response_writer(self) -> Agent:
gmail = GmailGetThread()
return Agent(
config=self.agents_config["email_response_writer"],
llm=self.llm,
verbose=True,
tools=[
TavilySearchResults(),
GmailGetThread(api_resource=gmail.api_resource),
CreateDraftTool.create_draft,
],
)
@task
def filter_emails_task(self) -> Task:
return Task(config=self.tasks_config["filter_emails"])
@task
def action_required_emails_task(self) -> Task:
return Task(config=self.tasks_config["action_required_emails"])
@task
def draft_responses_task(self) -> Task:
return Task(config=self.tasks_config["draft_responses"])
@crew
def crew(self) -> Crew:
"""Creates the Email Filter Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)

View File

@@ -0,0 +1,73 @@
#!/usr/bin/env python
import asyncio
import time
from typing import List
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel
from email_auto_responder_flow.types import Email
from email_auto_responder_flow.utils.emails import check_email, format_emails
from .crews.email_filter_crew.email_filter_crew import EmailFilterCrew
class AutoResponderState(BaseModel):
emails: List[Email] = []
checked_emails_ids: set[str] = set()
class EmailAutoResponderFlow(Flow[AutoResponderState]):
initial_state = AutoResponderState
@start("wait_next_run")
def fetch_new_emails(self):
print("Kickoff the Email Filter Crew")
new_emails, updated_checked_email_ids = check_email(
checked_emails_ids=self.state.checked_emails_ids
)
self.state.emails = new_emails
self.state.checked_emails_ids = updated_checked_email_ids
@listen(fetch_new_emails)
def generate_draft_responses(self):
print("Current email queue: ", len(self.state.emails))
if len(self.state.emails) > 0:
print("Writing New emails")
emails = format_emails(self.state.emails)
EmailFilterCrew().crew().kickoff(inputs={"emails": emails})
self.state.emails = []
print("Waiting for 180 seconds")
time.sleep(180)
async def run_flow():
"""
Run the flow.
"""
email_auto_response_flow = EmailAutoResponderFlow()
email_auto_response_flow.kickoff()
async def plot_flow():
"""
Plot the flow.
"""
email_auto_response_flow = EmailAutoResponderFlow()
email_auto_response_flow.plot()
def main():
asyncio.run(run_flow())
def plot():
asyncio.run(plot_flow())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,20 @@
from langchain.tools import tool
from langchain_community.agent_toolkits import GmailToolkit
from langchain_community.tools.gmail.create_draft import GmailCreateDraft
class CreateDraftTool:
@tool("Create Draft")
def create_draft(data):
"""
Useful to create an email draft.
The input to this tool should be a pipe (|) separated text
of length 3 (three), representing who to send the email to,
the subject of the email and the actual message.
For example, `lorem@ipsum.com|Nice To Meet You|Hey it was great to meet you.`.
"""
email, subject, message = data.split("|")
gmail = GmailToolkit()
draft = GmailCreateDraft(api_resource=gmail.api_resource)
result = draft({"to": [email], "subject": subject, "message": message})
return f"\nDraft created: {result}\n"

View File

@@ -0,0 +1,8 @@
from pydantic import BaseModel
class Email(BaseModel):
id: str
threadId: str
snippet: str
sender: str

View File

@@ -0,0 +1,65 @@
import os
import time
from typing import List
from langchain_community.agent_toolkits import GmailToolkit
from langchain_community.tools.gmail.search import GmailSearch
from email_auto_responder_flow.types import Email
def check_email(checked_emails_ids: set[str]) -> tuple[list[Email], set[str]]:
print("# Checking for new emails")
gmail = GmailToolkit()
search = GmailSearch(api_resource=gmail.api_resource)
emails = search("after:newer_than:1d")
thread = []
new_emails: List[Email] = []
for email in emails:
if (
(email["id"] not in checked_emails_ids)
and (email["threadId"] not in thread)
and (os.environ["MY_EMAIL"] not in email["sender"])
):
thread.append(email["threadId"])
new_emails.append(
{
"id": email["id"],
"threadId": email["threadId"],
"snippet": email["snippet"],
"sender": email["sender"],
}
)
checked_emails_ids.update([email["id"] for email in emails])
return new_emails, checked_emails_ids
def wait_next_run(state):
print("## Waiting for 180 seconds")
time.sleep(180)
return state
def new_emails(state):
if len(state["emails"]) == 0:
print("## No new emails")
return "end"
else:
print("## New emails")
return "continue"
def format_emails(emails):
emails_string = []
for email in emails:
print(email)
arr = [
f"ID: {email['id']}",
f"- Thread ID: {email['threadId']}",
f"- Snippet: {email['snippet']}",
f"- From: {email['sender']}",
"--------",
]
emails_string.append("\n".join(arr))
return "\n".join(emails_string)

2
lead-score-flow/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.env
__pycache__/

File diff suppressed because it is too large Load Diff

87
lead-score-flow/README.md Normal file
View File

@@ -0,0 +1,87 @@
# Lead Score Flow
Welcome to the Lead Score Flow project, powered by [crewAI](https://crewai.com). This example demonstrates how you can leverage Flows from crewAI to automate the process of scoring leads, including data collection, analysis, and scoring. By utilizing Flows, the process becomes much simpler and more efficient.
## Overview
This flow will guide you through the process of setting up an automated lead scoring system. Here's a brief overview of what will happen in this flow:
1. **Load Leads**: The flow starts by loading lead data from a CSV file named `leads.csv`.
2. **Score Leads**: The `LeadScoreCrew` is kicked off to score the loaded leads based on predefined criteria.
3. **Human in the Loop**: The top 3 candidates are presented for human review, allowing for additional feedback or proceeding with writing emails.
4. **Write and Save Emails**: Emails are generated and saved for all leads, with special attention to the top 3 candidates.
By following this flow, you can efficiently automate the process of scoring leads, leveraging the power of multiple AI agents to handle different aspects of the lead scoring workflow.
## Installation
Ensure you have Python >=3.10 <=3.13 installed on your system. This project uses [Poetry](https://python-poetry.org/) for dependency management and package handling, offering a seamless setup and execution experience.
First, if you haven't already, install Poetry:
```bash
pip install poetry
```
Next, navigate to your project directory and install the dependencies:
1. First lock the dependencies and then install them:
```bash
crewai install
```
### Customizing & Dependencies
**Add your `OPENAI_API_KEY` into the `.env` file**
**Add your `SERPER_API_KEY` into the `.env` file**
To customize the behavior of the lead score flow, you can update the agents and tasks defined in the `LeadDataCollectionCrew`, `LeadAnalysisCrew`, and `LeadScoringCrew`. If you want to adjust the flow itself, you will need to modify the flow in `main.py`.
- **Agents and Tasks**: Modify `src/lead_score_flow/config/agents.yaml` to define your agents and `src/lead_score_flow/config/tasks.yaml` to define your tasks. This is where you can customize how lead data is collected, analyzed, and scored.
- **Flow Adjustments**: Modify `src/lead_score_flow/main.py` to adjust the flow. This is where you can change how the flow orchestrates the different crews and tasks.
## Running the Project
To kickstart your crew of AI agents and begin task execution, run this from the root folder of your project:
```bash
crewai run
```
This command initializes the lead_score_flow, assembling the agents and assigning them tasks as defined in your configuration.
When you kickstart the flow, it will orchestrate multiple crews to perform the tasks. The flow will first collect lead data, then analyze the data, score the leads, save the scores to a CSV file, and generate email drafts.
## Understanding Your Flow
The lead_score_flow is composed of multiple AI agents, each with unique roles, goals, and tools. These agents collaborate on a series of tasks, defined in `config/tasks.yaml`, leveraging their collective skills to achieve complex objectives. The `config/agents.yaml` file outlines the capabilities and configurations of each agent in your flow.
### Flow Structure
1. **Collect Lead Data**: This step collects lead data from various sources.
2. **Analyze Lead Data**: The `LeadAnalysisCrew` is kicked off to analyze the collected lead data.
3. **Score Leads**: The analyzed data is then used to score the leads based on predefined criteria.
4. **Save Lead Scores**: The lead scores are saved to a CSV file named `lead_scores.csv`.
5. **Write and Save Emails**: Emails are generated and saved for all leads, with special attention to the top 3 candidates.
By understanding the flow structure, you can see how multiple crews are orchestrated to work together, each handling a specific part of the lead scoring process. This modular approach allows for efficient and scalable lead scoring automation.
## Support
For support, questions, or feedback regarding the Lead Score Flow or crewAI:
- Visit our [documentation](https://docs.crewai.com)
- Reach out to us through our [GitHub repository](https://github.com/joaomdmoura/crewai)
- [Join our Discord](https://discord.com/invite/X4JWnZnxPb)
- [Chat with our docs](https://chatg.pt/DWjSBZn)
Let's create wonders together with the power and simplicity of crewAI.

View File

@@ -0,0 +1,25 @@
[tool.poetry]
name = "lead_score_flow"
version = "0.1.0"
description = "lead_score_flow using crewAI"
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = ">=3.10,<=3.13"
crewai = { extras = ["tools"], version = ">=0.67.1,<1.0.0" }
asyncio = "*"
langchain-tools = "^0.1.34"
crewai-tools = "^0.12.0"
google-auth-oauthlib = "^1.2.1"
google-api-python-client = "^2.145.0"
pyvis = "^0.3.2"
[tool.poetry.scripts]
lead_score_flow = "lead_score_flow.main:main"
run_flow = "lead_score_flow.main:main"
plot_flow = "lead_score_flow.main:plot"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@@ -0,0 +1,47 @@
JOB_DESCRIPTION = """
# Junior React Developer
**Position:** Junior React Developer
**Duration:** 12-month contract with the possibility of extension based on performance and project needs.
We are seeking a motivated Junior React Developer to join our team and assist in the development of our cutting-edge Next.js web application. This project integrates the Vercel AI SDK to enhance user experience with advanced AI-driven features.
**Key Responsibilities:**
- Develop and maintain React components and Next.js applications.
- Integrate AI-driven features using the Vercel AI SDK.
- Collaborate with senior developers to design and implement new features.
- Optimize application performance and ensure responsiveness across different devices.
- Participate in code reviews and contribute to best practices.
- Troubleshoot and debug issues to ensure the highest quality of the web application.
**Qualifications:**
- 1-2 years of experience in front-end development with React and Next.js.
- Proficiency in JavaScript, TypeScript, CSS, and HTML.
- Experience with Git and RESTful APIs.
- Familiarity with Vercel AI SDK is a plus.
- Strong problem-solving skills and attention to detail.
- Excellent communication and teamwork abilities.
- Ability to work independently and take initiative on projects.
**What We Offer:**
- Opportunity to work with cutting-edge technologies and AI integration.
- Collaborative and supportive work environment.
- Mentorship from senior developers to help grow your skills.
- Potential for role extension and career advancement within the company.
- Flexible working hours and the possibility of remote work.
This role is ideal for someone looking to grow their skills in Next.js, React, and AI-powered web applications while contributing to impactful projects.
"""
SKILLS = [
"React",
"Next.js",
"JavaScript",
"TypeScript",
"Vercel AI SDK",
"CSS",
"HTML",
"Git",
"REST APIs",
"CrewAI",
]

View File

@@ -0,0 +1,9 @@
email_followup_agent:
role: >
HR Coordinator
goal: >
Compose personalized follow-up emails to candidates based on their bio and whether they are being pursued for the job.
If we are proceeding, request availability for a Zoom call. Otherwise, send a polite rejection email.
backstory: >
You are an HR professional named Sarah who works at CrewAI with excellent communication skills and a talent for crafting personalized and thoughtful
emails to job candidates. You understand the importance of maintaining a positive and professional tone in all correspondence.

View File

@@ -0,0 +1,26 @@
send_followup_email:
description: >
Compose personalized follow-up emails for candidates who applied to a specific job.
You will use the candidate's name, bio, and whether the company wants to proceed with them to generate the email.
If the candidate is proceeding, ask them for their availability for a Zoom call in the upcoming days.
If not, send a polite rejection email.
CANDIDATE DETAILS
-----------------
Candidate ID: {candidate_id}
Name: {name}
Bio:
{bio}
PROCEEDING WITH CANDIDATE: {proceed_with_candidate}
ADDITIONAL INSTRUCTIONS
-----------------------
- If we are proceeding, ask for their availability for a Zoom call within the next few days.
- If we are not proceeding, send a polite rejection email, acknowledging their effort in applying and appreciating their time.
expected_output: >
A personalized email based on the candidate's information. It should be professional and respectful,
either inviting them for a Zoom call or letting them know we are pursuing other candidates.
agent: email_followup_agent

View File

@@ -0,0 +1,35 @@
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
@CrewBase
class LeadResponseCrew:
"""Lead Response Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def email_followup_agent(self) -> Agent:
return Agent(
config=self.agents_config["email_followup_agent"],
verbose=True,
allow_delegation=False,
)
@task
def send_followup_email_task(self) -> Task:
return Task(
config=self.tasks_config["send_followup_email"],
verbose=True,
)
@crew
def crew(self) -> Crew:
"""Creates the Lead Response Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)

View File

@@ -0,0 +1,9 @@
hr_evaluation_agent:
role: >
Senior HR Evaluation Expert
goal: >
Analyze candidates' qualifications and compare them against the job description to provide a score and reasoning.
backstory: >
As a Senior HR Evaluation Expert, you have extensive experience in assessing candidate profiles. You excel at
evaluating how well candidates match job descriptions by analyzing their skills, experience, cultural fit, and
growth potential. Your professional background allows you to provide comprehensive evaluations with clear reasoning.

View File

@@ -0,0 +1,32 @@
evaluate_candidate:
description: >
Evaluate a candidate's bio based on the provided job description.
Use your expertise to carefully assess how well the candidate fits the job requirements. Consider key factors such as:
- Skill match
- Relevant experience
- Cultural fit
- Growth potential
CANDIDATE BIO
-------------
Candidate ID: {candidate_id}
Name: {name}
Bio:
{bio}
JOB DESCRIPTION
---------------
{job_description}
ADDITIONAL INSTRUCTIONS
-----------------------
Your final answer MUST include:
- The candidates unique ID
- A score between 1 and 100. Don't use numbers like 100, 75, or 50. Instead, use specific numbers like 87, 63, or 42.
- A detailed reasoning, considering the candidates skill match, experience, cultural fit, and growth potential.
{additional_instructions}
expected_output: >
A very specific score from 1 to 100 for the candidate, along with a detailed reasoning explaining why you assigned this score.
agent: hr_evaluation_agent

View File

@@ -0,0 +1,35 @@
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from lead_score_flow.types import CandidateScore
@CrewBase
class LeadScoreCrew:
"""Lead Score Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def hr_evaluation_agent(self) -> Agent:
return Agent(
config=self.agents_config["hr_evaluation_agent"],
verbose=True,
)
@task
def evaluate_candidate_task(self) -> Task:
return Task(
config=self.tasks_config["evaluate_candidate"],
output_pydantic=CandidateScore,
)
@crew
def crew(self) -> Crew:
"""Creates the Lead Score Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)

View File

@@ -0,0 +1,31 @@
id,name,email,bio,skills
1,John Doe,johndoe@example.com,"John is a passionate junior developer with a strong background in front-end technologies. He recently completed a web development bootcamp, where he built multiple responsive websites using React, CSS, and HTML. John is eager to apply his skills in a real-world setting and grow as a developer. He is highly detail-oriented and a fast learner.","React, CSS, HTML, Git"
2,Sarah Lee,sarahlee@example.com,"Sarah is a self-taught developer who has been building personal projects for the past year. Her portfolio includes a fully responsive personal blog and a task manager app, both built using React and Next.js. She enjoys the challenge of problem-solving and is constantly expanding her skill set through online courses. Sarah thrives in collaborative environments and is excited to contribute to team projects.","React, Next.js, JavaScript, CSS, HTML"
3,Michael Young,michaelyoung@example.com,"Michael recently graduated from a coding bootcamp and is skilled in web development, particularly in React-based applications. During his bootcamp, he worked on a capstone project where he developed a social media dashboard using React, JavaScript, and Git for version control. Michael is passionate about technology and is looking for an opportunity to apply his skills in a dynamic team environment.","React, JavaScript, CSS, Git"
4,Linda Smith,lindasmith@example.com,"Linda is an experienced full-stack developer with a focus on front-end technologies. She has over three years of experience working with React and Next.js. Recently, she has been exploring AI integrations, using the Vercel AI SDK and CrewAI to enhance user experiences in web applications. Linda excels at creating seamless, user-friendly interfaces and optimizing performance.","React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs"
5,Tom Brown,tombrown@example.com,"Tom is a mid-level developer with hands-on experience working on commercial projects using React and Next.js. He has built several customer-facing websites and eCommerce platforms, focusing on performance optimization and SEO. He is proficient in REST APIs and enjoys building scalable web solutions that improve user engagement.","React, Next.js, CSS, HTML, Git, REST APIs"
6,Kate Adams,kateadams@example.com,"Kate is an AI enthusiast with a solid background in front-end development and experience using the Vercel AI SDK and CrewAI. She has contributed to projects that leverage AI to improve user interaction and personalization. Kate is passionate about staying at the cutting edge of technology and is excited to work on projects that push the boundaries of what's possible.","React, Next.js, Vercel AI SDK, CrewAI, JavaScript, Git"
7,Robert Johnson,robertjohnson@example.com,"Robert is a highly skilled front-end developer with a deep knowledge of React and AI-powered applications. He has worked on multiple projects that integrate AI to provide enhanced user experiences, including a recommendation engine built using the Vercel AI SDK. Robert is known for his attention to detail and ability to produce high-quality, maintainable code.","React, Next.js, JavaScript, Vercel AI SDK, CrewAI, CSS, Git, REST APIs"
8,Emily Davis,emilydavis@example.com,"Emily is a beginner developer with a passion for learning and growing within the web development space. She has been building her foundation in HTML, CSS, and JavaScript by working on personal projects and completing online tutorials. Emily is looking for an opportunity to work on real-world projects and contribute to a team while continuing to develop her technical skills.","HTML, CSS, JavaScript"
9,James Wilson,jameswilson@example.com,"James is an intermediate developer with experience working primarily with React. He is eager to explore AI-driven projects and has recently started experimenting with Next.js and the Vercel AI SDK. James enjoys learning new technologies and applying them to solve real-world problems. He is looking for a role that will allow him to grow his skills and work on innovative projects.","React, JavaScript, Next.js, Git"
10,Amy White,amywhite@example.com,"Amy is a senior developer with extensive experience in full-stack development and AI integrations. She has led multiple projects, working with AI-powered tools such as CrewAI and the Vercel AI SDK to create dynamic, personalized web applications. Amy is passionate about mentoring junior developers and has a proven track record of delivering high-quality products.","React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs, Git"
11,Jessica Brown,jessicabrown@example.com,"Jessica is a motivated junior developer with a strong foundation in React and Next.js. She has recently completed an internship where she worked on a team to build a responsive web application for a local business. Jessica is eager to continue building her skills and gain more experience in AI technologies.","React, Next.js, JavaScript, CSS"
12,Daniel Martinez,danielmartinez@example.com,"Daniel is a front-end developer with several years of experience working with React. He has recently started integrating AI-driven features into his projects using the Vercel AI SDK and CrewAI. Daniel enjoys working on projects that challenge him to think outside the box and is always looking for ways to improve the user experience.","React, Next.js, Vercel AI SDK, CrewAI, JavaScript, Git"
13,Olivia Clark,oliviaclark@example.com,"Olivia is a self-starter with a passion for web development. She has built several personal projects using React, focusing on improving her problem-solving skills. Olivia has a basic understanding of AI integrations and is eager to apply what she's learned in a professional setting.","React, JavaScript, CSS, HTML, Git"
14,Matthew Evans,matthewevans@example.com,"Matthew is an experienced developer with expertise in full-stack development. He has worked on several AI-driven front-end applications, integrating advanced technologies such as the Vercel AI SDK and CrewAI. Matthew is passionate about creating user-friendly, high-performance web applications and enjoys tackling complex technical challenges.","React, Next.js, JavaScript, Vercel AI SDK, CrewAI, Git, REST APIs"
15,Sophia Baker,sophiabaker@example.com,"Sophia is an entry-level developer who has recently started learning React and building personal projects. She is excited to continue growing her skills and has a particular interest in AI-powered web applications. Sophia is eager to learn from more experienced developers and contribute to a collaborative team.","React, CSS, HTML, Git"
16,Joshua Harris,joshuaharris@example.com,"Joshua is a mid-level developer specializing in React and Next.js. He has experience building scalable web applications for eCommerce platforms and is familiar with REST APIs. Joshua is always looking for new ways to improve his code and enjoys working in a fast-paced, dynamic environment.","React, Next.js, JavaScript, REST APIs, Git"
17,Chloe Turner,chloeturner@example.com,"Chloe is a developer passionate about AI-powered applications. She has strong skills in both CrewAI and the Vercel AI SDK, which she has used to create personalized, data-driven user experiences. Chloe is looking to work on cutting-edge projects where she can continue to grow her skills and contribute to innovative solutions.","React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs, CSS"
18,Luke Roberts,lukeroberts@example.com,"Luke is a junior developer focused on building user-friendly React applications with clean, efficient code. He has a strong understanding of front-end fundamentals and is eager to continue building his skills in more advanced technologies, such as Next.js and AI integrations.","React, JavaScript, CSS, HTML"
19,Emma Mitchell,emmamitchell@example.com,"Emma is a web developer with strong skills in integrating AI solutions into front-end projects. She has experience working with both the Vercel AI SDK and CrewAI and enjoys creating applications that provide a seamless user experience. Emma is looking to join a team where she can contribute her technical skills and continue to grow as a developer.","React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs"
20,Henry Garcia,henrygarcia@example.com,"Henry is a recent graduate with a focus on AI-powered web applications. He has completed several projects, including a Next.js app that leverages the Vercel AI SDK for personalized recommendations. Henry is passionate about applying AI to solve real-world problems and is eager to join a team that shares his enthusiasm.","React, JavaScript, Vercel AI SDK, CrewAI, Next.js, Git"
21,Grace Hill,gracehill@example.com,"Grace is a junior developer with a strong foundation in web development and a growing interest in AI technologies. She has built multiple personal projects using React and JavaScript, including a weather app and a blog site. Grace is eager to join a team where she can expand her knowledge of Next.js and AI-driven solutions.","React, JavaScript, CSS, HTML, Git"
22,David Foster,davidfoster@example.com,"David is a mid-level React developer with experience in building responsive web applications using Next.js. He has worked on several eCommerce projects and is proficient in modern front-end technologies. David has recently started exploring AI integrations using the Vercel AI SDK and is looking for a role where he can apply these skills.","React, Next.js, JavaScript, CSS, HTML, Git"
23,Isabella Russell,isabellarussell@example.com,"Isabella is an entry-level developer with basic React knowledge and a passion for learning new technologies. She has completed several online courses and built personal projects focused on improving her front-end development skills. Isabella is looking for an opportunity to gain hands-on experience and contribute to a real-world project.","React, CSS, HTML, JavaScript"
24,Ethan Reed,ethanreed@example.com,"Ethan is a self-taught web developer with experience in full-stack development and AI-driven solutions. He has built several web applications using React, Next.js, and the Vercel AI SDK. Ethan enjoys tackling complex problems and is excited to continue working on AI-powered projects that enhance user experience.","React, Next.js, JavaScript, CrewAI, Vercel AI SDK, REST APIs"
25,Abigail Ward,abigailward@example.com,"Abigail is an intermediate developer with strong React skills and experience in integrating AI into web applications. She has worked on projects that leverage the Vercel AI SDK to deliver personalized content to users. Abigail is passionate about user experience and enjoys building applications that are both functional and visually appealing.","React, Next.js, JavaScript, Vercel AI SDK, CSS, Git"
26,Aiden Bailey,aidenbailey@example.com,"Aiden is an experienced full-stack developer with a focus on front-end technologies and AI-powered tools. He has led several projects that use CrewAI and the Vercel AI SDK to provide advanced AI-driven features. Aiden is excited to join a team where he can continue building innovative solutions and mentor junior developers.","React, Next.js, JavaScript, CrewAI, Vercel AI SDK, REST APIs"
27,Lily King,lilyking@example.com,"Lily is a junior developer with a solid understanding of React. She has worked on a few personal projects, including a to-do list app and a portfolio website. Lily is eager to contribute to AI-driven projects and is currently learning Next.js to improve her front-end development skills.","React, JavaScript, CSS, HTML, Git"
28,Benjamin Turner,benjaminturner@example.com,"Benjamin is a front-end developer with experience in modern web technologies and AI integrations. He has contributed to several projects that use the Vercel AI SDK and CrewAI to provide personalized user experiences. Benjamin is passionate about building scalable web applications and improving his skills in AI-powered solutions.","React, Next.js, Vercel AI SDK, CrewAI, JavaScript, CSS"
29,Zoe Barnes,zoebarnes@example.com,"Zoe is a junior developer looking to grow her skills in React and AI-driven web applications. She has built several personal projects and is constantly learning new technologies to improve her code. Zoe is excited to work on real-world projects where she can continue developing her skills and gain experience in AI integrations.","React, CSS, HTML, JavaScript, Git"
30,Alexander Cook,alexandercook@example.com,"Alexander is an experienced developer specializing in building high-performance web applications using React and Next.js. He has worked on projects that leverage CrewAI and the Vercel AI SDK to enhance user engagement through personalized features. Alexander enjoys working in fast-paced environments and collaborating with teams to build innovative solutions.","React, Next.js, JavaScript, CrewAI, Vercel AI SDK, REST APIs"
1 id name email bio skills
2 1 John Doe johndoe@example.com John is a passionate junior developer with a strong background in front-end technologies. He recently completed a web development bootcamp, where he built multiple responsive websites using React, CSS, and HTML. John is eager to apply his skills in a real-world setting and grow as a developer. He is highly detail-oriented and a fast learner. React, CSS, HTML, Git
3 2 Sarah Lee sarahlee@example.com Sarah is a self-taught developer who has been building personal projects for the past year. Her portfolio includes a fully responsive personal blog and a task manager app, both built using React and Next.js. She enjoys the challenge of problem-solving and is constantly expanding her skill set through online courses. Sarah thrives in collaborative environments and is excited to contribute to team projects. React, Next.js, JavaScript, CSS, HTML
4 3 Michael Young michaelyoung@example.com Michael recently graduated from a coding bootcamp and is skilled in web development, particularly in React-based applications. During his bootcamp, he worked on a capstone project where he developed a social media dashboard using React, JavaScript, and Git for version control. Michael is passionate about technology and is looking for an opportunity to apply his skills in a dynamic team environment. React, JavaScript, CSS, Git
5 4 Linda Smith lindasmith@example.com Linda is an experienced full-stack developer with a focus on front-end technologies. She has over three years of experience working with React and Next.js. Recently, she has been exploring AI integrations, using the Vercel AI SDK and CrewAI to enhance user experiences in web applications. Linda excels at creating seamless, user-friendly interfaces and optimizing performance. React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs
6 5 Tom Brown tombrown@example.com Tom is a mid-level developer with hands-on experience working on commercial projects using React and Next.js. He has built several customer-facing websites and eCommerce platforms, focusing on performance optimization and SEO. He is proficient in REST APIs and enjoys building scalable web solutions that improve user engagement. React, Next.js, CSS, HTML, Git, REST APIs
7 6 Kate Adams kateadams@example.com Kate is an AI enthusiast with a solid background in front-end development and experience using the Vercel AI SDK and CrewAI. She has contributed to projects that leverage AI to improve user interaction and personalization. Kate is passionate about staying at the cutting edge of technology and is excited to work on projects that push the boundaries of what's possible. React, Next.js, Vercel AI SDK, CrewAI, JavaScript, Git
8 7 Robert Johnson robertjohnson@example.com Robert is a highly skilled front-end developer with a deep knowledge of React and AI-powered applications. He has worked on multiple projects that integrate AI to provide enhanced user experiences, including a recommendation engine built using the Vercel AI SDK. Robert is known for his attention to detail and ability to produce high-quality, maintainable code. React, Next.js, JavaScript, Vercel AI SDK, CrewAI, CSS, Git, REST APIs
9 8 Emily Davis emilydavis@example.com Emily is a beginner developer with a passion for learning and growing within the web development space. She has been building her foundation in HTML, CSS, and JavaScript by working on personal projects and completing online tutorials. Emily is looking for an opportunity to work on real-world projects and contribute to a team while continuing to develop her technical skills. HTML, CSS, JavaScript
10 9 James Wilson jameswilson@example.com James is an intermediate developer with experience working primarily with React. He is eager to explore AI-driven projects and has recently started experimenting with Next.js and the Vercel AI SDK. James enjoys learning new technologies and applying them to solve real-world problems. He is looking for a role that will allow him to grow his skills and work on innovative projects. React, JavaScript, Next.js, Git
11 10 Amy White amywhite@example.com Amy is a senior developer with extensive experience in full-stack development and AI integrations. She has led multiple projects, working with AI-powered tools such as CrewAI and the Vercel AI SDK to create dynamic, personalized web applications. Amy is passionate about mentoring junior developers and has a proven track record of delivering high-quality products. React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs, Git
12 11 Jessica Brown jessicabrown@example.com Jessica is a motivated junior developer with a strong foundation in React and Next.js. She has recently completed an internship where she worked on a team to build a responsive web application for a local business. Jessica is eager to continue building her skills and gain more experience in AI technologies. React, Next.js, JavaScript, CSS
13 12 Daniel Martinez danielmartinez@example.com Daniel is a front-end developer with several years of experience working with React. He has recently started integrating AI-driven features into his projects using the Vercel AI SDK and CrewAI. Daniel enjoys working on projects that challenge him to think outside the box and is always looking for ways to improve the user experience. React, Next.js, Vercel AI SDK, CrewAI, JavaScript, Git
14 13 Olivia Clark oliviaclark@example.com Olivia is a self-starter with a passion for web development. She has built several personal projects using React, focusing on improving her problem-solving skills. Olivia has a basic understanding of AI integrations and is eager to apply what she's learned in a professional setting. React, JavaScript, CSS, HTML, Git
15 14 Matthew Evans matthewevans@example.com Matthew is an experienced developer with expertise in full-stack development. He has worked on several AI-driven front-end applications, integrating advanced technologies such as the Vercel AI SDK and CrewAI. Matthew is passionate about creating user-friendly, high-performance web applications and enjoys tackling complex technical challenges. React, Next.js, JavaScript, Vercel AI SDK, CrewAI, Git, REST APIs
16 15 Sophia Baker sophiabaker@example.com Sophia is an entry-level developer who has recently started learning React and building personal projects. She is excited to continue growing her skills and has a particular interest in AI-powered web applications. Sophia is eager to learn from more experienced developers and contribute to a collaborative team. React, CSS, HTML, Git
17 16 Joshua Harris joshuaharris@example.com Joshua is a mid-level developer specializing in React and Next.js. He has experience building scalable web applications for eCommerce platforms and is familiar with REST APIs. Joshua is always looking for new ways to improve his code and enjoys working in a fast-paced, dynamic environment. React, Next.js, JavaScript, REST APIs, Git
18 17 Chloe Turner chloeturner@example.com Chloe is a developer passionate about AI-powered applications. She has strong skills in both CrewAI and the Vercel AI SDK, which she has used to create personalized, data-driven user experiences. Chloe is looking to work on cutting-edge projects where she can continue to grow her skills and contribute to innovative solutions. React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs, CSS
19 18 Luke Roberts lukeroberts@example.com Luke is a junior developer focused on building user-friendly React applications with clean, efficient code. He has a strong understanding of front-end fundamentals and is eager to continue building his skills in more advanced technologies, such as Next.js and AI integrations. React, JavaScript, CSS, HTML
20 19 Emma Mitchell emmamitchell@example.com Emma is a web developer with strong skills in integrating AI solutions into front-end projects. She has experience working with both the Vercel AI SDK and CrewAI and enjoys creating applications that provide a seamless user experience. Emma is looking to join a team where she can contribute her technical skills and continue to grow as a developer. React, Next.js, JavaScript, Vercel AI SDK, CrewAI, REST APIs
21 20 Henry Garcia henrygarcia@example.com Henry is a recent graduate with a focus on AI-powered web applications. He has completed several projects, including a Next.js app that leverages the Vercel AI SDK for personalized recommendations. Henry is passionate about applying AI to solve real-world problems and is eager to join a team that shares his enthusiasm. React, JavaScript, Vercel AI SDK, CrewAI, Next.js, Git
22 21 Grace Hill gracehill@example.com Grace is a junior developer with a strong foundation in web development and a growing interest in AI technologies. She has built multiple personal projects using React and JavaScript, including a weather app and a blog site. Grace is eager to join a team where she can expand her knowledge of Next.js and AI-driven solutions. React, JavaScript, CSS, HTML, Git
23 22 David Foster davidfoster@example.com David is a mid-level React developer with experience in building responsive web applications using Next.js. He has worked on several eCommerce projects and is proficient in modern front-end technologies. David has recently started exploring AI integrations using the Vercel AI SDK and is looking for a role where he can apply these skills. React, Next.js, JavaScript, CSS, HTML, Git
24 23 Isabella Russell isabellarussell@example.com Isabella is an entry-level developer with basic React knowledge and a passion for learning new technologies. She has completed several online courses and built personal projects focused on improving her front-end development skills. Isabella is looking for an opportunity to gain hands-on experience and contribute to a real-world project. React, CSS, HTML, JavaScript
25 24 Ethan Reed ethanreed@example.com Ethan is a self-taught web developer with experience in full-stack development and AI-driven solutions. He has built several web applications using React, Next.js, and the Vercel AI SDK. Ethan enjoys tackling complex problems and is excited to continue working on AI-powered projects that enhance user experience. React, Next.js, JavaScript, CrewAI, Vercel AI SDK, REST APIs
26 25 Abigail Ward abigailward@example.com Abigail is an intermediate developer with strong React skills and experience in integrating AI into web applications. She has worked on projects that leverage the Vercel AI SDK to deliver personalized content to users. Abigail is passionate about user experience and enjoys building applications that are both functional and visually appealing. React, Next.js, JavaScript, Vercel AI SDK, CSS, Git
27 26 Aiden Bailey aidenbailey@example.com Aiden is an experienced full-stack developer with a focus on front-end technologies and AI-powered tools. He has led several projects that use CrewAI and the Vercel AI SDK to provide advanced AI-driven features. Aiden is excited to join a team where he can continue building innovative solutions and mentor junior developers. React, Next.js, JavaScript, CrewAI, Vercel AI SDK, REST APIs
28 27 Lily King lilyking@example.com Lily is a junior developer with a solid understanding of React. She has worked on a few personal projects, including a to-do list app and a portfolio website. Lily is eager to contribute to AI-driven projects and is currently learning Next.js to improve her front-end development skills. React, JavaScript, CSS, HTML, Git
29 28 Benjamin Turner benjaminturner@example.com Benjamin is a front-end developer with experience in modern web technologies and AI integrations. He has contributed to several projects that use the Vercel AI SDK and CrewAI to provide personalized user experiences. Benjamin is passionate about building scalable web applications and improving his skills in AI-powered solutions. React, Next.js, Vercel AI SDK, CrewAI, JavaScript, CSS
30 29 Zoe Barnes zoebarnes@example.com Zoe is a junior developer looking to grow her skills in React and AI-driven web applications. She has built several personal projects and is constantly learning new technologies to improve her code. Zoe is excited to work on real-world projects where she can continue developing her skills and gain experience in AI integrations. React, CSS, HTML, JavaScript, Git
31 30 Alexander Cook alexandercook@example.com Alexander is an experienced developer specializing in building high-performance web applications using React and Next.js. He has worked on projects that leverage CrewAI and the Vercel AI SDK to enhance user engagement through personalized features. Alexander enjoys working in fast-paced environments and collaborating with teams to build innovative solutions. React, Next.js, JavaScript, CrewAI, Vercel AI SDK, REST APIs

View File

@@ -0,0 +1,214 @@
#!/usr/bin/env python
import asyncio
from typing import List
from crewai.flow.flow import Flow, listen, or_, router, start
from pydantic import BaseModel
from lead_score_flow.constants import JOB_DESCRIPTION
from lead_score_flow.crews.lead_response_crew.lead_response_crew import LeadResponseCrew
from lead_score_flow.crews.lead_score_crew.lead_score_crew import LeadScoreCrew
from lead_score_flow.types import Candidate, CandidateScore, ScoredCandidate
from lead_score_flow.utils.candidateUtils import combine_candidates_with_scores
class LeadScoreState(BaseModel):
candidates: List[Candidate] = []
candidate_score: List[CandidateScore] = []
hydrated_candidates: List[ScoredCandidate] = []
scored_leads_feedback: str = ""
class LeadScoreFlow(Flow[LeadScoreState]):
initial_state = LeadScoreState
@start()
def load_leads(self):
import csv
from pathlib import Path
# Get the path to leads.csv in the same directory
current_dir = Path(__file__).parent
csv_file = current_dir / "leads.csv"
candidates = []
with open(csv_file, mode="r", newline="", encoding="utf-8") as file:
reader = csv.DictReader(file)
for row in reader:
# Create a Candidate object for each row
print("Row:", row)
candidate = Candidate(**row)
candidates.append(candidate)
# Update the state with the loaded candidates
self.state.candidates = candidates
@listen(or_(load_leads, "scored_leads_feedback"))
async def score_leads(self):
print("Scoring leads")
tasks = []
async def score_single_candidate(candidate: Candidate):
result = await (
LeadScoreCrew()
.crew()
.kickoff_async(
inputs={
"candidate_id": candidate.id,
"name": candidate.name,
"bio": candidate.bio,
"job_description": JOB_DESCRIPTION,
"additional_instructions": self.state.scored_leads_feedback,
}
)
)
self.state.candidate_score.append(result.pydantic)
for candidate in self.state.candidates:
print("Scoring candidate:", candidate.name)
task = asyncio.create_task(score_single_candidate(candidate))
tasks.append(task)
candidate_scores = await asyncio.gather(*tasks)
print("Finished scoring leads: ", len(candidate_scores))
@router(score_leads)
def human_in_the_loop(self):
print("Finding the top 3 candidates for human to review")
# Combine candidates with their scores using the helper function
self.state.hydrated_candidates = combine_candidates_with_scores(
self.state.candidates, self.state.candidate_score
)
# Sort the scored candidates by their score in descending order
sorted_candidates = sorted(
self.state.hydrated_candidates, key=lambda c: c.score, reverse=True
)
self.state.hydrated_candidates = sorted_candidates
# Select the top 3 candidates
top_candidates = sorted_candidates[:3]
print("Here are the top 3 candidates:")
for candidate in top_candidates:
print(
f"ID: {candidate.id}, Name: {candidate.name}, Score: {candidate.score}, Reason: {candidate.reason}"
)
# Present options to the user
print("\nPlease choose an option:")
print("1. Quit")
print("2. Redo lead scoring with additional feedback")
print("3. Proceed with writing emails to all leads")
choice = input("Enter the number of your choice: ")
if choice == "1":
print("Exiting the program.")
exit()
elif choice == "2":
feedback = input(
"\nPlease provide additional feedback on what you're looking for in candidates:\n"
)
self.state.scored_leads_feedback = feedback
print("\nRe-running lead scoring with your feedback...")
return "scored_leads_feedback"
elif choice == "3":
print("\nProceeding to write emails to all leads.")
return "generate_emails"
else:
print("\nInvalid choice. Please try again.")
return "human_in_the_loop"
@listen("generate_emails")
async def write_and_save_emails(self):
import re
from pathlib import Path
print("Writing and saving emails for all leads.")
# Determine the top 3 candidates to proceed with
top_candidate_ids = {
candidate.id for candidate in self.state.hydrated_candidates[:3]
}
tasks = []
# Create the directory 'email_responses' if it doesn't exist
output_dir = Path(__file__).parent / "email_responses"
print("output_dir:", output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
async def write_email(candidate):
# Check if the candidate is among the top 3
proceed_with_candidate = candidate.id in top_candidate_ids
# Kick off the LeadResponseCrew for each candidate
result = await (
LeadResponseCrew()
.crew()
.kickoff_async(
inputs={
"candidate_id": candidate.id,
"name": candidate.name,
"bio": candidate.bio,
"proceed_with_candidate": proceed_with_candidate,
}
)
)
# Sanitize the candidate's name to create a valid filename
safe_name = re.sub(r"[^a-zA-Z0-9_\- ]", "", candidate.name)
filename = f"{safe_name}.txt"
print("Filename:", filename)
# Write the email content to a text file
file_path = output_dir / filename
with open(file_path, "w", encoding="utf-8") as f:
f.write(result.raw)
# Return a message indicating the email was saved
return f"Email saved for {candidate.name} as {filename}"
# Create tasks for all candidates
for candidate in self.state.hydrated_candidates:
task = asyncio.create_task(write_email(candidate))
tasks.append(task)
# Run all email-writing tasks concurrently and collect results
email_results = await asyncio.gather(*tasks)
# After all emails have been generated and saved
print("\nAll emails have been written and saved to 'email_responses' folder.")
for message in email_results:
print(message)
async def run_flow():
"""
Run the flow.
"""
lead_score_flow = LeadScoreFlow()
lead_score_flow.kickoff()
async def plot_flow():
"""
Plot the flow.
"""
lead_score_flow = LeadScoreFlow()
lead_score_flow.plot()
def main():
asyncio.run(run_flow())
def plot():
asyncio.run(plot_flow())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,31 @@
from pydantic import BaseModel
class JobDescription(BaseModel):
title: str
description: str
skills: str
class Candidate(BaseModel):
id: str
name: str
email: str
bio: str
skills: str
class CandidateScore(BaseModel):
id: str
score: int
reason: str
class ScoredCandidate(BaseModel):
id: str
name: str
email: str
bio: str
skills: str
score: int
reason: str

View File

@@ -0,0 +1,36 @@
from typing import List
from lead_score_flow.types import Candidate, CandidateScore, ScoredCandidate
def combine_candidates_with_scores(
candidates: List[Candidate], candidate_scores: List[CandidateScore]
) -> List[ScoredCandidate]:
"""
Combine the candidates with their scores using a dictionary for efficient lookups.
"""
print("COMBINING CANDIDATES WITH SCORES")
print("SCORES:", candidate_scores)
print("CANDIDATES:", candidates)
# Create a dictionary to map score IDs to their corresponding CandidateScore objects
score_dict = {score.id: score for score in candidate_scores}
print("SCORE DICT:", score_dict)
scored_candidates = []
for candidate in candidates:
score = score_dict.get(candidate.id)
if score:
scored_candidates.append(
ScoredCandidate(
id=candidate.id,
name=candidate.name,
email=candidate.email,
bio=candidate.bio,
skills=candidate.skills,
score=score.score,
reason=score.reason,
)
)
print("SCORED CANDIDATES:", scored_candidates)
return scored_candidates

3
meeting_assistant_flow/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.env
__pycache__/
new_tasks.csv

View File

@@ -0,0 +1,149 @@
# Meeting Assistant Flow
Welcome to the Meeting Assistant Flow project, powered by [crewAI](https://crewai.com). This example demonstrates how you can leverage Flows from crewAI to automate the process of managing meetings, including scheduling, note-taking, and follow-up actions. By utilizing Flows, the process becomes much simpler and more efficient.
## Overview
This flow will guide you through the process of setting up an automated meeting assistant. Here's a brief overview of what will happen in this flow:
1. **Load Meeting Notes**: The flow starts by loading the meeting notes from a file named `meeting_notes.txt`.
2. **Generate Tasks from Meeting Transcript**: The `MeetingAssistantCrew` is kicked off to generate tasks from the meeting transcript.
3. **Add Tasks to Trello**: The generated tasks are added to a Trello board.
4. **Save New Tasks to CSV**: The new tasks are saved to a CSV file named `new_tasks.csv`.
5. **Send Slack Notification**: A Slack notification is sent to a specified channel, informing about the new tasks added to Trello.
By following this flow, you can efficiently automate the process of managing meetings, leveraging the power of multiple AI agents to handle different aspects of the meeting workflow.
## Installation
Ensure you have Python >=3.10 <=3.13 installed on your system. This project uses [Poetry](https://python-poetry.org/) for dependency management and package handling, offering a seamless setup and execution experience.
First, if you haven't already, install Poetry:
```bash
pip install poetry
```
Next, navigate to your project directory and install the dependencies:
1. First lock the dependencies and then install them:
```bash
crewai install
```
### Customizing & Dependencies
**Add your `OPENAI_API_KEY` into the `.env` file**
**Add your `SERPER_API_KEY` into the `.env` file**
**Add your `TRELLO_API_KEY`, `TRELLO_TOKEN`, `TRELLO_BOARD_ID`, and `TRELLO_LIST_ID` into the `.env` file**
**Add your `SLACK_TOKEN` and `SLACK_CHANNEL_ID` into the `.env` file**
To customize the behavior of the meeting assistant flow, you can update the agents and tasks defined in the `MeetingSchedulerCrew`, `NoteTakingCrew`, and `FollowUpCrew`. If you want to adjust the flow itself, you will need to modify the flow in `main.py`.
- **Agents and Tasks**: Modify `src/meeting_assistant_flow/config/agents.yaml` to define your agents and `src/meeting_assistant_flow/config/tasks.yaml` to define your tasks. This is where you can customize how meetings are scheduled, notes are taken, and follow-up actions are managed.
- **Flow Adjustments**: Modify `src/meeting_assistant_flow/main.py` to adjust the flow. This is where you can change how the flow orchestrates the different crews and tasks.
### Setting Up Trello
To enable the meeting assistant flow to interact with Trello, follow these steps to set up your Trello API credentials:
1. **Generate Trello API Key**:
- Visit the [Trello API Key page](https://trello.com/power-ups/admin/new) and log in with your Trello account.
- Click on the "Create a Power-Up" button.
- Fill in the required details for your Power-Up and click "Create".
- Once created, you will see your API key. Copy this key and add it to your `.env` file as `TRELLO_API_KEY`.
2. **Generate Trello Token**:
- Visit the [Trello Power Up page](https://developer.atlassian.com/cloud/trello/) to learn how to create a Power-Up and generate your token.
- Scroll down to the "OAuth" section and click on the "Token" link.
- Authorize the application to access your Trello account.
- You will be provided with a token. Copy this token and add it to your `.env` file as `TRELLO_TOKEN`.
3. **Find Trello Board ID**:
- Open Trello and navigate to the board you want to use.
- The board ID is part of the URL. For example, in `https://trello.com/b/BOARD_ID/board-name`, `BOARD_ID` is your board ID.
- Copy this ID and add it to your `.env` file as `TRELLO_BOARD_ID`.
4. **Find Trello List ID**:
- On your Trello board, click on the list where you want to add tasks.
- Click on the three dots (menu) on the top right of the list and select "Copy Link".
- The list ID is part of the URL. For example, in `https://trello.com/c/BOARD_ID/LIST_ID/card-name`, `LIST_ID` is your list ID.
- Copy this ID and add it to your `.env` file as `TRELLO_LIST_ID`.
5. **Set Up Environment Variables**:
- Add the following variables to your `.env` file:
```plaintext
TRELLO_API_KEY=your_trello_api_key
TRELLO_TOKEN=your_trello_token
TRELLO_BOARD_ID=your_trello_board_id
TRELLO_LIST_ID=your_trello_list_id
```
By following these steps, you will have set up your Trello API credentials correctly, allowing the meeting assistant flow to interact with your Trello board and lists.
### Setting Up Slack
To enable the meeting assistant flow to send notifications to Slack, follow these steps to set up your Slack API credentials:
1. **Create a Slack App**: Visit the [Slack API page](https://api.slack.com/apps) and create a new app.
2. **Generate Slack Token**: Under the "OAuth & Permissions" section, generate a token with the necessary permissions.
3. **Find Slack Channel ID**: To find your Slack channel ID, open Slack, go to the channel, and click on the channel name. The channel ID will be in the URL.
4. **Invite Slack Bot to Channel**: Invite the Slack bot to the channel by typing `/invite @your-bot-name` in the channel.
5. **Set Up Environment Variables**: Add the following variables to your `.env` file:
- `SLACK_TOKEN`
- `SLACK_CHANNEL_ID`
## Running the Project
To kickstart your crew of AI agents and begin task execution, run this from the root folder of your project:
```bash
crewai run
```
This command initializes the meeting_assistant_flow, assembling the agents and assigning them tasks as defined in your configuration.
When you kickstart the flow, it will orchestrate multiple crews to perform the tasks. The flow will first load meeting notes, then generate tasks from the transcript, add tasks to Trello, save tasks to a CSV file, and send a Slack notification.
## Understanding Your Flow
The meeting_assistant_flow is composed of multiple AI agents, each with unique roles, goals, and tools. These agents collaborate on a series of tasks, defined in `config/tasks.yaml`, leveraging their collective skills to achieve complex objectives. The `config/agents.yaml` file outlines the capabilities and configurations of each agent in your flow.
### Flow Structure
1. **Load Meeting Notes**: This step loads the meeting notes from a file named `meeting_notes.txt`.
2. **Generate Tasks from Meeting Transcript**: The `MeetingAssistantCrew` is kicked off to generate tasks from the meeting transcript.
3. **Add Tasks to Trello**: The generated tasks are added to a Trello board.
4. **Save New Tasks to CSV**: The new tasks are saved to a CSV file named `new_tasks.csv`.
5. **Send Slack Notification**: A Slack notification is sent to a specified channel, informing about the new tasks added to Trello.
By understanding the flow structure, you can see how multiple crews are orchestrated to work together, each handling a specific part of the meeting management process. This modular approach allows for efficient and scalable meeting automation.
## Support
For support, questions, or feedback regarding the Meeting Assistant Flow or crewAI:
- Visit our [documentation](https://docs.crewai.com)
- Reach out to us through our [GitHub repository](https://github.com/joaomdmoura/crewai)
- [Join our Discord](https://discord.com/invite/X4JWnZnxPb)
- [Chat with our docs](https://chatg.pt/DWjSBZn)
Let's create wonders together with the power and simplicity of crewAI.

View File

@@ -0,0 +1,82 @@
Alex: Hey team, good morning! Thanks for making time for this meeting. Weve got a pretty important task ahead of us—integrating Stripe for our subscription model. We need to get this right to make sure our users have a smooth experience. Hows everyone doing today?
Jordan: Morning, Alex! Im good, thanks. Excited to dive into this. Integrating Stripe sounds like a big job, though. Whats our current approach?
Alex: So, our main objective is to set up Stripe to manage our subscription model. Were looking at three different tiers: Basic, Pro, and Enterprise. We need to set up these tiers in Stripe, integrate them into our app, and ensure everything works seamlessly.
Taylor: Sounds like a plan. Whats the exact breakdown for each subscription tier?
Alex: Heres the pricing were going with:
Basic: $29 per month. This includes basic access to our AI model selection tool and a limited feature set.
Pro: $49 per month. This tier offers additional features and priority support.
Enterprise: $99 per month. This includes all features, custom support, and integration options.
Well need to set these up in Stripe and ensure theyre reflected correctly in the app, both in terms of functionality and user experience.
Jordan: Got it. Ill start on the frontend. For the checkout process, well use Stripe Elements, right?
Alex: Yes, Stripe Elements is the way to go. Its customizable and secure. Make sure the checkout form matches our apps design. We also need to handle potential errors gracefully, such as invalid card details or insufficient funds.
Jordan: Okay, Ill get started on that. Ill also need to update our pricing page to reflect the new subscription tiers. For the checkout form, are there any specific design elements or features you want to highlight?
Alex: The design should be clean and straightforward. Users should easily understand what theyre getting with each plan. We need a clear comparison of features for each tier, and the checkout button should be prominent. Lets also include a tooltip or help icon that explains what happens if they choose a different plan later on.
Jordan: Got it. Ill make sure to include those details. What about the user dashboard? What functionalities do we need there?
Alex: On the user dashboard, we need to provide:
Current plan details and billing info.
Options to upgrade, downgrade, or cancel their subscription.
Access to invoices and payment history.
A way to update payment methods.
The dashboard should be intuitive and reflect the current subscription status in real-time. It should also notify users of any changes, such as successful plan upgrades or payment failures.
Taylor: On the backend side, Ill focus on integrating Stripes API to handle all subscription-related tasks. This includes creating and managing subscriptions, processing payments, and dealing with webhooks for different events.
Alex: Exactly. We need to ensure the backend handles:
Creating subscriptions: When a user selects a plan and completes the payment.
Processing payments: Handling successful and failed payments.
Managing webhooks: For events like invoice payment success or failure, and subscription cancellations.
Taylor: Okay, so well need to handle several specific webhook events. Can we list those out?
Alex: Sure. We need to listen for:
invoice.payment_succeeded: To confirm successful payments and activate or continue the users subscription.
invoice.payment_failed: To notify users of failed payments and prompt them to update their payment information. We should also consider sending an email notification here.
customer.subscription.deleted: To manage cases where users cancel their subscriptions, including updating their access rights and possibly offering them a chance to re-subscribe.
Taylor: Got it. Ill set up webhook handlers for these events and ensure they update our system correctly. Well also need to test these handlers thoroughly. Im thinking of creating a few test scenarios to simulate different events, like payment failures and cancellations.
Jordan: Once Taylor has the backend set up, Ill integrate the frontend with the API. We need to make sure that any changes to the subscription are reflected in real-time on the dashboard.
Alex: Exactly. We should also handle any errors that might come up during the integration process and provide clear notifications to users. For instance, if a payment fails, we should clearly inform the user and provide instructions on how to fix it.
Taylor: Ill prepare a detailed test plan and share it with you both. We should cover manual tests as well as automated tests. This will include testing the whole subscription flow from sign-up to billing to managing the subscription.
Jordan: That makes sense. Ill start working on the frontend components and prepare them for integration. Ill also make sure the Stripe Elements form is correctly styled and integrated. And Ill handle the user notifications for different events, like subscription confirmations and payment errors.
Alex: Excellent. Lets aim to get the initial integration done within the next two weeks. After that, well need a week for testing. During the testing phase, we should ensure all edge cases are covered and everything is functioning as expected.
Jordan: Sounds good to me. Ill update you on my progress and coordinate with Taylor to ensure everything on the frontend matches up with the backend.
Taylor: Same here. Ill get started on the backend tasks and keep you updated on the webhook setup and API requirements.
Alex: Perfect. Well also need to plan for user documentation and support. Once everything is live, we should have clear instructions available for users on how to manage their subscriptions, access invoices, and handle any issues.
Jordan: Definitely. Well need a help section or FAQ that covers common issues and questions about subscriptions.
Taylor: Agreed. Ill also make sure to document the API endpoints and webhook event handlers, so its easier to maintain and troubleshoot in the future.
Alex: Great. Lets set up our next follow-up meeting for next week to review our progress and address any issues that come up. If either of you run into any blockers or need help, dont hesitate to reach out.
Jordan: Will do. Ill start on the frontend tasks today and keep you posted.
Taylor: Ill begin with the backend setup and webhook integration. Looking forward to seeing how everything comes together.
Alex: Awesome. Thanks, everyone. Lets make sure we get this right and provide a smooth experience for our users. Have a great day!
Jordan: You too, Alex. Talk soon!
Taylor: Talk soon. Thanks, everyone!
Alex: Talk soon. Bye for now!

View File

@@ -0,0 +1,20 @@
[tool.poetry]
name = "meeting_assistant_flow"
version = "0.1.0"
description = "meeting_assistant_flow using crewAI"
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = ">=3.10,<=3.13"
crewai = { extras = ["tools"], version = ">=0.67.1,<1.0.0" }
asyncio = "*"
slack-sdk = "^3.33.1"
[tool.poetry.scripts]
meeting_assistant_flow = "meeting_assistant_flow.main:main"
run_flow = "meeting_assistant_flow.main:main"
plot_flow = "meeting_assistant_flow.main:plot"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@@ -0,0 +1,12 @@
meeting_analyzer:
role: >
Meeting Transcript Analysis Agent
goal: >
Analyze the provided meeting transcript and extract important, actionable tasks or issues.
The goal is to break down the meeting content into well-structured,
detailed issues that can be easily understood and uploaded to Trello.
Here is the meeting transcript for your reference:\n\n {transcript}
backstory: >
You are an expert in analyzing meeting transcripts and summarizing the discussions into actionable tasks.
Your ability to identify important issues helps ensure teams can follow up and address key points effectively.

View File

@@ -0,0 +1,13 @@
analyze_meeting:
description: >
Analyze the provided meeting transcript and generate a set of detailed,
well-organized issues based on the discussion.
Focus on breaking down the transcript into manageable tasks or issues,
making sure to document each issue thoroughly with steps to reproduce, acceptance criteria,
and any other relevant details.
Here is the meeting transcript for your reference:\n\n {transcript}
expected_output: >
A JSON list of issues with titles and bodies, containing clear instructions,
steps to reproduce, and acceptance criteria where applicable.
agent: meeting_analyzer

View File

@@ -0,0 +1,40 @@
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from langchain_openai import ChatOpenAI
from meeting_assistant_flow.types import (
MeetingTaskList,
)
@CrewBase
class MeetingAssistantCrew:
"""Meeting Assistant Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
llm = ChatOpenAI(model="gpt-4")
@agent
def meeting_analyzer(self) -> Agent:
return Agent(
config=self.agents_config["meeting_analyzer"],
llm=self.llm,
)
@task
def analyze_meeting(self) -> Task:
return Task(
config=self.tasks_config["analyze_meeting"],
output_pydantic=MeetingTaskList,
)
@crew
def crew(self) -> Crew:
"""Creates the Meeting Issue Generation Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env python
import asyncio
import csv
import os
from typing import List
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel
from meeting_assistant_flow.crews.meeting_assistant_crew.meeting_assistant_crew import (
MeetingAssistantCrew,
)
from meeting_assistant_flow.types import MeetingTask
from meeting_assistant_flow.utils.slack_helper import send_message_to_channel
from meeting_assistant_flow.utils.trello_helper import save_tasks_to_trello
class MeetingState(BaseModel):
transcript: str = "Meeting transcript goes here"
tasks: List[MeetingTask] = []
class MeetingFlow(Flow[MeetingState]):
initial_state = MeetingState
@start()
def load_meeting_notes(self):
print("Loading Meeting Notes")
print("Current working directory:", os.getcwd())
with open("meeting_notes.txt", "r") as file:
self.state.transcript = file.read()
@listen(load_meeting_notes)
def generate_tasks_from_meeting_transcript(self):
print("Kickoff the Meeting Assistant Crew")
output = (
MeetingAssistantCrew()
.crew()
.kickoff(inputs={"transcript": self.state.transcript})
)
tasks = output["tasks"]
print("TASKS:", tasks)
self.state.tasks = tasks
@listen(generate_tasks_from_meeting_transcript)
def add_tasks_to_trello(self):
print("Adding Tasks to Trello")
save_tasks_to_trello(self.state.tasks)
@listen(generate_tasks_from_meeting_transcript)
def save_new_tasks_to_csv(self):
print("Saving New Tasks to CSV")
with open("new_tasks.csv", "w", newline="") as file:
writer = csv.writer(file)
# Write the header row
writer.writerow(["Name", "Description"])
# Write the task data
for task in self.state.tasks:
writer.writerow([task.name, task.description])
@listen(generate_tasks_from_meeting_transcript)
def send_slack_notification(self):
print("Sending Slack Notification")
message = f"{len(self.state.tasks)} New tasks have been added to Trello!"
send_message_to_channel(message)
async def run_flow():
"""
Run the flow.
"""
meeting_flow = MeetingFlow()
meeting_flow.kickoff()
async def plot_flow():
"""
Plot the flow.
"""
meeting_flow = MeetingFlow()
meeting_flow.plot()
def main():
asyncio.run(run_flow())
def plot():
asyncio.run(plot_flow())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel
class MeetingTask(BaseModel):
name: str
description: str
class MeetingTaskList(BaseModel):
tasks: list[MeetingTask]

View File

@@ -0,0 +1,35 @@
import os
from dotenv import load_dotenv
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
# Load environment variables from a .env file
load_dotenv()
def send_message_to_channel(text: str):
# Get your Slack token and channel ID from the environment variables
SLACK_TOKEN = os.getenv("SLACK_TOKEN")
SLACK_CHANNEL_ID = os.getenv("SLACK_CHANNEL_ID")
client = WebClient(token=SLACK_TOKEN)
try:
# Send a message to the channel
response = client.chat_postMessage(
channel=SLACK_CHANNEL_ID,
text=text,
)
return response
except SlackApiError as e:
print(f"Error sending message: {e.response['error']}")
if __name__ == "__main__":
# Example usage
message = "Hello, world! This is a test message from the Slack Helper."
response = send_message_to_channel(message)
if response:
print("Message sent successfully!")
else:
print("Failed to send message.")

View File

@@ -0,0 +1,76 @@
import os
from typing import List
import requests
from dotenv import load_dotenv
from meeting_assistant_flow.types import MeetingTask
# Load environment variables from .env file
load_dotenv()
# Your Trello API credentials loaded from environment variables
API_KEY = os.getenv("TRELLO_API_KEY")
TOKEN = os.getenv("TRELLO_TOKEN")
# The ID of the Trello board and list where you want to add the cards
BOARD_ID = os.getenv("TRELLO_BOARD_ID")
LIST_ID = os.getenv("TRELLO_LIST_ID")
def create_trello_card(task_title, task_description):
"""
Create a new card in Trello for the given task.
:param task_title: Title of the task (will be the title of the Trello card)
:param task_description: Detailed description of the task (will be the body of the Trello card)
:return: Response object from Trello API call
"""
url = "https://api.trello.com/1/cards"
query = {
"key": API_KEY,
"token": TOKEN,
"idList": LIST_ID,
"name": task_title,
"desc": task_description,
}
response = requests.post(url, params=query)
if response.status_code == 200:
print(f"Task '{task_title}' successfully created in Trello.")
else:
print(f"Failed to create task '{task_title}' in Trello.")
print(response.text)
return response
def save_tasks_to_trello(tasks: List[MeetingTask]):
"""
Save a list of tasks to Trello. Each task is a dictionary with 'title' and 'body'.
:param tasks: List of tasks, where each task is a dict with 'title' and 'body'
"""
for task in tasks:
if task.name and task.description:
create_trello_card(task.name, task.description)
else:
print("Task is missing a title or description. Skipping...")
# Example usage
if __name__ == "__main__":
tasks = [
{
"title": "Add Token Count Progress Indicator to Website",
"body": "I received a suggestion from a colleague to enhance the token count exceeded feature on our website...",
},
{
"title": "Improve Mobile Responsiveness for Dashboard",
"body": "We need to improve the mobile layout of the dashboard for better usability. The sidebar should collapse automatically...",
},
]
save_tasks_to_trello(tasks)

2
write_a_book_with_flows/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.env
__pycache__/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
# Write a Book Flow
Welcome to the Book Writing Flow, powered by [crewAI](https://crewai.com). This template is designed to help you set up a multi-agent AI system with ease, leveraging the powerful and flexible framework provided by crewAI. Our goal is to enable your agents to collaborate effectively on complex tasks, maximizing their collective intelligence and capabilities.
## Overview
This flow will guide you through the process of writing a book by leveraging multiple AI agents, each with specific roles. Here's a brief overview of what will happen in this flow:
1. **Generate Book Outline**: The flow starts by using the `OutlineCrew` to create a comprehensive outline for your book. This crew will search the internet, define the structure, and main topics of the book based on the provided goal and topic.
2. **Write Book Chapters**: Once the outline is ready, the flow will kick off a new crew, `WriteBookChapterCrew`, for each chapter outlined in the previous step. Each crew will be responsible for writing a specific chapter, ensuring that the content is detailed and coherent.
3. **Join and Save Chapters**: In the final step, the flow will combine all the chapters into a single markdown file, creating a complete book. This file will be saved in the root folder of your project.
By following this flow, you can efficiently produce a well-structured and comprehensive book, leveraging the power of multiple AI agents to handle different aspects of the writing process.
## Installation
Ensure you have Python >=3.10 <=3.13 installed on your system. This project uses [Poetry](https://python-poetry.org/) for dependency management and package handling, offering a seamless setup and execution experience.
First, if you haven't already, install Poetry:
```bash
pip install poetry
```
Next, navigate to your project directory and install the dependencies:
1. First lock the dependencies and then install them:
```bash
crewai install
```
### Customizing & Dependencies
**Add your `OPENAI_API_KEY` into the `.env` file**
**Add your `SERPER_API_KEY` into the `.env` file**
To customize the behavior of the book writing flow, you can update the agents and tasks defined in the `OutlineCrew` and `WriteBookChapterCrew`. If you want to adjust the flow itself, you will need to modify the flow in `main.py`.
- **Agents and Tasks**: Modify `src/write_a_book_with_flows/config/agents.yaml` to define your agents and `src/write_a_book_with_flows/config/tasks.yaml` to define your tasks. This is where you can customize how the book outline is generated and how chapters are written.
- **Flow Adjustments**: Modify `src/write_a_book_with_flows/main.py` to adjust the flow. This is where you can change how the flow orchestrates the different crews and tasks.
## Running the Project
To kickstart your crew of AI agents and begin task execution, run this from the root folder of your project:
```bash
crewai run
```
This command initializes the write_a_book_with_flows Crew, assembling the agents and assigning them tasks as defined in your configuration.
When you kickstart the flow, it will orchestrate multiple crews to perform the tasks. The flow will first generate a book outline, then create and run a crew for each chapter, and finally join all the chapters into a single markdown file.
## Understanding Your Flow
The write_a_book_with_flows Flow is composed of multiple AI agents, each with unique roles, goals, and tools. These agents collaborate on a series of tasks, defined in `config/tasks.yaml`, leveraging their collective skills to achieve complex objectives. The `config/agents.yaml` file outlines the capabilities and configurations of each agent in your flow.
### Flow Structure
1. **OutlineCrew**: This crew is responsible for generating the book outline. It defines the structure and main topics of the book based on the provided goal and topic.
2. **WriteBookChapterCrew**: For each chapter outlined by the `OutlineCrew`, a new `WriteBookChapterCrew` is created. Each of these crews is responsible for writing a specific chapter, ensuring detailed and coherent content.
3. **Join and Save**: After all chapters are written, the flow combines them into a single markdown file, creating a complete book.
By understanding the flow structure, you can see how multiple crews are orchestrated to work together, each handling a specific part of the book writing process. This modular approach allows for efficient and scalable book production.
## Support
For support, questions, or feedback regarding the {{crew_name}} Crew or crewAI.
- Visit our [documentation](https://docs.crewai.com)
- Reach out to us through our [GitHub repository](https://github.com/joaomdmoura/crewai)
- [Join our Discord](https://discord.com/invite/X4JWnZnxPb)
- [Chat with our docs](https://chatg.pt/DWjSBZn)
Let's create wonders together with the power and simplicity of crewAI.

View File

@@ -0,0 +1,19 @@
[tool.poetry]
name = "write_a_book_with_flows"
version = "0.1.0"
description = "write_a_book_with_flows using crewAI"
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = ">=3.10,<=3.13"
crewai = { extras = ["tools"], version = ">=0.67.1,<1.0.0" }
asyncio = "*"
[tool.poetry.scripts]
write_a_book_with_flows = "write_a_book_with_flows.main:main"
run_flow = "write_a_book_with_flows.main:main"
plot_flow = "write_a_book_with_flows.main:plot"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@@ -0,0 +1,20 @@
researcher:
role: >
Research Agent
goal: >
Gather comprehensive information about {topic} that will be used to create an organized and well-structured book outline.
Here is some additional information about the author's desired goal for the book:\n\n {goal}
backstory: >
You're a seasoned researcher, known for gathering the best sources and understanding the key elements of any topic.
You aim to collect all relevant information so the book outline can be accurate and informative.
outliner:
role: >
Book Outlining Agent
goal: >
Based on the research, generate a book outline about the following topic: {topic}
The generated outline should include all chapters in sequential order and provide a title and description for each chapter.
Here is some additional information about the author's desired goal for the book:\n\n {goal}
backstory: >
You are a skilled organizer, great at turning scattered information into a structured format.
Your goal is to create clear, concise chapter outlines with all key topics and subtopics covered.

View File

@@ -0,0 +1,22 @@
research_topic:
description: >
Research the provided topic of {topic} to gather the most important information that will
be useful in creating a book outline. Ensure you focus on high-quality, reliable sources.
Here is some additional information about the author's desired goal for the book:\n\n {goal}
expected_output: >
A set of key points and important information about {topic} that will be used to create the outline.
agent: researcher
generate_outline:
description: >
Create a book outline with chapters in sequential order based on the research findings.
Ensure that each chapter has a title and a brief description that highlights the topics and subtopics to be covered.
It's important to note that each chapter is only going to be 3,000 words or less.
Also, make sure that you do not duplicate any chapters or topics in the outline.
Here is some additional information about the author's desired goal for the book:\n\n {goal}
expected_output: >
An outline of chapters, with titles and descriptions of what each chapter will contain.
agent: outliner

View File

@@ -0,0 +1,56 @@
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool
from langchain_openai import ChatOpenAI
from write_a_book_with_flows.types import BookOutline
@CrewBase
class OutlineCrew:
"""Book Outline Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
# llm = ChatOpenAI(model="chatgpt-4o-latest")
llm = ChatOpenAI(model="gpt-4o")
@agent
def researcher(self) -> Agent:
search_tool = SerperDevTool()
return Agent(
config=self.agents_config["researcher"],
tools=[search_tool],
llm=self.llm,
verbose=True,
)
@agent
def outliner(self) -> Agent:
return Agent(
config=self.agents_config["outliner"],
llm=self.llm,
verbose=True,
)
@task
def research_topic(self) -> Task:
return Task(
config=self.tasks_config["research_topic"],
)
@task
def generate_outline(self) -> Task:
return Task(
config=self.tasks_config["generate_outline"], output_pydantic=BookOutline
)
@crew
def crew(self) -> Crew:
"""Creates the Book Outline Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)

View File

@@ -0,0 +1,20 @@
researcher:
role: >
Research Agent
goal: >
Gather comprehensive information about {topic} and {chapter_title} that will be used to enhance the content of the chapter.
Here is some additional information about the author's desired goal for the book and the chapter:\n\n {goal}
Here is the outline description for the chapter:\n\n {chapter_description}
backstory: >
You are an experienced researcher skilled in finding the most relevant and up-to-date information on any given topic.
Your job is to provide insightful data that supports and enriches the writing process for the chapter.
writer:
role: >
Chapter Writer
goal: >
Write a well-structured chapter for the book based on the provided chapter title, goal, and outline.
The chapter should be written in markdown format and contain around 3,000 words.
backstory: >
You are an exceptional writer, known for producing engaging, well-researched, and informative content.
You excel at transforming complex ideas into readable and well-organized chapters.

View File

@@ -0,0 +1,35 @@
research_chapter:
description: >
Research the provided chapter topic, title, and outline to gather additional content that will be helpful in writing the chapter.
Ensure you focus on reliable, high-quality sources of information.
Here is some additional information about the author's desired goal for the book and the chapter:\n\n {goal}
Here is the outline description for the chapter:\n\n {chapter_description}
When researching, consider the following key points:
- you need to gather enough information to write a 3,000-word chapter
- The chapter you are researching needs to fit in well with the rest of the chapters in the book.
Here is the outline of the entire book:\n\n
{book_outline}
expected_output: >
A set of additional insights and information that can be used in writing the chapter.
agent: researcher
write_chapter:
description: >
Write a well-structured chapter based on the chapter title, goal, and outline description.
Each chapter should be written in markdown and should contain around 3,000 words.
Here is the topic for the book: {topic}
Here is the title of the chapter: {chapter_title}
Here is the outline description for the chapter:\n\n {chapter_description}
Important notes:
- The chapter you are writing needs to fit in well with the rest of the chapters in the book.
Here is the outline of the entire book:\n\n
{book_outline}
expected_output: >
A markdown-formatted chapter of around 3,000 words that covers the provided chapter title and outline description.
agent: writer

View File

@@ -0,0 +1,51 @@
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool
from langchain_openai import ChatOpenAI
from write_a_book_with_flows.types import Chapter
@CrewBase
class WriteBookChapterCrew:
"""Write Book Chapter Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
llm = ChatOpenAI(model="gpt-4o")
@agent
def researcher(self) -> Agent:
search_tool = SerperDevTool()
return Agent(
config=self.agents_config["researcher"],
tools=[search_tool],
llm=self.llm,
)
@agent
def writer(self) -> Agent:
return Agent(
config=self.agents_config["writer"],
llm=self.llm,
)
@task
def research_chapter(self) -> Task:
return Task(
config=self.tasks_config["research_chapter"],
)
@task
def write_chapter(self) -> Task:
return Task(config=self.tasks_config["write_chapter"], output_pydantic=Chapter)
@crew
def crew(self) -> Crew:
"""Creates the Write Book Chapter Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)

View File

@@ -0,0 +1,143 @@
#!/usr/bin/env python
import asyncio
from typing import List
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel
from write_a_book_with_flows.crews.write_book_chapter_crew.write_book_chapter_crew import (
WriteBookChapterCrew,
)
from write_a_book_with_flows.types import Chapter, ChapterOutline
from .crews.outline_book_crew.outline_crew import OutlineCrew
class BookState(BaseModel):
title: str = (
"The Current State of AI in September 2024: Trends Across Industries and What's Next"
)
book: List[Chapter] = []
book_outline: List[ChapterOutline] = []
topic: str = (
"Exploring the latest trends in AI across different industries as of September 2024"
)
goal: str = """
The goal of this book is to provide a comprehensive overview of the current state of artificial intelligence in September 2024.
It will delve into the latest trends impacting various industries, analyze significant advancements,
and discuss potential future developments. The book aims to inform readers about cutting-edge AI technologies
and prepare them for upcoming innovations in the field.
"""
class BookFlow(Flow[BookState]):
initial_state = BookState
@start()
def generate_book_outline(self):
print("Kickoff the Book Outline Crew")
output = (
OutlineCrew()
.crew()
.kickoff(inputs={"topic": self.state.topic, "goal": self.state.goal})
)
chapters = output["chapters"]
print("Chapters:", chapters)
self.state.book_outline = chapters
return chapters
@listen(generate_book_outline)
async def write_chapters(self):
print("Writing Book Chapters")
tasks = []
async def write_single_chapter(chapter_outline):
output = await (
WriteBookChapterCrew()
.crew()
.kickoff_async(
inputs={
"goal": self.state.goal,
"topic": self.state.topic,
"chapter_title": chapter_outline.title,
"chapter_description": chapter_outline.description,
"book_outline": [
chapter_outline.model_dump_json()
for chapter_outline in self.state.book_outline
],
}
)
)
title = output["title"]
content = output["content"]
chapter = Chapter(title=title, content=content)
return chapter
for chapter_outline in self.state.book_outline:
print(f"Writing Chapter: {chapter_outline.title}")
print(f"Description: {chapter_outline.description}")
# Schedule each chapter writing task
task = asyncio.create_task(write_single_chapter(chapter_outline))
tasks.append(task)
# Await all chapter writing tasks concurrently
chapters = await asyncio.gather(*tasks)
print("Newly generated chapters:", chapters)
self.state.book.extend(chapters)
print("Book Chapters", self.state.book)
@listen(write_chapters)
async def join_and_save_chapter(self):
print("Joining and Saving Book Chapters")
# Combine all chapters into a single markdown string
book_content = ""
for chapter in self.state.book:
# Add the chapter title as an H1 heading
book_content += f"# {chapter.title}\n\n"
# Add the chapter content
book_content += f"{chapter.content}\n\n"
# The title of the book from self.state.title
book_title = self.state.title
# Create the filename by replacing spaces with underscores and adding .md extension
filename = f"./{book_title.replace(' ', '_')}.md"
# Save the combined content into the file
with open(filename, "w", encoding="utf-8") as file:
file.write(book_content)
print(f"Book saved as {filename}")
return book_content
async def run_flow():
"""
Run the flow.
"""
book_flow = BookFlow()
book_flow.kickoff()
async def plot_flow():
"""
Plot the flow.
"""
book_flow = BookFlow()
book_flow.plot()
def main():
asyncio.run(run_flow())
def plot():
asyncio.run(plot_flow())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,17 @@
from typing import List
from pydantic import BaseModel
class ChapterOutline(BaseModel):
title: str
description: str
class BookOutline(BaseModel):
chapters: List[ChapterOutline]
class Chapter(BaseModel):
title: str
content: str