Update app.py
Browse files
app.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
from crewai import Agent, Task, Crew
|
2 |
import gradio as gr
|
3 |
import asyncio
|
4 |
-
from typing import List,
|
5 |
from langchain_openai import ChatOpenAI
|
6 |
import queue
|
7 |
import threading
|
@@ -10,22 +10,17 @@ import os
|
|
10 |
class AgentMessageQueue:
|
11 |
def __init__(self):
|
12 |
self.message_queue = queue.Queue()
|
13 |
-
self.
|
14 |
-
|
15 |
def add_message(self, message: Dict):
|
|
|
16 |
self.message_queue.put(message)
|
17 |
-
|
18 |
def get_messages(self) -> List[Dict]:
|
19 |
messages = []
|
20 |
while not self.message_queue.empty():
|
21 |
messages.append(self.message_queue.get())
|
22 |
return messages
|
23 |
-
|
24 |
-
def set_final_output(self, output: str):
|
25 |
-
self.final_output = output
|
26 |
-
|
27 |
-
def get_final_output(self) -> str:
|
28 |
-
return self.final_output
|
29 |
|
30 |
class ArticleCrew:
|
31 |
def __init__(self, api_key: str = None):
|
@@ -34,264 +29,283 @@ class ArticleCrew:
|
|
34 |
self.planner = None
|
35 |
self.writer = None
|
36 |
self.editor = None
|
37 |
-
|
|
|
|
|
38 |
def initialize_agents(self, topic: str):
|
39 |
if not self.api_key:
|
40 |
raise ValueError("OpenAI API key is required")
|
41 |
-
|
42 |
os.environ["OPENAI_API_KEY"] = self.api_key
|
43 |
-
|
44 |
-
|
45 |
-
temperature=0.7,
|
46 |
-
model="gpt-4"
|
47 |
-
)
|
48 |
-
|
49 |
self.planner = Agent(
|
50 |
role="Content Planner",
|
51 |
goal=f"Plan engaging and factually accurate content on {topic}",
|
52 |
-
backstory=
|
53 |
-
"You collect information that helps the audience learn something "
|
54 |
-
"and make informed decisions.",
|
55 |
allow_delegation=False,
|
56 |
verbose=True,
|
57 |
llm=llm
|
58 |
)
|
59 |
-
|
60 |
self.writer = Agent(
|
61 |
role="Content Writer",
|
62 |
-
goal=f"Write insightful and factually accurate
|
63 |
-
backstory=
|
64 |
-
"You base your writing on the work of the Content Planner.",
|
65 |
allow_delegation=False,
|
66 |
verbose=True,
|
67 |
llm=llm
|
68 |
)
|
69 |
-
|
70 |
self.editor = Agent(
|
71 |
role="Editor",
|
72 |
-
goal="
|
73 |
-
backstory="
|
74 |
allow_delegation=False,
|
75 |
verbose=True,
|
76 |
llm=llm
|
77 |
)
|
78 |
|
79 |
-
def create_tasks(self, topic: str):
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
f"3. Develop a detailed content outline including introduction, key points, and call to action.\n"
|
88 |
-
f"4. Include SEO keywords and relevant data or sources."
|
89 |
-
),
|
90 |
-
expected_output="A comprehensive content plan document with an outline, audience analysis, SEO keywords, and resources.",
|
91 |
agent=self.planner
|
92 |
)
|
93 |
|
94 |
-
|
95 |
-
description=
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
expected_output="A well-written blog post in markdown format, ready for publication.",
|
103 |
agent=self.writer
|
104 |
)
|
105 |
|
106 |
-
|
107 |
-
description="
|
108 |
-
|
|
|
|
|
|
|
|
|
109 |
agent=self.editor
|
110 |
)
|
111 |
|
112 |
-
return [
|
113 |
|
114 |
async def process_article(self, topic: str) -> Generator[List[Dict], None, None]:
|
115 |
-
def
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
"role": "assistant",
|
130 |
-
"content": content,
|
131 |
-
"metadata": {"title": f"π {agent_name}'s Task"}
|
132 |
-
})
|
133 |
-
elif "## Final Answer:" in output_str:
|
134 |
-
content = output_str.split("## Final Answer:")[1].strip()
|
135 |
-
if agent_name == "Editor":
|
136 |
-
# For Editor's final answer, store it for later
|
137 |
-
self.message_queue.set_final_output(content)
|
138 |
-
self.message_queue.add_message({
|
139 |
-
"role": "assistant",
|
140 |
-
"content": content,
|
141 |
-
"metadata": {"title": f"β
{agent_name}'s Output"}
|
142 |
-
})
|
143 |
-
else:
|
144 |
-
self.message_queue.add_message({
|
145 |
-
"role": "assistant",
|
146 |
-
"content": output_str,
|
147 |
-
"metadata": {"title": f"π {agent_name} thinking"}
|
148 |
-
})
|
149 |
-
|
150 |
-
except Exception as e:
|
151 |
-
print(f"Error in step_callback: {str(e)}")
|
152 |
|
153 |
-
def
|
154 |
-
|
155 |
-
content
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
self.message_queue.add_message({
|
162 |
"role": "assistant",
|
163 |
-
"content":
|
164 |
-
"metadata": {"title":
|
165 |
})
|
166 |
|
167 |
-
#
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
"role": "assistant",
|
178 |
-
"content": final_content
|
179 |
-
})
|
180 |
-
self.message_queue.add_message({
|
181 |
-
"role": "assistant",
|
182 |
-
"content": "Article generation completed!",
|
183 |
-
"metadata": {"title": "β¨ Complete"}
|
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 |
-
# Stream messages while crew is working
|
220 |
-
while thread.is_alive() or not self.message_queue.message_queue.empty():
|
221 |
-
messages = self.message_queue.get_messages()
|
222 |
-
if messages:
|
223 |
-
yield messages
|
224 |
-
await asyncio.sleep(0.1)
|
225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
def create_demo():
|
227 |
article_crew = None
|
228 |
-
|
229 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
230 |
gr.Markdown("# π AI Article Writing Crew")
|
231 |
-
gr.Markdown("Watch as this AI Crew collaborates to create your article! This application utilizes [CrewAI](https://www.crewai.com/) agents: Content Planner, Content Writer, and Content Editor, to write an article on any topic you choose. To get started, enter your OpenAI API Key below and press Enter!")
|
232 |
|
233 |
openai_api_key = gr.Textbox(
|
234 |
-
label='OpenAI API Key',
|
235 |
-
type='password',
|
236 |
-
placeholder='
|
237 |
interactive=True
|
238 |
)
|
239 |
|
240 |
chatbot = gr.Chatbot(
|
241 |
label="Writing Process",
|
242 |
-
avatar_images=(None, "https://avatars.githubusercontent.com/u/170677839?v=4"),
|
243 |
height=700,
|
244 |
type="messages",
|
245 |
show_label=True,
|
246 |
visible=False,
|
247 |
-
|
|
|
248 |
)
|
249 |
-
|
250 |
with gr.Row(equal_height=True):
|
251 |
topic = gr.Textbox(
|
252 |
label="Article Topic",
|
253 |
-
placeholder="Enter
|
254 |
scale=4,
|
255 |
visible=False
|
256 |
)
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
"content": "Please provide an OpenAI API key first.",
|
264 |
-
"metadata": {"title": "β Error"}
|
265 |
-
})
|
266 |
-
yield history # Changed from return to yield
|
267 |
-
return # Early return without value
|
268 |
-
|
269 |
-
# Initialize or update ArticleCrew with API key
|
270 |
-
if article_crew is None:
|
271 |
-
article_crew = ArticleCrew(api_key=api_key)
|
272 |
-
else:
|
273 |
-
article_crew.api_key = api_key
|
274 |
-
|
275 |
-
# Add user message
|
276 |
history.append({
|
277 |
-
"role": "
|
278 |
-
"content":
|
|
|
279 |
})
|
280 |
yield history
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
|
|
292 |
yield history
|
293 |
-
|
294 |
-
|
|
|
|
|
|
|
|
|
|
|
295 |
|
296 |
def show_interface():
|
297 |
return {
|
@@ -301,17 +315,8 @@ def create_demo():
|
|
301 |
btn: gr.Button(visible=True)
|
302 |
}
|
303 |
|
304 |
-
openai_api_key.submit(
|
305 |
-
|
306 |
-
None,
|
307 |
-
[openai_api_key, chatbot, topic, btn]
|
308 |
-
)
|
309 |
-
|
310 |
-
btn.click(
|
311 |
-
process_input,
|
312 |
-
inputs=[topic, chatbot, openai_api_key], # Added openai_api_key back as input
|
313 |
-
outputs=[chatbot]
|
314 |
-
)
|
315 |
|
316 |
return demo
|
317 |
|
|
|
1 |
from crewai import Agent, Task, Crew
|
2 |
import gradio as gr
|
3 |
import asyncio
|
4 |
+
from typing import List, Dict, Any, Generator
|
5 |
from langchain_openai import ChatOpenAI
|
6 |
import queue
|
7 |
import threading
|
|
|
10 |
class AgentMessageQueue:
|
11 |
def __init__(self):
|
12 |
self.message_queue = queue.Queue()
|
13 |
+
self.last_agent = None
|
14 |
+
|
15 |
def add_message(self, message: Dict):
|
16 |
+
print(f"Adding message to queue: {message}") # Debug print
|
17 |
self.message_queue.put(message)
|
18 |
+
|
19 |
def get_messages(self) -> List[Dict]:
|
20 |
messages = []
|
21 |
while not self.message_queue.empty():
|
22 |
messages.append(self.message_queue.get())
|
23 |
return messages
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
25 |
class ArticleCrew:
|
26 |
def __init__(self, api_key: str = None):
|
|
|
29 |
self.planner = None
|
30 |
self.writer = None
|
31 |
self.editor = None
|
32 |
+
self.current_agent = None
|
33 |
+
self.final_article = None
|
34 |
+
|
35 |
def initialize_agents(self, topic: str):
|
36 |
if not self.api_key:
|
37 |
raise ValueError("OpenAI API key is required")
|
38 |
+
|
39 |
os.environ["OPENAI_API_KEY"] = self.api_key
|
40 |
+
llm = ChatOpenAI(temperature=0.7, model="gpt-4")
|
41 |
+
|
|
|
|
|
|
|
|
|
42 |
self.planner = Agent(
|
43 |
role="Content Planner",
|
44 |
goal=f"Plan engaging and factually accurate content on {topic}",
|
45 |
+
backstory="Expert content planner with focus on creating engaging outlines",
|
|
|
|
|
46 |
allow_delegation=False,
|
47 |
verbose=True,
|
48 |
llm=llm
|
49 |
)
|
50 |
+
|
51 |
self.writer = Agent(
|
52 |
role="Content Writer",
|
53 |
+
goal=f"Write insightful and factually accurate piece about {topic}",
|
54 |
+
backstory="Expert content writer with focus on engaging articles",
|
|
|
55 |
allow_delegation=False,
|
56 |
verbose=True,
|
57 |
llm=llm
|
58 |
)
|
59 |
+
|
60 |
self.editor = Agent(
|
61 |
role="Editor",
|
62 |
+
goal="Polish and refine the article",
|
63 |
+
backstory="Expert editor with eye for detail and clarity",
|
64 |
allow_delegation=False,
|
65 |
verbose=True,
|
66 |
llm=llm
|
67 |
)
|
68 |
|
69 |
+
def create_tasks(self, topic: str) -> List[Task]:
|
70 |
+
planner_task = Task(
|
71 |
+
description=f"""Create a detailed content plan for an article about {topic} by:
|
72 |
+
1. Prioritizing the latest trends, key players, and noteworthy news
|
73 |
+
2. Identifying the target audience, considering their interests and pain points
|
74 |
+
3. Developing a detailed content outline including introduction, key points, and call to action
|
75 |
+
4. Including SEO keywords and relevant data or sources""",
|
76 |
+
expected_output="A comprehensive content plan with outline, keywords, and target audience analysis",
|
|
|
|
|
|
|
|
|
77 |
agent=self.planner
|
78 |
)
|
79 |
|
80 |
+
writer_task = Task(
|
81 |
+
description="""Based on the provided content plan:
|
82 |
+
1. Use the content plan to craft a compelling blog post
|
83 |
+
2. Incorporate SEO keywords naturally
|
84 |
+
3. Ensure sections/subtitles are properly named in an engaging manner
|
85 |
+
4. Create proper structure with introduction, body, and conclusion
|
86 |
+
5. Proofread for grammatical errors""",
|
87 |
+
expected_output="A well-written article draft following the content plan",
|
|
|
88 |
agent=self.writer
|
89 |
)
|
90 |
|
91 |
+
editor_task = Task(
|
92 |
+
description="""Review the written article by:
|
93 |
+
1. Checking for clarity and coherence
|
94 |
+
2. Correcting any grammatical errors and typos
|
95 |
+
3. Ensuring consistent tone and style
|
96 |
+
4. Verifying proper formatting and structure""",
|
97 |
+
expected_output="A polished, final version of the article ready for publication",
|
98 |
agent=self.editor
|
99 |
)
|
100 |
|
101 |
+
return [planner_task, writer_task, editor_task]
|
102 |
|
103 |
async def process_article(self, topic: str) -> Generator[List[Dict], None, None]:
|
104 |
+
def add_agent_messages(agent_name: str, tasks: str, emoji: str = "π€"):
|
105 |
+
# Add agent header
|
106 |
+
self.message_queue.add_message({
|
107 |
+
"role": "assistant",
|
108 |
+
"content": agent_name,
|
109 |
+
"metadata": {"title": f"{emoji} {agent_name}"}
|
110 |
+
})
|
111 |
+
|
112 |
+
# Add task description
|
113 |
+
self.message_queue.add_message({
|
114 |
+
"role": "assistant",
|
115 |
+
"content": tasks,
|
116 |
+
"metadata": {"title": f"π Task for {agent_name}"}
|
117 |
+
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
|
119 |
+
def setup_next_agent(current_agent: str) -> None:
|
120 |
+
agent_sequence = {
|
121 |
+
"Content Planner": ("Content Writer", """1. Use the content plan to craft a compelling blog post
|
122 |
+
2. Incorporate SEO keywords naturally
|
123 |
+
3. Ensure sections/subtitles are properly named in an engaging manner
|
124 |
+
4. Create proper structure with introduction, body, and conclusion
|
125 |
+
5. Proofread for grammatical errors"""),
|
126 |
|
127 |
+
"Content Writer": ("Editor", """1. Review the article for clarity and coherence
|
128 |
+
2. Check for grammatical errors and typos
|
129 |
+
3. Ensure consistent tone and style
|
130 |
+
4. Verify proper formatting and structure""")
|
131 |
+
}
|
132 |
+
|
133 |
+
if current_agent in agent_sequence:
|
134 |
+
next_agent, tasks = agent_sequence[current_agent]
|
135 |
+
self.current_agent = next_agent
|
136 |
+
add_agent_messages(next_agent, tasks)
|
137 |
+
|
138 |
+
|
139 |
+
def task_callback(task_output) -> None:
|
140 |
+
print(f"Task callback received: {task_output}") # Debug print
|
141 |
+
|
142 |
+
# Extract content from raw output
|
143 |
+
raw_output = task_output.raw
|
144 |
+
if "## Final Answer:" in raw_output:
|
145 |
+
content = raw_output.split("## Final Answer:")[1].strip()
|
146 |
+
else:
|
147 |
+
content = raw_output.strip()
|
148 |
+
|
149 |
+
# Handle the output based on current agent
|
150 |
+
if self.current_agent == "Editor":
|
151 |
+
# Not going to show editor's output with metadata
|
152 |
+
# Instead, I am showing assistant message as the final article
|
153 |
self.message_queue.add_message({
|
154 |
"role": "assistant",
|
155 |
+
"content": "Final article is ready!",
|
156 |
+
"metadata": {"title": "π Final Article"}
|
157 |
})
|
158 |
|
159 |
+
# Convert common markdown patterns to Gradio-compatible markdown
|
160 |
+
formatted_content = content
|
161 |
+
# Ensure proper spacing for headers
|
162 |
+
formatted_content = formatted_content.replace("\n#", "\n\n#")
|
163 |
+
# Ensure proper spacing for lists
|
164 |
+
formatted_content = formatted_content.replace("\n-", "\n\n-")
|
165 |
+
formatted_content = formatted_content.replace("\n*", "\n\n*")
|
166 |
+
formatted_content = formatted_content.replace("\n1.", "\n\n1.")
|
167 |
+
# Ensure proper spacing for paragraphs
|
168 |
+
formatted_content = formatted_content.replace("\n\n\n", "\n\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
|
170 |
+
# Add the final article content without metadata
|
171 |
+
self.message_queue.add_message({
|
172 |
+
"role": "assistant",
|
173 |
+
"content": formatted_content
|
174 |
+
})
|
175 |
+
else:
|
176 |
+
# For other agents, show their output with metadata
|
177 |
+
self.message_queue.add_message({
|
178 |
+
"role": "assistant",
|
179 |
+
"content": content,
|
180 |
+
"metadata": {"title": f"β¨ Output from {self.current_agent}"}
|
181 |
+
})
|
182 |
+
# Setup next agent
|
183 |
+
setup_next_agent(self.current_agent)
|
184 |
|
185 |
+
def step_callback(output: Any) -> None:
|
186 |
+
print(f"Step callback received: {output}") # Debug print
|
187 |
+
# We'll only use step_callback for logging purposes now
|
188 |
+
pass
|
189 |
+
|
190 |
+
try:
|
191 |
+
self.initialize_agents(topic)
|
192 |
+
self.current_agent = "Content Planner"
|
193 |
+
|
194 |
+
# Start process
|
195 |
+
yield [{
|
196 |
+
"role": "assistant",
|
197 |
+
"content": "Starting work on your article...",
|
198 |
+
"metadata": {"title": "π Process Started"}
|
199 |
+
}]
|
200 |
+
|
201 |
+
# Initialize first agent
|
202 |
+
add_agent_messages("Content Planner",
|
203 |
+
"""1. Prioritize the latest trends, key players, and noteworthy news
|
204 |
+
2. Identify the target audience, considering their interests and pain points
|
205 |
+
3. Develop a detailed content outline including introduction, key points, and call to action
|
206 |
+
4. Include SEO keywords and relevant data or sources""")
|
207 |
+
|
208 |
+
crew = Crew(
|
209 |
+
agents=[self.planner, self.writer, self.editor],
|
210 |
+
tasks=self.create_tasks(topic),
|
211 |
+
verbose=True,
|
212 |
+
step_callback=step_callback,
|
213 |
+
task_callback=task_callback
|
214 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
|
216 |
+
def run_crew():
|
217 |
+
try:
|
218 |
+
crew.kickoff()
|
219 |
+
except Exception as e:
|
220 |
+
print(f"Error in crew execution: {str(e)}") # Debug print
|
221 |
+
self.message_queue.add_message({
|
222 |
+
"role": "assistant",
|
223 |
+
"content": f"An error occurred: {str(e)}",
|
224 |
+
"metadata": {"title": "β Error"}
|
225 |
+
})
|
226 |
+
|
227 |
+
thread = threading.Thread(target=run_crew)
|
228 |
+
thread.start()
|
229 |
+
|
230 |
+
while thread.is_alive() or not self.message_queue.message_queue.empty():
|
231 |
+
messages = self.message_queue.get_messages()
|
232 |
+
if messages:
|
233 |
+
print(f"Yielding messages: {messages}") # Debug print
|
234 |
+
yield messages
|
235 |
+
await asyncio.sleep(0.1)
|
236 |
+
|
237 |
+
except Exception as e:
|
238 |
+
print(f"Error in process_article: {str(e)}") # Debug print
|
239 |
+
yield [{
|
240 |
+
"role": "assistant",
|
241 |
+
"content": f"An error occurred: {str(e)}",
|
242 |
+
"metadata": {"title": "β Error"}
|
243 |
+
}]
|
244 |
+
|
245 |
+
|
246 |
+
# Gradio code
|
247 |
def create_demo():
|
248 |
article_crew = None
|
249 |
+
|
250 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
251 |
gr.Markdown("# π AI Article Writing Crew")
|
|
|
252 |
|
253 |
openai_api_key = gr.Textbox(
|
254 |
+
label='OpenAI API Key',
|
255 |
+
type='password',
|
256 |
+
placeholder='Enter your OpenAI API key...',
|
257 |
interactive=True
|
258 |
)
|
259 |
|
260 |
chatbot = gr.Chatbot(
|
261 |
label="Writing Process",
|
|
|
262 |
height=700,
|
263 |
type="messages",
|
264 |
show_label=True,
|
265 |
visible=False,
|
266 |
+
bubble_full_width=False, # Allow messages to wrap naturally
|
267 |
+
render_markdown=True # Enable markdown rendering
|
268 |
)
|
269 |
+
|
270 |
with gr.Row(equal_height=True):
|
271 |
topic = gr.Textbox(
|
272 |
label="Article Topic",
|
273 |
+
placeholder="Enter topic...",
|
274 |
scale=4,
|
275 |
visible=False
|
276 |
)
|
277 |
+
btn = gr.Button("Write Article", variant="primary", scale=1, visible=False)
|
278 |
+
|
279 |
+
async def process_input(topic, history, api_key):
|
280 |
+
nonlocal article_crew
|
281 |
+
if not api_key:
|
282 |
+
history = history or []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
283 |
history.append({
|
284 |
+
"role": "assistant",
|
285 |
+
"content": "Please provide an OpenAI API key.",
|
286 |
+
"metadata": {"title": "β Error"}
|
287 |
})
|
288 |
yield history
|
289 |
+
return
|
290 |
+
|
291 |
+
if article_crew is None:
|
292 |
+
article_crew = ArticleCrew(api_key=api_key)
|
293 |
+
|
294 |
+
history = history or []
|
295 |
+
history.append({"role": "user", "content": f"Write an article about: {topic}"})
|
296 |
+
yield history
|
297 |
+
|
298 |
+
try:
|
299 |
+
async for messages in article_crew.process_article(topic):
|
300 |
+
history.extend(messages)
|
301 |
yield history
|
302 |
+
except Exception as e:
|
303 |
+
history.append({
|
304 |
+
"role": "assistant",
|
305 |
+
"content": f"An error occurred: {str(e)}",
|
306 |
+
"metadata": {"title": "β Error"}
|
307 |
+
})
|
308 |
+
yield history
|
309 |
|
310 |
def show_interface():
|
311 |
return {
|
|
|
315 |
btn: gr.Button(visible=True)
|
316 |
}
|
317 |
|
318 |
+
openai_api_key.submit(show_interface, None, [openai_api_key, chatbot, topic, btn])
|
319 |
+
btn.click(process_input, [topic, chatbot, openai_api_key], [chatbot])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
320 |
|
321 |
return demo
|
322 |
|