Reorganize repo structure and upgrade to CrewAI 0.152.0 (#277)

* Reorganize repo structure and upgrade to CrewAI 0.152.0

* chore(gitignore): ignore Python bytecode and __pycache__ across templates

* chore(gitignore): ignore Python bytecode and __pycache__ across templates; clean tracked artifacts

* Update crews/instagram_post/pyproject.toml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Tony Kipkemboi
2025-08-12 12:05:06 -04:00
committed by GitHub
parent 18e1ce703c
commit 7045b059bf
341 changed files with 77344 additions and 13685 deletions

View File

@@ -0,0 +1,3 @@
SERPER_API_KEY=KEY # https://serper.dev/ (free tier)
BROWSERLESS_API_KEY=KEY # https://www.browserless.io/ (free tier)
MODEL='openhermes'

3
crews/instagram_post/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.env
.DS_Store
__pycache__

View File

@@ -0,0 +1,44 @@
# AI Crew for Instagram Post
## Introduction
This project is an example using the CrewAI framework to automate the process of coming up with an instagram post. CrewAI orchestrates autonomous AI agents, enabling them to collaborate and execute complex tasks efficiently.
#### Instagram Post
[![Instagram Post](https://img.youtube.com/vi/lcD0nT8IVTg/0.jpg)](https://www.youtube.com/watch?v=lcD0nT8IVTg "Instagram Post")
By [@joaomdmoura](https://x.com/joaomdmoura)
- [CrewAI Framework](#crewai-framework)
- [Running the script](#running-the-script)
- [Details & Explanation](#details--explanation)
- [Using Local Models with Ollama](#using-local-models-with-ollama)
- [License](#license)
## CrewAI Framework
CrewAI is designed to facilitate the collaboration of role-playing AI agents. In this example, these agents work together to generate a creative and trendy instagram post.
## Running the Script
This example uses OpenHermes 2.5 through Ollama by default so you should to download [Ollama](ollama.ai) and [OpenHermes](https://ollama.ai/library/openhermes).
You can change the model by changing the `MODEL` env var in the `.env` file.
- **Configure Environment**: Copy ``.env.example` and set up the environment variables for [Browseless](https://www.browserless.io/), [Serper](https://serper.dev/).
- **Install Dependencies**: Run `poetry install --no-root` (uses crewAI==0.130.0).
- **Execute the Script**: Run `python main.py` and input your idea.
## Details & Explanation
- **Running the Script**: Execute `python main.py`` and input your idea when prompted. The script will leverage the CrewAI framework to process the idea and generate an instagram post.
- **Key Components**:
- `./main.py`: Main script file.
- `./tasks.py`: Main file with the tasks prompts.
- `./agents.py`: Main file with the agents creation.
- `./tools/`: Contains tool classes used by the agents.
## Using Local Models with Ollama
This example run entirely local models, the CrewAI framework supports integration with both closed and local models, by using tools such as Ollama, for enhanced flexibility and customization. This allows you to utilize your own models, which can be particularly useful for specialized tasks or data privacy concerns.
### Setting Up Ollama
- **Install Ollama**: Ensure that Ollama is properly installed in your environment. Follow the installation guide provided by Ollama for detailed instructions.
- **Configure Ollama**: Set up Ollama to work with your local model. You will probably need to [tweak the model using a Modelfile](https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md), I'd recommend playing with `top_p` and `temperature`.
## License
This project is released under the MIT License.

View File

@@ -0,0 +1,117 @@
import os
from textwrap import dedent
from crewai import Agent
from tools.browser_tools import BrowserTools
from tools.search_tools import SearchTools
from langchain.agents import load_tools
from langchain.llms import Ollama
class MarketingAnalysisAgents:
def __init__(self):
self.llm = Ollama(model=os.environ['MODEL'])
def product_competitor_agent(self):
return Agent(
role="Lead Market Analyst",
goal=dedent("""\
Conduct amazing analysis of the products and
competitors, providing in-depth insights to guide
marketing strategies."""),
backstory=dedent("""\
As the Lead Market Analyst at a premier
digital marketing firm, you specialize in dissecting
online business landscapes."""),
tools=[
BrowserTools.scrape_and_summarize_website,
SearchTools.search_internet
],
allow_delegation=False,
llm=self.llm,
verbose=True
)
def strategy_planner_agent(self):
return Agent(
role="Chief Marketing Strategist",
goal=dedent("""\
Synthesize amazing insights from product analysis
to formulate incredible marketing strategies."""),
backstory=dedent("""\
You are the Chief Marketing Strategist at
a leading digital marketing agency, known for crafting
bespoke strategies that drive success."""),
tools=[
BrowserTools.scrape_and_summarize_website,
SearchTools.search_internet,
SearchTools.search_instagram
],
llm=self.llm,
verbose=True
)
def creative_content_creator_agent(self):
return Agent(
role="Creative Content Creator",
goal=dedent("""\
Develop compelling and innovative content
for social media campaigns, with a focus on creating
high-impact Instagram ad copies."""),
backstory=dedent("""\
As a Creative Content Creator at a top-tier
digital marketing agency, you excel in crafting narratives
that resonate with audiences on social media.
Your expertise lies in turning marketing strategies
into engaging stories and visual content that capture
attention and inspire action."""),
tools=[
BrowserTools.scrape_and_summarize_website,
SearchTools.search_internet,
SearchTools.search_instagram
],
llm=self.llm,
verbose=True
)
def senior_photographer_agent(self):
return Agent(
role="Senior Photographer",
goal=dedent("""\
Take the most amazing photographs for instagram ads that
capture emotions and convey a compelling message."""),
backstory=dedent("""\
As a Senior Photographer at a leading digital marketing
agency, you are an expert at taking amazing photographs that
inspire and engage, you're now working on a new campaign for a super
important customer and you need to take the most amazing photograph."""),
tools=[
BrowserTools.scrape_and_summarize_website,
SearchTools.search_internet,
SearchTools.search_instagram
],
llm=self.llm,
allow_delegation=False,
verbose=True
)
def chief_creative_diretor_agent(self):
return Agent(
role="Chief Creative Director",
goal=dedent("""\
Oversee the work done by your team to make sure it's the best
possible and aligned with the product's goals, review, approve,
ask clarifying question or delegate follow up work if necessary to make
decisions"""),
backstory=dedent("""\
You're the Chief Content Officer of leading digital
marketing specialized in product branding. You're working on a new
customer, trying to make sure your team is crafting the best possible
content for the customer."""),
tools=[
BrowserTools.scrape_and_summarize_website,
SearchTools.search_internet,
SearchTools.search_instagram
],
llm=self.llm,
verbose=True
)

View File

@@ -0,0 +1,75 @@
from dotenv import load_dotenv
load_dotenv()
from textwrap import dedent
from crewai import Agent, Crew
from tasks import MarketingAnalysisTasks
from agents import MarketingAnalysisAgents
tasks = MarketingAnalysisTasks()
agents = MarketingAnalysisAgents()
print("## Welcome to the marketing Crew")
print('-------------------------------')
product_website = input("What is the product website you want a marketing strategy for?\n")
product_details = input("Any extra details about the product and or the instagram post you want?\n")
# Create Agents
product_competitor_agent = agents.product_competitor_agent()
strategy_planner_agent = agents.strategy_planner_agent()
creative_agent = agents.creative_content_creator_agent()
# Create Tasks
website_analysis = tasks.product_analysis(product_competitor_agent, product_website, product_details)
market_analysis = tasks.competitor_analysis(product_competitor_agent, product_website, product_details)
campaign_development = tasks.campaign_development(strategy_planner_agent, product_website, product_details)
write_copy = tasks.instagram_ad_copy(creative_agent)
# Create Crew responsible for Copy
copy_crew = Crew(
agents=[
product_competitor_agent,
strategy_planner_agent,
creative_agent
],
tasks=[
website_analysis,
market_analysis,
campaign_development,
write_copy
],
verbose=True
)
ad_copy = copy_crew.kickoff()
# Create Crew responsible for Image
senior_photographer = agents.senior_photographer_agent()
chief_creative_diretor = agents.chief_creative_diretor_agent()
# Create Tasks for Image
take_photo = tasks.take_photograph_task(senior_photographer, ad_copy, product_website, product_details)
approve_photo = tasks.review_photo(chief_creative_diretor, product_website, product_details)
image_crew = Crew(
agents=[
senior_photographer,
chief_creative_diretor
],
tasks=[
take_photo,
approve_photo
],
verbose=True
)
image = image_crew.kickoff()
# Print results
print("\n\n########################")
print("## Here is the result")
print("########################\n")
print("Your post copy:")
print(ad_copy)
print("'\n\nYour midjourney description:")
print(image)

View File

@@ -0,0 +1,24 @@
[project]
name = "instagram-post-example"
version = "0.1.0"
description = ""
requires-python = ">=3.10,<3.12"
dependencies = [
"crewai>=0.152.0",
"python-dotenv==1.0.0",
"opencv-python==4.8.1.78",
"google-search-results==2.4.2",
"unstructured>=0.18.11",
"langchain>=0.3.27",
"langchain-community>=0.3.27",
]
[tool.pyright]
# https://github.com/microsoft/pyright/blob/main/docs/configuration.md
useLibraryCodeForTypes = true
exclude = [".cache"]
[tool.ruff]
# https://beta.ruff.rs/docs/configuration/
select = ['E', 'W', 'F', 'I', 'B', 'C4', 'ARG', 'SIM']
ignore = ['W291', 'W292', 'W293']

View File

@@ -0,0 +1,121 @@
from crewai import Task
from textwrap import dedent
class MarketingAnalysisTasks:
def product_analysis(self, agent, product_website, product_details):
return Task(description=dedent(f"""\
Analyze the given product website: {product_website}.
Extra details provided by the customer: {product_details}.
Focus on identifying unique features, benefits,
and the overall narrative presented.
Your final report should clearly articulate the
product's key selling points, its market appeal,
and suggestions for enhancement or positioning.
Emphasize the aspects that make the product stand out.
Keep in mind, attention to detail is crucial for
a comprehensive analysis. It's currenlty 2024.
"""),
agent=agent
)
def competitor_analysis(self, agent, product_website, product_details):
return Task(description=dedent(f"""\
Explore competitor of: {product_website}.
Extra details provided by the customer: {product_details}.
Identify the top 3 competitors and analyze their
strategies, market positioning, and customer perception.
Your final report MUST include BOTH all context about {product_website}
and a detailed comparison to whatever competitor they have competitors.
"""),
agent=agent
)
def campaign_development(self, agent, product_website, product_details):
return Task(description=dedent(f"""\
You're creating a targeted marketing campaign for: {product_website}.
Extra details provided by the customer: {product_details}.
To start this campaing we will need a strategy and creative content ideas.
It should be meticulously designed to captivate and engage
the product's target audience.
Based on your ideas your co-workers will create the content for the campaign.
Your final answer MUST be ideas that will resonate with the audience and
also include ALL context you have about the product and the customer.
"""),
agent=agent
)
def instagram_ad_copy(self, agent):
return Task(description=dedent("""\
Craft an engaging Instagram post copy.
The copy should be punchy, captivating, concise,
and aligned with the product marketing strategy.
Focus on creating a message that resonates with
the target audience and highlights the product's
unique selling points.
Your ad copy must be attention-grabbing and should
encourage viewers to take action, whether it's
visiting the website, making a purchase, or learning
more about the product.
Your final answer MUST be 3 options for an ad copy for instagram that
not only informs but also excites and persuades the audience.
"""),
agent=agent
)
def take_photograph_task(self, agent, copy, product_website, product_details):
return Task(description=dedent(f"""\
You are working on a new campaign for a super important customer,
and you MUST take the most amazing photo ever for an instagram post
regarding the product, you have the following copy:
{copy}
This is the product you are working with: {product_website}.
Extra details provided by the customer: {product_details}.
Imagine what the photo you wanna take describe it in a paragraph.
Here are some examples for you follow:
- high tech airplaine in a beautiful blue sky in a beautiful sunset super cripsy beautiful 4k, professional wide shot
- the last supper, with Jesus and his disciples, breaking bread, close shot, soft lighting, 4k, crisp
- an bearded old man in the snows, using very warm clothing, with mountains full of snow behind him, soft lighting, 4k, crisp, close up to the camera
Think creatively and focus on how the image can capture the audience's
attention. Don't show the actual product on the photo.
Your final answer must be 3 options of photographs, each with 1 paragraph
describing the photograph exactly like the examples provided above.
"""),
agent=agent
)
def review_photo(self, agent, product_website, product_details):
return Task(description=dedent(f"""\
Review the photos you got from the senior photographer.
Make sure it's the best possible and aligned with the product's goals,
review, approve, ask clarifying question or delegate follow up work if
necessary to make decisions. When delegating work send the full draft
as part of the information.
This is the product you are working with: {product_website}.
Extra details provided by the customer: {product_details}.
Here are some examples on how the final photographs should look like:
- high tech airplaine in a beautiful blue sky in a beautiful sunset super cripsy beautiful 4k, professional wide shot
- the last supper, with Jesus and his disciples, breaking bread, close shot, soft lighting, 4k, crisp
- an bearded old man in the snows, using very warm clothing, with mountains full of snow behind him, soft lighting, 4k, crisp, close up to the camera
Your final answer must be 3 reviewed options of photographs,
each with 1 paragraph description following the examples provided above.
"""),
agent=agent
)

View File

View File

@@ -0,0 +1,42 @@
import json
import os
import requests
from crewai import Agent, Task
from langchain.tools import tool
from unstructured.partition.html import partition_html
from langchain.llms import Ollama
class BrowserTools():
@tool("Scrape website content")
def scrape_and_summarize_website(website):
"""Useful to scrape and summarize a website content, just pass a string with
only the full url, no need for a final slash `/`, eg: https://google.com or https://clearbit.com/about-us"""
url = f"https://chrome.browserless.io/content?token={os.environ['BROWSERLESS_API_KEY']}"
payload = json.dumps({"url": website})
headers = {'cache-control': 'no-cache', 'content-type': 'application/json'}
response = requests.request("POST", url, headers=headers, data=payload)
elements = partition_html(text=response.text)
content = "\n\n".join([str(el) for el in elements])
content = [content[i:i + 8000] for i in range(0, len(content), 8000)]
summaries = []
for chunk in content:
agent = Agent(
role='Principal Researcher',
goal=
'Do amazing researches and summaries based on the content you are working with',
backstory=
"You're a Principal Researcher at a big company and you need to do a research about a given topic.",
llm=Ollama(model=os.environ['MODEL']),
allow_delegation=False)
task = Task(
agent=agent,
description=
f'Analyze and make a LONG summary the content bellow, make sure to include the ALL relevant information in the summary, return only the summary nothing else.\n\nCONTENT\n----------\n{chunk}'
)
summary = task.execute()
summaries.append(summary)
content = "\n\n".join(summaries)
return f'\nScrapped Content: {content}\n'

View File

@@ -0,0 +1,44 @@
import json
import os
import requests
from langchain.tools import tool
class SearchTools():
@tool("Search internet")
def search_internet(query):
"""Useful to search the internet about a given topic and return relevant
results."""
return SearchTools.search(query)
@tool("Search instagram")
def search_instagram(query):
"""Useful to search for instagram post about a given topic and return relevant
results."""
query = f"site:instagram.com {query}"
return SearchTools.search(query)
def search(query, n_results=5):
url = "https://google.serper.dev/search"
payload = json.dumps({"q": query})
headers = {
'X-API-KEY': os.environ['SERPER_API_KEY'],
'content-type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
results = response.json()['organic']
stirng = []
for result in results[:n_results]:
try:
stirng.append('\n'.join([
f"Title: {result['title']}", f"Link: {result['link']}",
f"Snippet: {result['snippet']}", "\n-----------------"
]))
except KeyError:
next
content = '\n'.join(stirng)
return f"\nSearch result: {content}\n"

3320
crews/instagram_post/uv.lock generated Normal file

File diff suppressed because it is too large Load Diff