Sharan1712 commited on
Commit
a7fd095
·
verified ·
1 Parent(s): cc74849

Upload 2 files

Browse files
Files changed (2) hide show
  1. agents.py +80 -0
  2. app.py +148 -0
agents.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from crewai import Agent, Task, Crew
2
+ from crewai_tools import SerperDevTool, ScrapeWebsiteTool
3
+
4
+ def generate_content(llm, topic):
5
+
6
+ search_tool = SerperDevTool(n_results=10)
7
+ docs_scrape_tool = ScrapeWebsiteTool()
8
+
9
+ planner = Agent(
10
+ role = "Content Planner",
11
+ goal = "Plan engaging and factually accurate content on {topic}",
12
+ backstory = """You're working on planning a blog article about the topic: {topic}.
13
+ You collect information that helps the audience learn something and make informed decisions.
14
+ Your work is the basis for the Content Writer to write an article on this topic.""",
15
+ llm = llm,
16
+ allow_delegation = False,
17
+ verbose = True,
18
+ tools = [search_tool, docs_scrape_tool]
19
+ )
20
+
21
+ plan = Task(
22
+ description = """1. Prioritize the latest trends, key players, and noteworthy news on {topic}.
23
+ 2. Identify the target audience, considering their interests and pain points.
24
+ 3. Develop a detailed content outline including an introduction, key points, and a call to action.
25
+ 4. Include SEO keywords and relevant data or sources.""",
26
+ expected_output = """A comprehensive content plan document with an outline, audience analysis, SEO keywords, and resources.""",
27
+ agent = planner,
28
+ )
29
+
30
+ writer = Agent(
31
+ role = "Content Writer",
32
+ goal = """Write insightful and factually accurate opinion piece about the topic: {topic}""",
33
+ backstory = """You're working on a writing a new opinion piece about the topic: {topic}.
34
+ You base your writing on the work of the Content Planner, who provides an outline and relevant context about the topic.
35
+ You follow the main objectives and direction of the outline, as provide by the Content Planner.
36
+ You also provide objective and impartial insights and back them up with information provide by the Content Planner.
37
+ You acknowledge in your opinion piece when your statements are opinions as opposed to objective statements.""",
38
+ llm = llm,
39
+ allow_delegation = False,
40
+ verbose = True
41
+ )
42
+
43
+ write = Task(
44
+ description = """1. Use the content plan to craft a compelling blog post on {topic}.
45
+ 2. Incorporate SEO keywords naturally.
46
+ 3. Sections/Subtitles are properly named in an engaging manner.
47
+ 4. Ensure the post is structured with an engaging introduction, insightful body, and a summarizing conclusion.
48
+ 5. Proofread for grammatical errors and alignment with the brand's voice.""",
49
+ expected_output = "A well-written blog post in markdown format, ready for publication, each section should have 2 or 3 paragraphs.",
50
+ agent = writer,
51
+ )
52
+
53
+ editor = Agent(
54
+ role = "Editor",
55
+ goal = "Edit a given blog post to align with the writing style of the organization.",
56
+ backstory = """You are an editor who receives a blog post from the Content Writer.
57
+ Your goal is to review the blog post to ensure that it follows journalistic best practices,
58
+ provides balanced viewpoints when providing opinions or assertions, and also avoids major controversial topics
59
+ or opinions when possible.""",
60
+ llm = llm,
61
+ allow_delegation = False,
62
+ verbose = True
63
+ )
64
+
65
+ edit = Task(
66
+ description = "Proofread the given blog post for grammatical errors and alignment with the brand's voice.",
67
+ expected_output = "A well-written blog post in markdown format, ready for publication, each section should have 2 or 3 paragraphs.",
68
+ agent = editor
69
+ )
70
+
71
+ crew = Crew(
72
+ agents = [planner, writer, editor],
73
+ tasks = [plan, write, edit],
74
+ verbose = True
75
+ )
76
+
77
+ return crew.kickoff(inputs={"topic": topic})
78
+
79
+
80
+
app.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit as st
3
+ # from dotenv import load_dotenv
4
+ from crewai import LLM
5
+ from agents import generate_content
6
+
7
+ # Load env variables
8
+ # load_dotenv()
9
+
10
+ # Streamlit Page Config
11
+ st.set_page_config(
12
+ page_title = "AI Blog Writer",
13
+ page_icon = ":newspaper:",
14
+ layout = "wide",
15
+ initial_sidebar_state="expanded")
16
+
17
+ # Logo
18
+ st.logo(
19
+ "https://cdn.prod.website-files.com/66cf2bfc3ed15b02da0ca770/66d07240057721394308addd_Logo%20(1).svg",
20
+ link = "https://www.crewai.com/",
21
+ size = "large"
22
+ )
23
+
24
+ col1, col2, col3 = st.columns([1, 6, 1])
25
+ with col2:
26
+ # Title and description
27
+ st.title("✍️AI Blog Article Generator, powered by :red[CrewAI]")
28
+ st.markdown("Generate comprehensive blog posts about any topic using AI agents.")
29
+
30
+ # Sidebar
31
+ with st.sidebar:
32
+ st.markdown("### ⚙️ Model API Configuration")
33
+ st.write("")
34
+
35
+ model_options = [
36
+ "gpt-4o-mini",
37
+ "gpt-4o",
38
+ "o1",
39
+ "o1-mini",
40
+ "o1-preview"
41
+ "o3-mini"
42
+ ]
43
+
44
+ selected_model = st.selectbox("🤖 Select which LLM to use", model_options, key = "selected_model")
45
+
46
+ with st.expander("🔑 API Keys", expanded = True):
47
+
48
+ st.info("API keys are stored temporarily in memory and cleared when you close the browser.")
49
+
50
+ openai_api_key = st.text_input(
51
+ "OpenAI API Key",
52
+ type = "password",
53
+ placeholder = "Enter your OpenAI API key",
54
+ help = "Enter your OpenAI API key"
55
+ )
56
+
57
+ if openai_api_key:
58
+ os.environ["OPENAI_API_KEY"] = openai_api_key
59
+
60
+ serper_api_key = st.text_input(
61
+ "Serper API Key",
62
+ type = "password",
63
+ placeholder = "Enter your Serper API key",
64
+ help = "Enter your Serper API key for web search capabilities"
65
+ )
66
+ if serper_api_key:
67
+ os.environ["SERPER_API_KEY"] = serper_api_key
68
+
69
+ st.write("")
70
+ with st.expander("ℹ️ About", expanded=False):
71
+ st.markdown(
72
+ """This Blog Article Writing assistant uses advanced AI models to help you:
73
+ - Research any topic in depth
74
+ - Analyze and summarize information
75
+ - Provide structured article
76
+
77
+ Choose your preferred model and enter the required API keys to get started.""")
78
+
79
+ if not os.environ.get("OPENAI_API_KEY"):
80
+ st.warning("⚠️ Please enter your OpenAI API key in the sidebar to get started")
81
+ st.stop()
82
+
83
+ if not os.environ.get("SERPER_API_KEY"):
84
+ st.warning("⚠️ Please enter your Serper API key in the sidebar to get started")
85
+ st.stop()
86
+
87
+ # Create two columns for the input section
88
+ input_col1, input_col2, input_col3 = st.columns([1, 6, 1])
89
+
90
+ with input_col2:
91
+ # st.header("Content Settings")
92
+
93
+ # Make the text input take up more space
94
+ topic = st.text_area(
95
+ "Enter your topic",
96
+ height = 68,
97
+ placeholder = "Enter the topic you want to generate content about..."
98
+ )
99
+
100
+ col1, col2, col3 = st.columns([1, 0.5, 1])
101
+ with col2:
102
+ generate_button = st.button("🚀 Generate Article", use_container_width = False, type = "primary")
103
+
104
+ # # Add more sidebar controls if needed
105
+ # st.markdown("### Advanced Settings")
106
+ # temperature = st.slider("Temperature", 0.0, 1.0, 0.7)
107
+
108
+ # # Add some spacing
109
+ # st.markdown("---")
110
+
111
+ # # Make the generate button more prominent in the sidebar
112
+ # generate_button = st.button("Generate Article", type="primary", use_container_width=True)
113
+
114
+
115
+ if generate_button:
116
+ with st.spinner("Generating content... This may take a moment."):
117
+ try:
118
+ llm = LLM(model = f"openai/{selected_model}")
119
+ result = generate_content(llm, topic)
120
+
121
+ except Exception as e:
122
+ st.error(f"An error occurred: {str(e)}")
123
+
124
+ st.markdown("### Generated Article")
125
+ st.markdown(str(result))
126
+
127
+ # Add download button
128
+ st.download_button(
129
+ label = "Download Article",
130
+ data = result.raw,
131
+ file_name = f"{topic.lower().replace(' ', '_')}_article.md",
132
+ mime = "text/markdown"
133
+ )
134
+
135
+ # Add footer
136
+ st.divider()
137
+ footer_col1, footer_col2, footer_col3 = st.columns([1, 2, 1])
138
+ with footer_col2:
139
+ st.caption("Made with ❤️ using [CrewAI](https://crewai.com), [Serper](https://serper.dev/) and [Streamlit](https://streamlit.io)")
140
+ st.caption("By Sharan Shyamsundar")
141
+
142
+ # Footer
143
+ # footer_html = """<div style='text-align: center;'>
144
+ # <p>Developed with CrewAI, Streamlit and OpenAI by Sharan</p>
145
+ # </div>"""
146
+ # st.markdown(footer_html, unsafe_allow_html=True)
147
+
148
+ # st.markdown("Built with CrewAI, Streamlit and powered by OpenAI's GPT4o")