Spaces:
Sleeping
Sleeping
File size: 8,964 Bytes
2fe9eb8 baf9e10 2fe9eb8 baf9e10 2fe9eb8 aa67901 2fe9eb8 baf9e10 2fe9eb8 4dcb44f 2fe9eb8 aa67901 2fe9eb8 aa67901 2fe9eb8 aa67901 2fe9eb8 baf9e10 2fe9eb8 baf9e10 2fe9eb8 aa67901 2fe9eb8 baf9e10 2fe9eb8 aa67901 56f4bfd aa67901 5ddd7f1 6aedb51 5ddd7f1 6aedb51 5ddd7f1 2fe9eb8 f1e22c1 e30c01e f1e22c1 2fe9eb8 79132ac 2fe9eb8 e30c01e 2fe9eb8 baf9e10 56f4bfd 2fe9eb8 6aedb51 2fe9eb8 baf9e10 56f4bfd 2fe9eb8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# import relevant libraries and modules
import warnings
from crewai import LLM, Task, Agent, Crew
import os
from dotenv import load_dotenv
from pathlib import Path
import gradio as gr
from tools.hybrid_retriever_tool import HybridRetrieverTool
# control warnings
warnings.filterwarnings("ignore")
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
#Define LLMs
llm_planner = LLM(model="gpt-4o-mini", temperature=0.5)
llm_writer = LLM(model="gpt-5-mini", temperature=1.0)
llm_editor = LLM(model="gpt-4-turbo", temperature=0.3)
llm_fact=LLM(model="gpt-4o-mini", temperature=0.3)
#Define tools
hybrid_tool = HybridRetrieverTool(alpha=0.6) #including RAG in search
#Creating Agents
planner = Agent(
role="Research Lead",
goal="Plan engaging and factually accurate content on {topic}",
backstory="You are working on planning a blog article about the topic {topic}."
"Use the retriever tool to gather accurate, recent information before outlining." #RAG search
"You collect relevant 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.",
allow_delegation=False,
verbose=True,
tools = [hybrid_tool], #Rag search
llm=llm_planner
)
writer = Agent(
role="Technical Writer",
goal="Write an insightful and factually accurate opinion piece about the topic: {topic}",
backstory="You are working on writing a new opnion piece about the topic: {topic}. "
"You base your writing on the work of the research lead, 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, supported by relevant information that is provided by the Content Planner. "
"You acknowledge in your opnion piece when your statements are opinions as opposed to objective staements.",
allow_delegation=False,
verbose=True,
llm=llm_writer
)
fact_checker = Agent(
role="Data Verifier",
goal="Verify factual accuracy, detect unsupported claims and identify missing references or sources.",
backstory="You are a meticulous research analyst who checks every claim against known facts and relaible sources"
"Use the retriever tool to cross-check the Content Writer's statements against reliable, recent information.",
allow_delegation=False,
verbose=True,
tools = [hybrid_tool], #Rag search
llm=llm_fact
)
editor = Agent(
role="Editor-in-Chief",
goal="Edit a given blog post to align with the context and narrative style of the {topic} (e.g. academic, informal, satirical).",
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. "
"The blog post should align with the context and narrative style of the topic being discussed.",
allow_delegation=False,
verbose=True,
llm=llm_editor
)
#Creating Tasks
plan = Task(
name="content_planner_task",
description=(
"1. Prioritize the latest trends, key players, and groundbreaking news on {topic}.\n"
"2. Identify the target audience, considering their interests and pain points.\n"
"3. Develop a detailed content outline including and 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(
name="blog_writer_task",
description=(
"1. Use the provided content plan to craft a compelling blog post on {topic}.\n"
"2. Incorporate SEO keywords naturally.\n"
"3. Sections/Subtitles are properly named in an engaging manner.\n"
"4. Ensure the post structured with an engaging introduction, insightful body, and a summarizing conclusion.\n"
"5. The narrative style and language used should be determined by the target audience and {tone}.\n"
"6. Proofread for grammatical errors and alignment with the target audience.\n"
),
expected_output="A well-written blog post in markdown format, ready for publication. "
"Each section should have 2 or 3 paragraphs and the whole blog should be a maximum of 1000 words.",
agent=writer,
context=[plan]
)
fact_check = Task(
name="fact_checker_task",
description=(
"Carefully review the drafted blog post provided by the Content Writer. "
"Check all factual statements for accuracy and ensure sources or references are mentioned. "
"Identify any unsupported claims, logical inconsistencies, or outdated information. "
"Provide corrections or highlight areas that require further verification."
),
expected_output=(
"A revised version of the blog post in markdown format, with annotations or corrections "
"for any inaccurate or unsupported statements."
),
agent=fact_checker,
context=[write]
)
edit = Task(
name="editor_task",
description=("Edit and refine the fact-checked blog post to ensure clarity, flow and consistent {tone}.\n"
"Polish grammar, readability, and overall style."
),
expected_output="A well-written blog post in markdown format, ready for publication. "
"Each section should have 2 or 3 paragraphs and the whole blog should be a maximum of 1000 words",
agent=editor,
context=[fact_check]
)
# Creating the Crew
crew = Crew(
agents=[planner, writer, fact_checker, editor],
tasks=[plan, write, fact_check, edit],
process="sequential",
verbose=True
)
# fetch context for RAG search
def fetch_context(topic):
passages = hybrid_tool._run(topic)
if isinstance(passages, str):
summary = passages
else:
summary = hybrid_tool.summarize_passages(topic, passages)
return summary
# Define Gradio Handler
def generate_blog(topic, tone, progress=gr.Progress(track_tqdm=True)):
progress(0, desc="Starting collaborative report generation...")
yield "### π§ Starting Collaborative Report\n"
# Run the entire multi-agent workflow once (non-streaming)
result = crew.kickoff(inputs={"topic": topic, "tone": tone})
# Try to extract clean text output
if hasattr(result, "output"):
final_output = result.output
elif hasattr(result, "final_output"):
final_output = result.final_output
else:
final_output = str(result)
progress(1.0, desc="Completed.")
yield f"β
**Collaborative Report Generated Successfully!**\n\n{final_output}"
# Build Gradio Interface
css = """
#output-box {
background-color: #f8f9fa;
border-radius: 12px;
padding: 1.5rem;
font-family: 'Inter', sans-serif;
font-size: 1rem;
line-height: 1.6;
white-space: pre-wrap;
overflow-y: auto;
max-height: 70vh;
}
#context-box h1, #context-box h2, #context-box h3 {
font-size: 1rem !important;
font-weight: 600 !important;
}
#context-box {
font-family: 'Inter', sans-serif;
font-size: 1rem;
line-height: 1.6;
background-color: #ffffff;
border: 1px solid #ddd;
border-radius: 10px;
padding: 1rem;
margin-top: 0.5rem;
max-height: 70vh;
overflow-y: auto;
}
"""
with gr.Blocks(css=css) as demo:
gr.Markdown(
"""
## βοΈ AI Blog Writer Multi-Agent (Multi-Agent Crew: Sequential research β writing β verification β editing)
Create a professional, fact-checked, and polished article using CrewAI agents.
"""
)
with gr.Row():
topic = gr.Textbox(
label="Blog Topic",
placeholder="e.g. Sustainable Investing, Vegan cuisine, AI in Healthcare",
value="Sustainable Investing"
)
tone=gr.Dropdown(
["professional", "playful", "academic", "casual", "satirical", "humorous"],
label="Select Writing Tone",
value="academic"
)
fetch_btn = gr.Button("π Fetch & Summarize Context", variant="secondary") # Rag Search
context_output = gr.Markdown(label="π Retrieved Context Summary") # Rag Search
run_button = gr.Button("π Generate Blog", variant="primary")
final_output = gr.Textbox(label="π° Generated Blog Post", elem_id="output-box", lines=30, interactive=False, show_label=True)
fetch_btn.click(fetch_context, inputs=[topic], outputs=[context_output]) # Rag Search
run_button.click(generate_blog, inputs=[topic, tone], outputs=[final_output])
#Launch app
if __name__=="__main__":
demo.launch(server_name="0.0.0.0", server_port=7860, share=True)
|