"""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()