crew / app.py
stevafernandes's picture
Upload 2 files
d229af7 verified
Raw History Blame Contribute Delete
5.17 kB
"""Create agents to research and write an article.
Planner -> Writer -> Editor, executed sequentially.
Needs only GEMINI_API_KEY (in .env locally, or as a Space secret on Hugging Face).
Run: python app.py
"""
import os
import gradio as gr
from dotenv import load_dotenv
from crewai import Agent, Task, Crew, LLM
load_dotenv()
if not (os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")):
raise SystemExit("Missing GEMINI_API_KEY. Add it to .env locally, "
"or as a secret in your Hugging Face Space settings.")
# CrewAI picks the provider from the prefix before the slash.
# The key is read automatically from GEMINI_API_KEY (or GOOGLE_API_KEY).
gemini_llm = LLM(model=os.getenv("GEMINI_MODEL", "gemini/gemini-3.8-flash"))
# Default topic shown in the text box.
TOPIC = "Artificial Intelligence"
planner = Agent(
role="Content Planner",
goal="Plan engaging and factually accurate content on {topic}",
backstory="You're working on planning a blog article "
"about the topic: {topic}. "
"You collect information that helps the "
"audience learn something "
"and make informed decisions. "
"Your work is the basis for "
"the Content Writer to write an article on this topic.",
llm=gemini_llm,
allow_delegation=False,
verbose=True,
)
writer = Agent(
role="Content Writer",
goal="Write insightful and factually accurate "
"opinion piece about the topic: {topic}",
backstory="You're working on writing "
"a new opinion piece about the topic: {topic}. "
"You base your writing on the work of "
"the Content Planner, who provides an outline "
"and relevant context about the topic. "
"You follow the main objectives and "
"direction of the outline, "
"as provided by the Content Planner. "
"You also provide objective and impartial insights "
"and back them up with information "
"provided by the Content Planner. "
"You acknowledge in your opinion piece "
"when your statements are opinions "
"as opposed to objective statements.",
llm=gemini_llm,
allow_delegation=False,
verbose=True,
)
editor = Agent(
role="Editor",
goal="Edit a given blog post to align with "
"the writing style of the organization.",
backstory="You are an editor who receives a blog post "
"from the Content Writer. "
"Your goal is to review the blog post "
"to ensure that it follows journalistic best practices, "
"provides balanced viewpoints "
"when providing opinions or assertions, "
"and also avoids major controversial topics "
"or opinions when possible.",
llm=gemini_llm,
allow_delegation=False,
verbose=True,
)
plan = Task(
description=(
"1. Prioritize the latest trends, key players, "
"and noteworthy news on {topic}.\n"
"2. Identify the target audience, considering "
"their interests and pain points.\n"
"3. Develop a detailed content outline including "
"an introduction, key points, and a call to action.\n"
"4. Include SEO keywords and relevant data or sources."
),
expected_output="A comprehensive content plan document "
"with an outline, audience analysis, "
"SEO keywords, and resources.",
agent=planner,
)
write = Task(
description=(
"1. Use the content plan to craft a compelling "
"blog post on {topic}.\n"
"2. Incorporate SEO keywords naturally.\n"
"3. Sections and subtitles are properly named "
"in an engaging manner.\n"
"4. Ensure the post is structured with an "
"engaging introduction, insightful body, "
"and a summarizing conclusion.\n"
"5. Proofread for grammatical errors and "
"alignment with the brand's voice."
),
expected_output="A well-written blog post "
"in markdown format, ready for publication, "
"each section should have 2 or 3 paragraphs.",
agent=writer,
)
edit = Task(
description="Proofread the given blog post for "
"grammatical errors and "
"alignment with the brand's voice.",
expected_output="A well-written blog post in markdown format, "
"ready for publication, "
"each section should have 2 or 3 paragraphs.",
agent=editor,
)
crew = Crew(
agents=[planner, writer, editor],
tasks=[plan, write, edit],
verbose=True,
)
# --- Hugging Face Space UI (the only real addition) ---
def write_article(topic):
return crew.kickoff(inputs={"topic": topic}).raw
demo = gr.Interface(
fn=write_article,
inputs=gr.Textbox(label="Topic", value=TOPIC),
outputs=gr.Markdown(),
title="Research & Write an Article",
submit_btn="Write article",
)
if __name__ == "__main__":
demo.launch()