eaglelandsonce commited on
Commit
0b2dd75
Β·
verified Β·
1 Parent(s): ceda6e2

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +363 -0
app.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
8
+ import os
9
+
10
+ analysis_text = """
11
+ Stage 1: Ground-Based Spin-Up and Launch Initiation
12
+ β€’ Concept:
13
+ A large, energy‑efficient, electrically powered centrifuge is built on the ground. This β€œspin launcher” uses renewable energy (for example, solar‐assisted electricity) to accelerate a specially designed payload assembly along a rotating arm or in a long circular tunnel.
14
+ β€’ Benefits:
15
+ Because most of the kinetic energy is imparted mechanically (rather than via chemical propellant), the system drastically reduces the need for traditional, polluting rocket propellants. This stage is also relatively low‑cost because the β€œengine” is essentially an electromagnetic drive rather than a rocket motor.
16
+ Stage 2: Controlled Payload Release and Orbital Injection
17
+ β€’ Concept:
18
+ At a pre‑calculated high tangential velocity, the payload is released from the spin launcher. A very short, minimal‐burn liquid or electric thruster (if needed) β€œtunes” the trajectory so that the payload enters a stable, low‑Earth orbit.
19
+ β€’ Benefits:
20
+ The primary acceleration is mechanical, so only a tiny amount of propellant is required for orbital insertion. This greatly cuts both cost and the environmental impact typically associated with rocket launches.
21
+ Stage 3: Autonomous On-Orbit Stabilization and Despinning
22
+ β€’ Concept:
23
+ Once in orbit, the payload’s onboard guidance and control systems (such as small reaction control thrusters or a yo-yo de-spin mechanism) despin and stabilize the payload. Integrated sensors and attitude-control software adjust the payload’s orientation and gently circularize the orbit.
24
+ β€’ Benefits:
25
+ Autonomous stabilization minimizes additional propellant use and prepares the payload for a safe, predictable rendezvous. The controlled despinning ensures that the payload’s docking adapter remains in the proper orientation for subsequent attachment.
26
+ Stage 4: Rendezvous and Docking with the Manned Vehicle
27
+ β€’ Concept:
28
+ A separately launched or pre‑positioned manned spacecraft (or space station) maneuvers to intercept the payload. The payload is equipped with a dedicated docking adapter (for instance, a magnetic or mechanical latch system engineered for high-precision contact under low‑g conditions).
29
+ β€’ Benefits:
30
+ This phase uses conventional low‑delta‑V maneuvers that are far less expensive than a full chemical orbital insertion burn. The docking system is designed to absorb minor mismatches in velocity or attitude, allowing the crew to safely β€œhook on” to the payload. This minimizes extra propellant usage during the rendezvous phase.
31
+ Stage 5: Integrated Mission Operations and Continued Space Activity
32
+ β€’ Concept:
33
+ Once docked, the combined systemβ€”the manned vehicle with the attached spin-delivered payloadβ€”continues its mission. The payload might provide additional resources (such as extra fuel, scientific instruments, or habitat modules) that augment the manned vehicle’s capabilities.
34
+ β€’ Benefits:
35
+ With the payload permanently attached, mission operations (such as orbital adjustments, inter-station transfers, or even on-orbit assembly of larger structures) proceed with enhanced capabilities. The system’s reliance on mechanical acceleration for the bulk of the launch cut both launch costs and the environmental footprint, leaving only minor orbital maneuvers to be performed with conventional thrusters.
36
+ Summary
37
+ This five-stage system marries a ground-based spin acceleration concept with in-space docking and integration to achieve a β€œpropellant-light” method for delivering payloads into orbit. By using a spin launcher to achieve high velocity on the ground (Stage 1) and minimizing onboard chemical propellant (Stage 2), the payload is inserted into orbit economically and with reduced environmental impact. On-orbit stabilization (Stage 3) prepares it for rendezvous with a manned vehicle (Stage 4), after which the combined system carries out the mission (Stage 5).
38
+ """
39
+
40
+ summary_txt = """
41
+ Summary
42
+ This five-stage system marries a ground-based spin acceleration concept with in-space docking and integration to achieve a β€œpropellant-light” method for delivering payloads into orbit. By using a spin launcher to achieve high velocity on the ground (Stage 1) and minimizing onboard chemical propellant (Stage 2), the payload is inserted into orbit economically and with reduced environmental impact. On-orbit stabilization (Stage 3) prepares it for rendezvous with a manned vehicle (Stage 4), after which the combined system carries out the mission (Stage 5).
43
+ """
44
+
45
+ class AgentMessageQueue:
46
+ def __init__(self):
47
+ self.message_queue = queue.Queue()
48
+ self.last_agent = None
49
+
50
+ def add_message(self, message: Dict):
51
+ print(f"Adding message to queue: {message}") # Debug print
52
+ self.message_queue.put(message)
53
+
54
+ def get_messages(self) -> List[Dict]:
55
+ messages = []
56
+ while not self.message_queue.empty():
57
+ messages.append(self.message_queue.get())
58
+ return messages
59
+
60
+ class ArticleCrew:
61
+ def __init__(self, api_key: str = None):
62
+ self.api_key = api_key
63
+ self.message_queue = AgentMessageQueue()
64
+ self.planner = None
65
+ self.writer = None
66
+ self.editor = None
67
+ self.current_agent = None
68
+ self.final_article = None
69
+
70
+ def initialize_agents(self, topic: str):
71
+ if not self.api_key:
72
+ raise ValueError("OpenAI API key is required")
73
+
74
+ os.environ["OPENAI_API_KEY"] = self.api_key
75
+ llm = ChatOpenAI(temperature=0.7, model="gpt-4")
76
+
77
+ self.planner = Agent(
78
+ role="Content Planner",
79
+ goal=f"Plan engaging and factually accurate content on {topic}",
80
+ backstory="Expert content planner with focus on creating engaging outlines",
81
+ allow_delegation=False,
82
+ verbose=True,
83
+ llm=llm
84
+ )
85
+
86
+ self.writer = Agent(
87
+ role="Content Writer",
88
+ goal=f"Write insightful and factually accurate piece about {topic}",
89
+ backstory="Expert content writer with focus on engaging articles",
90
+ allow_delegation=False,
91
+ verbose=True,
92
+ llm=llm
93
+ )
94
+
95
+ self.editor = Agent(
96
+ role="Editor",
97
+ goal="Polish and refine the article",
98
+ backstory="Expert editor with eye for detail and clarity",
99
+ allow_delegation=False,
100
+ verbose=True,
101
+ llm=llm
102
+ )
103
+
104
+ def create_tasks(self, topic: str) -> List[Task]:
105
+ planner_task = Task(
106
+ description=f"""Create a detailed content plan for an article about {topic} by:
107
+ 1. Prioritizing the latest trends, key players, and noteworthy news
108
+ 2. Identifying the target audience, considering their interests and pain points
109
+ 3. Developing a detailed content outline including introduction, key points, and call to action
110
+ 4. Including SEO keywords and relevant data or sources""",
111
+ expected_output="A comprehensive content plan with outline, keywords, and target audience analysis",
112
+ agent=self.planner
113
+ )
114
+
115
+ writer_task = Task(
116
+ description="""Based on the provided content plan:
117
+ 1. Use the content plan to craft a compelling blog post
118
+ 2. Incorporate SEO keywords naturally
119
+ 3. Ensure sections/subtitles are properly named in an engaging manner
120
+ 4. Create proper structure with introduction, body, and conclusion
121
+ 5. Proofread for grammatical errors""",
122
+ expected_output="A well-written article draft following the content plan",
123
+ agent=self.writer
124
+ )
125
+
126
+ editor_task = Task(
127
+ description="""Review the written article by:
128
+ 1. Checking for clarity and coherence
129
+ 2. Correcting any grammatical errors and typos
130
+ 3. Ensuring consistent tone and style
131
+ 4. Verifying proper formatting and structure""",
132
+ expected_output="A polished, final version of the article ready for publication",
133
+ agent=self.editor
134
+ )
135
+
136
+ return [planner_task, writer_task, editor_task]
137
+
138
+ async def process_article(self, topic: str) -> Generator[List[Dict], None, None]:
139
+ def add_agent_messages(agent_name: str, tasks: str, emoji: str = "πŸ€–"):
140
+ # Add agent header
141
+ self.message_queue.add_message({
142
+ "role": "assistant",
143
+ "content": agent_name,
144
+ "metadata": {"title": f"{emoji} {agent_name}"}
145
+ })
146
+
147
+ # Add task description
148
+ self.message_queue.add_message({
149
+ "role": "assistant",
150
+ "content": tasks,
151
+ "metadata": {"title": f"πŸ“‹ Task for {agent_name}"}
152
+ })
153
+
154
+ def setup_next_agent(current_agent: str) -> None:
155
+ agent_sequence = {
156
+ "Content Planner": ("Content Writer", """1. Use the content plan to craft a compelling blog post
157
+ 2. Incorporate SEO keywords naturally
158
+ 3. Ensure sections/subtitles are properly named in an engaging manner
159
+ 4. Create proper structure with introduction, body, and conclusion
160
+ 5. Proofread for grammatical errors"""),
161
+
162
+ "Content Writer": ("Editor", """1. Review the article for clarity and coherence
163
+ 2. Check for grammatical errors and typos
164
+ 3. Ensure consistent tone and style
165
+ 4. Verify proper formatting and structure""")
166
+ }
167
+
168
+ if current_agent in agent_sequence:
169
+ next_agent, tasks = agent_sequence[current_agent]
170
+ self.current_agent = next_agent
171
+ add_agent_messages(next_agent, tasks)
172
+
173
+
174
+ def task_callback(task_output) -> None:
175
+ print(f"Task callback received: {task_output}") # Debug print
176
+
177
+ # Extract content from raw output
178
+ raw_output = task_output.raw
179
+ if "## Final Answer:" in raw_output:
180
+ content = raw_output.split("## Final Answer:")[1].strip()
181
+ else:
182
+ content = raw_output.strip()
183
+
184
+ # Handle the output based on current agent
185
+ if self.current_agent == "Editor":
186
+ # Don't show editor's output with metadata
187
+ # Instead, show completion message and final article
188
+ self.message_queue.add_message({
189
+ "role": "assistant",
190
+ "content": "Final article is ready!",
191
+ "metadata": {"title": "πŸ“ Final Article"}
192
+ })
193
+
194
+ # Convert common markdown patterns to Gradio-compatible markdown
195
+ formatted_content = content
196
+ # Ensure proper spacing for headers
197
+ formatted_content = formatted_content.replace("\n#", "\n\n#")
198
+ # Ensure proper spacing for lists
199
+ formatted_content = formatted_content.replace("\n-", "\n\n-")
200
+ formatted_content = formatted_content.replace("\n*", "\n\n*")
201
+ formatted_content = formatted_content.replace("\n1.", "\n\n1.")
202
+ # Ensure proper spacing for paragraphs
203
+ formatted_content = formatted_content.replace("\n\n\n", "\n\n")
204
+
205
+ # Add the final article content without metadata
206
+ self.message_queue.add_message({
207
+ "role": "assistant",
208
+ "content": formatted_content
209
+ })
210
+ else:
211
+ # For other agents, show their output with metadata
212
+ self.message_queue.add_message({
213
+ "role": "assistant",
214
+ "content": content,
215
+ "metadata": {"title": f"✨ Output from {self.current_agent}"}
216
+ })
217
+ # Setup next agent
218
+ setup_next_agent(self.current_agent)
219
+
220
+ def step_callback(output: Any) -> None:
221
+ print(f"Step callback received: {output}") # Debug print
222
+ # We'll only use step_callback for logging purposes now
223
+ pass
224
+
225
+ try:
226
+ self.initialize_agents(topic)
227
+ self.current_agent = "Content Planner"
228
+
229
+ # Start process
230
+ yield [{
231
+ "role": "assistant",
232
+ "content": "Starting work on your article...",
233
+ "metadata": {"title": "πŸš€ Process Started"}
234
+ }]
235
+
236
+ # Initialize first agent
237
+ add_agent_messages("Content Planner",
238
+ """1. Prioritize the latest trends, key players, and noteworthy news
239
+ 2. Identify the target audience, considering their interests and pain points
240
+ 3. Develop a detailed content outline including introduction, key points, and call to action
241
+ 4. Include SEO keywords and relevant data or sources""")
242
+
243
+ crew = Crew(
244
+ agents=[self.planner, self.writer, self.editor],
245
+ tasks=self.create_tasks(topic),
246
+ verbose=True,
247
+ step_callback=step_callback,
248
+ task_callback=task_callback
249
+ )
250
+
251
+ def run_crew():
252
+ try:
253
+ crew.kickoff()
254
+ except Exception as e:
255
+ print(f"Error in crew execution: {str(e)}") # Debug print
256
+ self.message_queue.add_message({
257
+ "role": "assistant",
258
+ "content": f"An error occurred: {str(e)}",
259
+ "metadata": {"title": "❌ Error"}
260
+ })
261
+
262
+ thread = threading.Thread(target=run_crew)
263
+ thread.start()
264
+
265
+ while thread.is_alive() or not self.message_queue.message_queue.empty():
266
+ messages = self.message_queue.get_messages()
267
+ if messages:
268
+ print(f"Yielding messages: {messages}") # Debug print
269
+ yield messages
270
+ await asyncio.sleep(0.1)
271
+
272
+ except Exception as e:
273
+ print(f"Error in process_article: {str(e)}") # Debug print
274
+ yield [{
275
+ "role": "assistant",
276
+ "content": f"An error occurred: {str(e)}",
277
+ "metadata": {"title": "❌ Error"}
278
+ }]
279
+
280
+ # [Rest of the code remains the same]
281
+
282
+
283
+ def create_demo():
284
+ article_crew = None
285
+
286
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
287
+ gr.Markdown("# πŸ“ AI Article Writing Crew")
288
+
289
+ openai_api_key = gr.Textbox(
290
+ label='OpenAI API Key',
291
+ type='password',
292
+ placeholder='Enter your OpenAI API key...',
293
+ interactive=True
294
+ )
295
+
296
+ chatbot = gr.Chatbot(
297
+ label="Writing Process",
298
+ height=700,
299
+ type="messages",
300
+ show_label=True,
301
+ visible=False,
302
+ avatar_images=(None, "https://avatars.githubusercontent.com/u/170677839?v=4"),
303
+ render_markdown=True # Enable markdown rendering
304
+ )
305
+
306
+ with gr.Row(equal_height=True):
307
+ topic = gr.Textbox(
308
+ label="Article Topic",
309
+ placeholder="Enter topic...",
310
+ scale=4,
311
+ visible=False
312
+ )
313
+ btn = gr.Button("Write Article", variant="primary", scale=1, visible=False)
314
+
315
+ async def process_input(topic, history, api_key):
316
+ nonlocal article_crew
317
+ if not api_key:
318
+ history = history or []
319
+ history.append({
320
+ "role": "assistant",
321
+ "content": "Please provide an OpenAI API key.",
322
+ "metadata": {"title": "❌ Error"}
323
+ })
324
+ yield history
325
+ return
326
+
327
+ if article_crew is None:
328
+ article_crew = ArticleCrew(api_key=api_key)
329
+
330
+ history = history or []
331
+ history.append({"role": "user", "content": f"Write an article about: {topic}"})
332
+ yield history
333
+
334
+ try:
335
+ async for messages in article_crew.process_article(topic):
336
+ history.extend(messages)
337
+ yield history
338
+ except Exception as e:
339
+ history.append({
340
+ "role": "assistant",
341
+ "content": f"An error occurred: {str(e)}",
342
+ "metadata": {"title": "❌ Error"}
343
+ })
344
+ yield history
345
+
346
+ def show_interface():
347
+ return {
348
+ openai_api_key: gr.Textbox(visible=False),
349
+ chatbot: gr.Chatbot(visible=True),
350
+ topic: gr.Textbox(visible=True),
351
+ btn: gr.Button(visible=True)
352
+ }
353
+
354
+ openai_api_key.submit(show_interface, None, [openai_api_key, chatbot, topic, btn])
355
+ btn.click(process_input, [topic, chatbot, openai_api_key], [chatbot])
356
+ topic.submit(process_input, [topic, chatbot, openai_api_key], [chatbot])
357
+
358
+ return demo
359
+
360
+ if __name__ == "__main__":
361
+ demo = create_demo()
362
+ demo.queue()
363
+ demo.launch(debug=True)