ramsi-k commited on
Commit
43eef2f
Β·
verified Β·
1 Parent(s): 4d5eb4e

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -458
app.py DELETED
@@ -1,458 +0,0 @@
1
- """
2
- 🚧 PROJECT STATUS DISCLAIMER 🚧
3
-
4
- This agentic comic generator project demonstrates a multi-agent workflow architecture
5
- but is NOT fully functional due to several technical limitations:
6
-
7
- KNOWN LIMITATIONS:
8
- 1. πŸ”΄ OpenAI API Rate Limits: Severe restrictions on GPT-4 usage (3 requests/min)
9
- 2. πŸ”΄ Modal .remote() Integration: Gradio doesn't support Modal's serverless functions properly
10
- 3. πŸ”΄ Deployment Constraints: Full pipeline requires Modal infrastructure not available in this demo
11
-
12
- WHAT WORKS:
13
- βœ… Individual agent components (Brown & Bayko) function correctly
14
- βœ… Agent-to-agent communication protocols are implemented
15
- βœ… LlamaIndex workflow architecture is properly structured
16
- βœ… UI components and chat interface work as intended
17
- βœ… Tool calling and response handling mechanisms are functional
18
-
19
- WHAT'S INCOMPLETE:
20
- ❌ End-to-end comic generation pipeline
21
- ❌ Image generation via Modal serverless functions
22
- ❌ Full multi-iteration refinement workflow
23
- ❌ Production-ready error handling and recovery
24
-
25
- This represents a proof-of-concept implementation showcasing the architectural
26
- approach for multi-agent comic generation. The individual components communicate
27
- effectively, but the complete workflow requires infrastructure beyond the current
28
- deployment environment's capabilities.
29
-
30
- For a fully functional version, deploy with proper Modal credentials and
31
- infrastructure setup as outlined in the technical specifications.
32
- """
33
-
34
- import gradio as gr
35
- import time
36
- import json
37
- import os
38
- import sys
39
- import io
40
- import logging
41
- import threading
42
- import queue
43
- from contextlib import redirect_stdout, redirect_stderr
44
- from agents.brown_workflow import create_brown_workflow
45
- from pathlib import Path
46
-
47
-
48
- # Initialize workflow
49
- workflow = create_brown_workflow(
50
- max_iterations=3,
51
- openai_api_key=os.getenv("OPENAI_API_KEY"),
52
- )
53
-
54
-
55
- def colorize_message(message, msg_type="default"):
56
- """Add color coding to messages based on type"""
57
- colors = {
58
- "agent_brown": "#2E86AB", # Blue for Agent Brown
59
- "agent_bayko": "#A23B72", # Purple for Agent Bayko
60
- "tool_output": "#F18F01", # Orange for tool outputs
61
- "error": "#C73E1D", # Red for errors
62
- "success": "#2D5016", # Green for success
63
- "log": "#6C757D", # Gray for logs
64
- "analysis": "#8E44AD", # Purple for analysis
65
- "default": "#212529", # Dark gray default
66
- }
67
-
68
- color = colors.get(msg_type, colors["default"])
69
- return f'<span style="color: {color}; font-weight: bold;">{message}</span>'
70
-
71
-
72
- class LogCapture(io.StringIO):
73
- """Capture all print statements and logs for Gradio display"""
74
-
75
- def __init__(self, log_queue):
76
- super().__init__()
77
- self.log_queue = log_queue
78
- self.original_stdout = sys.stdout
79
-
80
- def write(self, text):
81
- if text.strip(): # Only capture non-empty lines
82
- self.log_queue.put(text.strip())
83
- # Also write to original stdout so terminal still shows logs
84
- self.original_stdout.write(text)
85
- return len(text)
86
-
87
- def flush(self):
88
- self.original_stdout.flush()
89
-
90
-
91
- def comic_generator(prompt, style_preference, verbose=True):
92
- """Verbose comic generation: stream all agent/tool messages and reasoning"""
93
- chat = []
94
- tool_calls = []
95
- images = []
96
- progress = 0
97
-
98
- # Create log queue and capture
99
- log_queue = queue.Queue()
100
- log_capture = LogCapture(log_queue)
101
-
102
- try:
103
- # Start message
104
- chat.append(
105
- (
106
- colorize_message(
107
- "🧐 Agent Brown: Starting comic generation...",
108
- "agent_brown",
109
- ),
110
- )
111
- )
112
- progress += 5
113
- yield chat, images
114
-
115
- # Start workflow in a separate thread to capture logs in real-time
116
- def run_workflow():
117
- with redirect_stdout(log_capture):
118
- return workflow.process_comic_request(
119
- f"{prompt} Style preference: {style_preference}"
120
- )
121
-
122
- # Run workflow in thread
123
- workflow_thread = threading.Thread(
124
- target=lambda: setattr(run_workflow, "result", run_workflow())
125
- )
126
- workflow_thread.start()
127
-
128
- # Stream logs while workflow is running
129
- while workflow_thread.is_alive():
130
- try:
131
- # Get logs from queue with timeout
132
- log_message = log_queue.get(timeout=0.1)
133
- chat.append((colorize_message(f"πŸ“ {log_message}", "log"),))
134
- progress = min(progress + 2, 90)
135
- yield chat, images
136
- except queue.Empty:
137
- continue
138
-
139
- # Wait for thread to complete
140
- workflow_thread.join()
141
-
142
- # Get any remaining logs
143
- while not log_queue.empty():
144
- try:
145
- log_message = log_queue.get_nowait()
146
- chat.append((colorize_message(f"πŸ“ {log_message}", "log"),))
147
- yield chat, images
148
- except queue.Empty:
149
- break
150
-
151
- # Get the result
152
- result = getattr(run_workflow, "result", None)
153
- if not result:
154
- chat.append(("❌ No result from workflow",))
155
- yield chat, images
156
- return
157
-
158
- response_data = (
159
- json.loads(result) if isinstance(result, str) else result
160
- )
161
-
162
- # Show all tool outputs and chat history if available
163
- tool_outputs = response_data.get("tool_outputs", [])
164
- for tool_output in tool_outputs:
165
- # Try to pretty-print tool output JSON if possible
166
- try:
167
- tool_json = json.loads(tool_output)
168
- tool_msg = json.dumps(tool_json, indent=2)
169
- except Exception:
170
- tool_msg = str(tool_output)
171
- chat.append(
172
- (
173
- colorize_message(
174
- f"πŸ› οΈ Tool Output:\n{tool_msg}", "tool_output"
175
- ),
176
- )
177
- )
178
- tool_calls.append("tool_call")
179
- progress = min(progress + 10, 95)
180
- yield chat, images
181
-
182
- # Show error if any
183
- if "error" in response_data:
184
- chat.append(
185
- (
186
- colorize_message(
187
- f"❌ Error: {response_data['error']}", "error"
188
- ),
189
- )
190
- )
191
- progress = 100
192
- yield chat, images
193
- return
194
-
195
- # Show Bayko's panel generation
196
- if "bayko_response" in response_data:
197
- bayko_data = response_data["bayko_response"]
198
- panels = bayko_data.get("panels", [])
199
- progress_per_panel = 50 / max(len(panels), 1)
200
- for i, panel in enumerate(panels, 1):
201
- chat.append(
202
- (
203
- colorize_message(
204
- f"🧸 Agent Bayko: Panel {i}: {panel.get('caption', '')}",
205
- "agent_bayko",
206
- ),
207
- )
208
- )
209
- tool_calls.append("generate_panel_content")
210
- # Show image if available
211
- if "image_path" in panel:
212
- img_path = Path(panel["image_path"])
213
- if img_path.exists():
214
- images.append(str(img_path.absolute()))
215
- elif "image_url" in panel:
216
- images.append(panel["image_url"])
217
- progress += progress_per_panel
218
- yield chat, images
219
- time.sleep(0.2)
220
-
221
- # Show Brown's analysis and decision
222
- if "analysis" in response_data:
223
- chat.append(
224
- (
225
- colorize_message(
226
- f"🧐 Agent Brown Analysis: {response_data['analysis']}",
227
- "analysis",
228
- ),
229
- )
230
- )
231
- tool_calls.append("analyze_bayko_output")
232
- progress = min(progress + 10, 99)
233
- yield chat, images
234
-
235
- # Final decision
236
- if "decision" in response_data:
237
- decision = response_data["decision"]
238
- if decision == "APPROVE":
239
- chat.append(
240
- (
241
- "βœ… Agent Brown: Comic approved! All quality checks passed.",
242
- )
243
- )
244
- elif decision == "REFINE":
245
- chat.append(
246
- (
247
- "πŸ”„ Agent Brown: Comic needs refinement. Starting another iteration...",
248
- )
249
- )
250
- else:
251
- chat.append(
252
- ("❌ Agent Brown: Comic rejected. Starting over...",)
253
- )
254
- tool_calls.append("final_decision")
255
- progress = 100
256
- yield chat, images
257
-
258
- # If verbose, show the full response_data for debugging
259
- if verbose:
260
- chat.append(
261
- (
262
- f"[DEBUG] Full response: {json.dumps(response_data, indent=2)}",
263
- )
264
- )
265
- yield chat, images
266
-
267
- except Exception as e:
268
- chat.append(
269
- (
270
- colorize_message(
271
- f"❌ Error during generation: {str(e)}", "error"
272
- ),
273
- )
274
- )
275
- progress = 100
276
- yield chat, images
277
-
278
-
279
- def set_api_key(api_key):
280
- """Set the OpenAI API key as environment variable"""
281
- if not api_key or not api_key.strip():
282
- return colorize_message("❌ Please enter a valid API key", "error")
283
-
284
- if not api_key.startswith("sk-"):
285
- return colorize_message(
286
- "❌ Invalid API key format (should start with 'sk-')", "error"
287
- )
288
-
289
- # Set the environment variable
290
- os.environ["OPENAI_API_KEY"] = api_key.strip()
291
-
292
- # Update the global workflow with the new key
293
- global workflow
294
- workflow = create_brown_workflow(
295
- max_iterations=3,
296
- openai_api_key=api_key.strip(),
297
- )
298
-
299
- return colorize_message("βœ… API key set successfully!", "success")
300
-
301
-
302
- # Gradio UI
303
- with gr.Blocks() as demo:
304
- gr.Markdown(
305
- """
306
- # 🚧 PROJECT STATUS DISCLAIMER 🚧
307
-
308
- **This agentic comic generator is a PROOF-OF-CONCEPT demonstration with known limitations:**
309
-
310
- ### πŸ”΄ Known Issues:
311
- - **OpenAI Rate Limits:** Severe restrictions (3 requests/min for GPT-4)
312
- - **Modal Integration:** Gradio doesn't support Modal .remote() functions properly
313
- - **Infrastructure:** Full pipeline requires Modal serverless deployment
314
-
315
- ### βœ… What Works:
316
- - Individual agent components (Brown & Bayko) function correctly
317
- - Agent-to-agent communication protocols are implemented
318
- - UI components and workflow architecture are functional
319
-
320
- ### ❌ What's Incomplete:
321
- - End-to-end comic generation pipeline
322
- - Image generation via Modal serverless functions
323
- - Full multi-iteration refinement workflow
324
-
325
- **This demonstrates the architectural approach but is NOT a complete working system.**
326
- """
327
- )
328
-
329
- gr.Markdown(
330
- """
331
- ⚠️ **Additional Warning:** This demo is subject to OpenAI's strict rate limits (3 requests/min for gpt-4o). You may experience long waits (20+ seconds) between steps. If you see a rate limit error, please wait and try again, or use your own OpenAI API key with higher limits.
332
- """
333
- )
334
-
335
- gr.Markdown(
336
- """
337
- # πŸ¦™ Multi-Agent Comic Generator
338
- Enter a story prompt and let Brown & Bayko create a comic!
339
- Watch as the agents collaborate using LlamaIndex workflow and GPT-4V vision capabilities.
340
- """
341
- )
342
-
343
- with gr.Row():
344
- openai_key_box = gr.Textbox(
345
- label="Enter your OpenAI API Key (optional)",
346
- placeholder="sk-...",
347
- type="password",
348
- scale=4,
349
- )
350
- set_key_button = gr.Button("Set API Key πŸ”‘", scale=1)
351
- key_status = gr.Textbox(
352
- label="Status",
353
- value="No API key set",
354
- interactive=False,
355
- scale=2,
356
- )
357
-
358
- with gr.Row():
359
- user_input = gr.Textbox(
360
- label="Enter your comic prompt",
361
- placeholder="A moody K-pop idol finds a puppy on the street...",
362
- scale=4,
363
- )
364
- style_dropdown = gr.Dropdown(
365
- ["Studio Ghibli", "Noir", "Manga", "Pixel Art"],
366
- label="Art Style",
367
- value="Studio Ghibli",
368
- )
369
- submit_button = gr.Button("Generate Comic 🎨")
370
-
371
- with gr.Row():
372
- chat_window = gr.Chatbot(
373
- label="Agent Conversation",
374
- bubble_full_width=False,
375
- show_copy_button=True,
376
- height=350,
377
- )
378
-
379
- with gr.Row():
380
- image_gallery = gr.Gallery(
381
- label="Comic Panels",
382
- columns=2,
383
- rows=2,
384
- height=400,
385
- object_fit="contain",
386
- )
387
- feedback = gr.Radio(
388
- ["πŸ‘ Love it!", "πŸ‘Ž Try again"],
389
- label="How's the comic?",
390
- value=None,
391
- )
392
-
393
- def stream_comic(openai_key, prompt, style):
394
- # Use user-provided OpenAI key if given, else fallback to env
395
- key = openai_key or os.getenv("OPENAI_API_KEY")
396
-
397
- # Set the API key as environment variable if provided
398
- if openai_key:
399
- os.environ["OPENAI_API_KEY"] = openai_key
400
-
401
- # Re-create the workflow with the user key
402
- workflow = create_brown_workflow(
403
- max_iterations=3,
404
- openai_api_key=key,
405
- )
406
- for chat, images in comic_generator(prompt, style, verbose=True):
407
- chat_display = []
408
- for msg in chat:
409
- if isinstance(msg, tuple) and len(msg) >= 1:
410
- # If it's a single-element tuple, make it a proper chat message
411
- if len(msg) == 1:
412
- chat_display.append((msg[0], ""))
413
- else:
414
- chat_display.append(
415
- (msg[0], msg[1] if len(msg) > 1 else "")
416
- )
417
- else:
418
- # Handle string messages
419
- chat_display.append((str(msg), ""))
420
- yield chat_display, images
421
-
422
- submit_button.click(
423
- stream_comic,
424
- inputs=[openai_key_box, user_input, style_dropdown],
425
- outputs=[chat_window, image_gallery],
426
- )
427
-
428
- set_key_button.click(
429
- set_api_key,
430
- inputs=[openai_key_box],
431
- outputs=[key_status],
432
- )
433
-
434
- gr.Markdown(
435
- """
436
- ---
437
- <center>
438
- <b>Built with πŸ¦™ LlamaIndex, Modal Labs, MistralAI and Gradio for the Hugging Face Hackathon!</b>
439
- <br>Using GPT-4 for intelligent comic analysis
440
- </center>
441
- """
442
- )
443
-
444
- gr.Markdown(
445
- """
446
- **πŸš€ Want the real version?**
447
- 1. Clone this Space
448
- 2. Set up Modal credentials
449
- 3. Deploy with actual Modal functions
450
- 4. Enjoy serverless AI magic!
451
-
452
- *This demo shows the UI and MCP structure without Modal execution.*
453
- """
454
- )
455
-
456
- # Launch the app
457
- if __name__ == "__main__":
458
- demo.launch()