Noo88ear commited on
Commit
7e8adfc
Β·
verified Β·
1 Parent(s): 17a51e1

Rename app.py to app_all_in_one_a2a.py

Browse files
Files changed (2) hide show
  1. app.py +0 -629
  2. app_all_in_one_a2a.py +338 -0
app.py DELETED
@@ -1,629 +0,0 @@
1
- import gradio as gr
2
- from PIL import Image, ImageDraw, ImageFont
3
- import requests
4
- import json
5
- import base64
6
- import io
7
- import asyncio
8
- import aiohttp
9
- import os
10
- import time
11
- import traceback
12
-
13
- # Configuration - matching full Streamlit functionality
14
- ORCHESTRATOR_URL = os.getenv("ORCHESTRATOR_URL", "http://localhost:8000")
15
- GENERATOR_URL = os.getenv("GENERATOR_URL", "http://localhost:8001")
16
- REVIEWER_URL = os.getenv("REVIEWER_URL", "http://localhost:8002")
17
-
18
- # Backward compatibility
19
- AGENT1_URL = os.getenv("AGENT1_URL", GENERATOR_URL)
20
- AGENT2_URL = os.getenv("AGENT2_URL", REVIEWER_URL)
21
-
22
- async def call_agent1_generate(prompt, style):
23
- """Call Agent1 to generate an image"""
24
- try:
25
- payload = {
26
- "prompt": prompt,
27
- "style": style.lower(),
28
- "size": "1024x1024",
29
- "quality": "standard"
30
- }
31
-
32
- async with aiohttp.ClientSession() as session:
33
- async with session.post(f"{AGENT1_URL}/generate", json=payload, timeout=60) as response:
34
- if response.status == 200:
35
- result = await response.json()
36
- return result
37
- else:
38
- error_text = await response.text()
39
- return {"error": f"Agent1 error {response.status}: {error_text}"}
40
- except Exception as e:
41
- return {"error": f"Failed to connect to Agent1: {str(e)}"}
42
-
43
- async def call_agent2_review(image_url, prompt, review_guidelines=""):
44
- """Call Agent2 to review the generated image"""
45
- try:
46
- payload = {
47
- "image_url": image_url,
48
- "original_prompt": prompt,
49
- "review_criteria": ["quality", "relevance", "safety"]
50
- }
51
-
52
- # Add review guidelines if provided
53
- if review_guidelines.strip():
54
- payload["review_guidelines"] = review_guidelines
55
-
56
- async with aiohttp.ClientSession() as session:
57
- async with session.post(f"{AGENT2_URL}/review", json=payload, timeout=30) as response:
58
- if response.status == 200:
59
- result = await response.json()
60
- return result
61
- else:
62
- error_text = await response.text()
63
- return {"error": f"Agent2 error {response.status}: {error_text}"}
64
- except Exception as e:
65
- return {"error": f"Failed to connect to Agent2: {str(e)}"}
66
-
67
- def create_fallback_image(prompt, style):
68
- """Create a fallback demo image when agents are unavailable"""
69
- colors = {"Professional": "#3B82F6", "Creative": "#8B5CF6", "Minimalist": "#6B7280", "Corporate": "#1E40AF", "Modern": "#059669"}
70
- color = colors.get(style, "#3B82F6")
71
- rgb = tuple(int(color[i:i+2], 16) for i in (1, 4, 7))
72
-
73
- img = Image.new("RGB", (512, 512), rgb)
74
- draw = ImageDraw.Draw(img)
75
- font = ImageFont.load_default()
76
-
77
- draw.text((50, 200), "Marketing Image", fill="white", font=font)
78
- draw.text((50, 230), f"{style} Style", fill="white", font=font)
79
- draw.text((50, 260), prompt[:35] + "..." if len(prompt) > 35 else prompt, fill=(200, 200, 200), font=font)
80
- draw.text((50, 350), "(Fallback Mode)", fill=(150, 150, 150), font=font)
81
-
82
- return img
83
-
84
- def generate_image_with_review(prompt, style, max_retries=3, review_threshold=0.8, review_guidelines=""):
85
- """Generate an image with automated review using Agent1 and Agent2 with retry logic - mirrors Streamlit function"""
86
- workflow_history = []
87
-
88
- try:
89
- for iteration in range(1, max_retries + 1):
90
- print(f"πŸ”„ Iteration {iteration} of {max_retries}")
91
-
92
- # Step 1: Call Agent1 to generate the image
93
- agent1_payload = {
94
- "prompt": prompt,
95
- "style": style.lower(),
96
- "size": "1024x1024",
97
- "quality": "standard"
98
- }
99
-
100
- agent1_response = requests.post(f"{GENERATOR_URL}/generate", json=agent1_payload, timeout=60)
101
-
102
- if agent1_response.status_code != 200:
103
- return {"success": False, "error": f"Agent1 failed: {agent1_response.text}"}
104
-
105
- agent1_result = agent1_response.json()
106
- image_url = agent1_result.get("image_url", "")
107
-
108
- if not image_url:
109
- return {"success": False, "error": "Agent1 did not return an image URL"}
110
-
111
- # Step 2: Call Agent2 to review the generated image
112
- agent2_payload = {
113
- "image_url": image_url,
114
- "original_prompt": prompt,
115
- "review_criteria": ["quality", "relevance", "safety"]
116
- }
117
-
118
- # Add review guidelines if provided
119
- if review_guidelines.strip():
120
- agent2_payload["review_guidelines"] = review_guidelines
121
-
122
- agent2_response = requests.post(f"{REVIEWER_URL}/review", json=agent2_payload, timeout=30)
123
-
124
- if agent2_response.status_code != 200:
125
- # Continue with just the image if review fails
126
- workflow_history.append({
127
- "iteration": iteration,
128
- "agent1_status": "success",
129
- "agent2_status": "failed",
130
- "review_score": 0.7,
131
- "feedback": {"error": "Agent2 review failed"}
132
- })
133
-
134
- return {
135
- "success": True,
136
- "image": {
137
- "url": image_url,
138
- "data": image_url,
139
- "prompt": prompt,
140
- "style": style
141
- },
142
- "review": {
143
- "quality_score": 0.7,
144
- "final_status": "review_failed",
145
- "iterations": iteration,
146
- "passed": True,
147
- "recommendations": ["Agent2 review failed - using generated image"],
148
- "workflow_history": workflow_history
149
- },
150
- "metadata": agent1_result.get("metadata", {})
151
- }
152
-
153
- agent2_result = agent2_response.json()
154
- review_score = agent2_result.get("review_score", 0.7)
155
-
156
- # Add to workflow history
157
- workflow_history.append({
158
- "iteration": iteration,
159
- "agent1_status": "success",
160
- "agent2_status": "success",
161
- "review_score": review_score,
162
- "feedback": agent2_result.get("feedback", {}),
163
- "recommendations": agent2_result.get("recommendations", [])
164
- })
165
-
166
- # Check if quality threshold is met
167
- if review_score >= review_threshold:
168
- print(f"βœ… Quality threshold met on iteration {iteration}!")
169
-
170
- return {
171
- "success": True,
172
- "image": {
173
- "url": image_url,
174
- "data": image_url,
175
- "prompt": prompt,
176
- "style": style
177
- },
178
- "review": {
179
- "quality_score": review_score,
180
- "final_status": "passed",
181
- "iterations": iteration,
182
- "passed": True,
183
- "recommendations": agent2_result.get("recommendations", []),
184
- "workflow_history": workflow_history
185
- },
186
- "metadata": agent1_result.get("metadata", {})
187
- }
188
- else:
189
- print(f"⚠️ Quality score {review_score:.2f} below threshold {review_threshold}. Retrying...")
190
- if iteration < max_retries:
191
- # Enhance prompt for next iteration based on feedback
192
- feedback = agent2_result.get("feedback", {})
193
- if "relevance" in feedback and "missing_elements" in feedback["relevance"]:
194
- missing = feedback["relevance"]["missing_elements"]
195
- if missing:
196
- prompt += f" Including: {', '.join(missing[:3])}"
197
-
198
- # If we get here, all retries failed to meet threshold
199
- return {
200
- "success": True,
201
- "image": {
202
- "url": image_url,
203
- "data": image_url,
204
- "prompt": prompt,
205
- "style": style
206
- },
207
- "review": {
208
- "quality_score": review_score,
209
- "final_status": "needs_improvement",
210
- "iterations": max_retries,
211
- "passed": False,
212
- "recommendations": agent2_result.get("recommendations", []) + [f"Failed to meet quality threshold {review_threshold} after {max_retries} attempts"],
213
- "workflow_history": workflow_history
214
- },
215
- "metadata": agent1_result.get("metadata", {})
216
- }
217
-
218
- except Exception as e:
219
- return {"success": False, "error": f"Unexpected error: {str(e)}"}
220
-
221
- def process_generated_image_and_results(api_response):
222
- """Process API response and return image and review text for Gradio display"""
223
- try:
224
- # Parse the response if it's a string
225
- if isinstance(api_response, str):
226
- response_data = json.loads(api_response)
227
- else:
228
- response_data = api_response
229
-
230
- # Check if the response was successful
231
- if not response_data.get('success', False):
232
- return None, f"❌ API call failed: {response_data.get('error', 'Unknown error')}"
233
-
234
- # Data can be at top level or nested under 'data' key
235
- data = response_data.get('data', response_data)
236
-
237
- # Extract image data
238
- image_info = data.get('image', {})
239
- image_data_b64 = ""
240
- image = None
241
-
242
- # Try different possible image data locations
243
- if 'data' in image_info:
244
- image_data_b64 = image_info['data']
245
- elif 'url' in image_info and image_info['url'].startswith('data:image'):
246
- image_data_b64 = image_info['url']
247
- elif 'image_url' in data:
248
- image_data_b64 = data['image_url']
249
-
250
- if image_data_b64:
251
- try:
252
- # Handle data URL format
253
- if image_data_b64.startswith('data:image'):
254
- base64_data = image_data_b64.split(',')[1]
255
- elif image_data_b64.startswith('http'):
256
- # Handle regular URL (like picsum.photos)
257
- response = requests.get(image_data_b64, timeout=10)
258
- if response.status_code == 200:
259
- image = Image.open(io.BytesIO(response.content))
260
- else:
261
- image = None
262
- else:
263
- base64_data = image_data_b64
264
-
265
- if image is None and 'base64_data' in locals():
266
- # Decode base64 image
267
- image_bytes = base64.b64decode(base64_data)
268
- image = Image.open(io.BytesIO(image_bytes))
269
-
270
- except Exception as e:
271
- print(f"Error processing image: {str(e)}")
272
- image = None
273
-
274
- # Extract review data
275
- review_data = data.get('review', {})
276
- if not review_data:
277
- review_data = response_data.get('review', {})
278
-
279
- # Format review text
280
- if review_data:
281
- quality_score = review_data.get('quality_score', 0)
282
- passed = review_data.get('passed', False)
283
- final_status = review_data.get('final_status', 'unknown')
284
- iterations = review_data.get('iterations', 0)
285
- recommendations = review_data.get('recommendations', [])
286
-
287
- status_emoji = "🟒" if passed else "πŸ”΄"
288
-
289
- review_text = f"""**πŸ” AI Review Results**
290
-
291
- **Quality Score:** {quality_score:.2f}/1.0
292
- **Status:** {status_emoji} {final_status.upper()}
293
- **Iterations:** {iterations}
294
-
295
- **πŸ’‘ Recommendations:**
296
- """
297
-
298
- if recommendations:
299
- for i, rec in enumerate(recommendations[:5], 1):
300
- review_text += f"{i}. {rec}\n"
301
- else:
302
- review_text += "β€’ Image meets quality standards\n"
303
-
304
- # Add workflow history if available
305
- workflow_history = review_data.get('workflow_history', [])
306
- if workflow_history and len(workflow_history) > 1:
307
- review_text += "\n**πŸ“‹ Workflow History:**\n"
308
- for item in workflow_history:
309
- iteration = item.get('iteration', 'N/A')
310
- score = item.get('review_score', 'N/A')
311
- review_text += f"β€’ Iteration {iteration}: Score {score:.2f}\n"
312
- else:
313
- review_text = "⚠️ Review data not available"
314
-
315
- return image, review_text
316
-
317
- except Exception as e:
318
- error_text = f"❌ Error processing results: {str(e)}\n\n**Debug Info:**\n{traceback.format_exc()}"
319
- return None, error_text
320
-
321
- async def generate_and_review_async(prompt, style, review_guidelines=""):
322
- """Generate image with Agent1 and review with Agent2 - legacy function for backward compatibility"""
323
- if not prompt.strip():
324
- return None, "Please enter a prompt"
325
-
326
- # Step 1: Generate image with Agent1
327
- agent1_result = await call_agent1_generate(prompt, style)
328
-
329
- if "error" in agent1_result:
330
- # Fallback to demo image
331
- fallback_image = create_fallback_image(prompt, style)
332
- return fallback_image, f"**Agent1 Unavailable**: {agent1_result['error']}\n\nUsing fallback demo image."
333
-
334
- # Extract image from Agent1 response
335
- image_url = agent1_result.get("image_url", "")
336
- image = None
337
-
338
- if image_url:
339
- try:
340
- if image_url.startswith("data:image"):
341
- # Handle base64 data URL
342
- base64_data = image_url.split(',')[1]
343
- image_bytes = base64.b64decode(base64_data)
344
- image = Image.open(io.BytesIO(image_bytes))
345
- elif image_url.startswith("http"):
346
- # Handle regular URL (like picsum.photos)
347
- async with aiohttp.ClientSession() as session:
348
- async with session.get(image_url) as response:
349
- if response.status == 200:
350
- image_bytes = await response.read()
351
- image = Image.open(io.BytesIO(image_bytes))
352
- except Exception as e:
353
- print(f"Error loading image: {e}")
354
-
355
- if image is None:
356
- image = create_fallback_image(prompt, style)
357
- image_url = "fallback://demo"
358
-
359
- # Step 2: Review image with Agent2
360
- agent2_result = await call_agent2_review(image_url, prompt, review_guidelines)
361
-
362
- if "error" in agent2_result:
363
- # Simple review fallback
364
- word_count = len(prompt.split())
365
- quality = "Excellent" if word_count > 15 else "Good" if word_count > 8 else "Basic"
366
-
367
- review = f"""**Agent Review (Fallback Mode)**
368
-
369
- Agent1: Generated {style.lower()} marketing image βœ…
370
- Agent2: Unavailable - {agent2_result['error']}
371
-
372
- Prompt Quality: {quality} ({word_count} words)
373
- Style: {style}
374
- Status: Image generated but not reviewed
375
-
376
- Recommendation: {f"Great detail level!" if word_count > 15 else "Consider adding more descriptive details"}"""
377
- else:
378
- # Format Agent2 review results
379
- review_score = agent2_result.get("review_score", 0)
380
- feedback = agent2_result.get("feedback", {})
381
- recommendations = agent2_result.get("recommendations", [])
382
-
383
- quality_feedback = feedback.get("quality", {})
384
- relevance_feedback = feedback.get("relevance", {})
385
- safety_feedback = feedback.get("safety", {})
386
-
387
- review = f"""**πŸ€– AI Agent Review Complete**
388
-
389
- **Agent1**: Generated {style.lower()} marketing image βœ…
390
- **Agent2**: Quality analysis complete βœ…
391
-
392
- **Overall Score**: {review_score:.2f}/1.0
393
- **Quality**: {quality_feedback.get('score', 'N/A')}
394
- **Relevance**: {relevance_feedback.get('score', 'N/A')}
395
- **Safety**: {safety_feedback.get('score', 'N/A')}
396
-
397
- **Status**: {'βœ… Approved' if review_score > 0.7 else '⚠️ Needs Improvement'}
398
-
399
- **Recommendations**:
400
- {chr(10).join(f"β€’ {rec}" for rec in recommendations[:3]) if recommendations else "β€’ Image meets quality standards"}"""
401
-
402
- return image, review
403
-
404
- def check_service_health():
405
- """Check the health of all agent services"""
406
- health_status = {}
407
-
408
- # Check Agent1 (Image Generator)
409
- try:
410
- response = requests.get(f"{GENERATOR_URL}/health", timeout=5)
411
- health_status["Agent1 (Generator)"] = response.status_code == 200
412
- except:
413
- health_status["Agent1 (Generator)"] = False
414
-
415
- # Check Agent2 (Reviewer)
416
- try:
417
- response = requests.get(f"{REVIEWER_URL}/health", timeout=5)
418
- health_status["Agent2 (Marketing Reviewer)"] = response.status_code == 200
419
- except:
420
- health_status["Agent2 (Marketing Reviewer)"] = False
421
-
422
- # Check Orchestrator (if available)
423
- try:
424
- response = requests.get(f"{ORCHESTRATOR_URL}/health", timeout=5)
425
- health_status["Orchestrator"] = response.status_code == 200
426
- except:
427
- health_status["Orchestrator"] = False
428
-
429
- return health_status
430
-
431
- def get_system_status():
432
- """Get system status for display"""
433
- health_status = check_service_health()
434
-
435
- status_text = "**πŸ”§ System Status:**\n\n"
436
- for service_name, is_healthy in health_status.items():
437
- status_emoji = "βœ…" if is_healthy else "❌"
438
- status_text += f"{status_emoji} {service_name}\n"
439
-
440
- all_healthy = all(health_status.values())
441
- if all_healthy:
442
- status_text += "\nπŸŽ‰ All services are running!"
443
- else:
444
- status_text += "\n⚠️ Some services are not responding."
445
-
446
- return status_text
447
-
448
- def generate_marketing_image(prompt, style, max_retries, review_threshold, review_guidelines):
449
- """Main function called by Gradio interface - enhanced version"""
450
- if not prompt.strip():
451
- return None, "⚠️ Please enter a prompt to generate an image."
452
-
453
- try:
454
- # Call the same backend function as Streamlit
455
- result = generate_image_with_review(prompt, style, max_retries, review_threshold, review_guidelines)
456
-
457
- if result["success"]:
458
- # Process the results for display
459
- image, review_text = process_generated_image_and_results(result)
460
-
461
- success_message = f"βœ… Image generated successfully!\n\n{review_text}"
462
- return image, success_message
463
- else:
464
- error_message = f"❌ Generation failed: {result.get('error', 'Unknown error')}"
465
- return None, error_message
466
-
467
- except Exception as e:
468
- error_message = f"❌ Error generating image: {str(e)}\n\n**Debug Info:**\n{traceback.format_exc()}"
469
- return None, error_message
470
-
471
- def generate_and_review(prompt, style):
472
- """Sync wrapper for async function - legacy compatibility"""
473
- loop = asyncio.new_event_loop()
474
- asyncio.set_event_loop(loop)
475
- try:
476
- return loop.run_until_complete(generate_and_review_async(prompt, style))
477
- finally:
478
- loop.close()
479
-
480
- def use_suggested_prompt(suggested_prompt, suggested_style):
481
- """Update prompt and style with suggested values"""
482
- return suggested_prompt, suggested_style
483
-
484
- # Define suggested prompts (matching Streamlit app)
485
- SUGGESTED_PROMPTS = {
486
- "Modern office team collaboration": ("A modern office space with diverse professionals collaborating around a sleek conference table, natural lighting, professional attire, English signage visible", "realistic"),
487
- "Executive boardroom meeting": ("Professional executive boardroom with polished conference table, city skyline view, business documents, English presentations on screens", "realistic"),
488
- "Customer service excellence": ("Professional customer service representative with headset in modern call center, English signage, clean corporate environment", "realistic"),
489
- "Product showcase display": ("Clean product showcase on white background with professional lighting, English product labels, minimalist marketing aesthetic", "realistic"),
490
- "Creative workspace design": ("Creative workspace with colorful design elements, inspirational English quotes on walls, modern furniture, artistic marketing materials", "artistic"),
491
- "Brand presentation setup": ("Professional brand presentation setup with English branded materials, corporate colors, marketing displays, conference room setting", "realistic")
492
- }
493
-
494
- # Create enhanced Gradio interface
495
- with gr.Blocks(title="Marketing Image Generator", theme=gr.themes.Soft()) as demo:
496
- gr.Markdown("""
497
- # 🎨 Marketing Image Generator with Marketing Review
498
- ### Create stunning marketing images with AI-powered Marketing Reviewer
499
-
500
- Agent1 creates β†’ Agent2 reviews β†’ Professional results with automated quality assurance
501
- """)
502
-
503
- with gr.Row():
504
- with gr.Column(scale=1):
505
- gr.Markdown("### βš™οΈ Configuration")
506
-
507
- # Main inputs
508
- prompt = gr.Textbox(
509
- label="Describe your marketing image",
510
- placeholder="e.g., A modern office space with natural lighting, featuring diverse professionals collaborating around a sleek conference table",
511
- lines=4,
512
- info="Be specific about the scene, style, mood, and any marketing elements you want to include"
513
- )
514
-
515
- style = gr.Dropdown(
516
- choices=["realistic", "artistic", "cartoon", "photographic", "illustration"],
517
- value="realistic",
518
- label="Art Style",
519
- info="Choose the artistic style for your generated image"
520
- )
521
-
522
- review_guidelines = gr.Textbox(
523
- label="πŸ” Marketing Review Guidelines (Optional)",
524
- placeholder="e.g., All text must be in English only, focus on professional appearance, ensure brand colors are prominent, check accessibility compliance, verify readability",
525
- lines=3,
526
- info="Provide specific marketing guidelines for the Marketing Reviewer to evaluate against your brand standards"
527
- )
528
-
529
- # Advanced settings
530
- with gr.Accordion("πŸ”§ Advanced Settings", open=False):
531
- max_retries = gr.Slider(
532
- minimum=1,
533
- maximum=5,
534
- value=3,
535
- step=1,
536
- label="Max Retries",
537
- info="Maximum number of retry attempts if generation fails"
538
- )
539
-
540
- review_threshold = gr.Slider(
541
- minimum=0.0,
542
- maximum=1.0,
543
- value=0.8,
544
- step=0.1,
545
- label="Quality Threshold",
546
- info="Minimum quality score required for auto-approval"
547
- )
548
-
549
- # Generate buttons
550
- generate_enhanced_btn = gr.Button("πŸš€ Generate with Full Review", variant="primary", size="lg")
551
- generate_simple_btn = gr.Button("⚑ Quick Generate", variant="secondary", size="sm")
552
-
553
- # System status
554
- with gr.Accordion("πŸ“Š System Status", open=False):
555
- status_display = gr.Markdown(get_system_status())
556
- refresh_status_btn = gr.Button("πŸ”„ Refresh Status", size="sm")
557
-
558
- with gr.Column(scale=2):
559
- # Results display
560
- gr.Markdown("### πŸ–ΌοΈ Generated Image & Review")
561
-
562
- image_output = gr.Image(
563
- label="Generated Marketing Image",
564
- type="pil",
565
- height=400,
566
- show_download_button=True
567
- )
568
-
569
- review_output = gr.Markdown(
570
- value="Click **Generate** to create your marketing image with AI review",
571
- label="AI Review Results"
572
- )
573
-
574
- # Suggested prompts section
575
- gr.Markdown("---")
576
- gr.Markdown("### πŸ’‘ Suggested Marketing Prompts")
577
-
578
- with gr.Row():
579
- with gr.Column():
580
- gr.Markdown("**🏒 Professional/Corporate**")
581
- for prompt_name in ["Modern office team collaboration", "Executive boardroom meeting", "Customer service excellence"]:
582
- suggested_prompt, suggested_style = SUGGESTED_PROMPTS[prompt_name]
583
- btn = gr.Button(prompt_name, size="sm")
584
- btn.click(
585
- fn=lambda p=suggested_prompt, s=suggested_style: (p, s),
586
- outputs=[prompt, style]
587
- )
588
-
589
- with gr.Column():
590
- gr.Markdown("**🎨 Creative/Marketing**")
591
- for prompt_name in ["Product showcase display", "Creative workspace design", "Brand presentation setup"]:
592
- suggested_prompt, suggested_style = SUGGESTED_PROMPTS[prompt_name]
593
- btn = gr.Button(prompt_name, size="sm")
594
- btn.click(
595
- fn=lambda p=suggested_prompt, s=suggested_style: (p, s),
596
- outputs=[prompt, style]
597
- )
598
-
599
- # Event handlers
600
- generate_enhanced_btn.click(
601
- fn=generate_marketing_image,
602
- inputs=[prompt, style, max_retries, review_threshold, review_guidelines],
603
- outputs=[image_output, review_output],
604
- show_progress=True
605
- )
606
-
607
- generate_simple_btn.click(
608
- fn=generate_and_review,
609
- inputs=[prompt, style],
610
- outputs=[image_output, review_output],
611
- show_progress=True
612
- )
613
-
614
- refresh_status_btn.click(
615
- fn=get_system_status,
616
- outputs=status_display
617
- )
618
-
619
- # Footer
620
- gr.Markdown("""
621
- ---
622
- <div style='text-align: center; color: #666; font-size: 0.9rem;'>
623
- <p>🎨 Marketing Image Generator with Agent Review | Powered by Google Imagen3 & AI Agents</p>
624
- <p>Create professional marketing images with automated quality assurance</p>
625
- </div>
626
- """)
627
-
628
- if __name__ == "__main__":
629
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_all_in_one_a2a.py ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ All-in-One Marketing Image Generator with Proper A2A Architecture
3
+ Includes A2A Orchestrator + Agent1 (MCP-Imagen3) + Agent2 (Reviewer) + Gradio Interface
4
+ """
5
+
6
+ import gradio as gr
7
+ import os
8
+ import logging
9
+ import asyncio
10
+ import json
11
+ from typing import Dict, Any
12
+ from PIL import Image
13
+ import io
14
+ import base64
15
+
16
+ # A2A imports
17
+ try:
18
+ from a2a_orchestrator import A2AOrchestrator
19
+ A2A_AVAILABLE = True
20
+ except ImportError:
21
+ A2A_AVAILABLE = False
22
+
23
+ # Configure logging
24
+ logging.basicConfig(level=logging.INFO)
25
+ logger = logging.getLogger(__name__)
26
+
27
+ # Initialize A2A Orchestrator
28
+ if A2A_AVAILABLE:
29
+ orchestrator = A2AOrchestrator()
30
+ logger.info("βœ… A2A Orchestrator initialized")
31
+ else:
32
+ orchestrator = None
33
+ logger.warning("⚠️ A2A not available - will use fallback mode")
34
+
35
+ def process_generated_image_and_results(api_response):
36
+ """Process API response and return image and review text for Gradio display"""
37
+ try:
38
+ response_data = api_response
39
+
40
+ if not response_data.get('success', False):
41
+ return None, f"❌ Generation failed: {response_data.get('error', 'Unknown error')}"
42
+
43
+ # Extract image data
44
+ image_info = response_data.get('image', {})
45
+ image_data_b64 = image_info.get('data', image_info.get('url', ''))
46
+
47
+ image = None
48
+ if image_data_b64 and image_data_b64.startswith('data:image'):
49
+ try:
50
+ base64_data = image_data_b64.split(',')[1]
51
+ image_bytes = base64.b64decode(base64_data)
52
+ image = Image.open(io.BytesIO(image_bytes))
53
+ except Exception as e:
54
+ logger.error(f"Error processing image: {str(e)}")
55
+
56
+ # Extract review data
57
+ review_data = response_data.get('review', {})
58
+
59
+ if review_data:
60
+ quality_score = review_data.get('quality_score', 0)
61
+ passed = review_data.get('passed', False)
62
+ final_status = review_data.get('final_status', 'unknown')
63
+ iterations = review_data.get('iterations', 0)
64
+ recommendations = review_data.get('recommendations', [])
65
+
66
+ status_emoji = "🟒" if passed else "πŸ”΄"
67
+
68
+ # Extract metadata about generation method
69
+ metadata = response_data.get('metadata', {})
70
+ generation_method = metadata.get('generation_method', 'unknown')
71
+ real_ai = metadata.get('real_ai_generation', False)
72
+
73
+ generation_info = ""
74
+ if generation_method == "imagen3-mcp":
75
+ generation_info = "🎨 **Generated with**: Imagen3-MCP (Real AI)\n"
76
+ elif generation_method == "google-genai-sdk":
77
+ generation_info = "🎨 **Generated with**: Google Genai SDK (Real AI)\n"
78
+ elif generation_method == "placeholder":
79
+ generation_info = "🎨 **Generated with**: Placeholder (Fallback)\n"
80
+
81
+ review_text = f"""**πŸ” A2A Marketing Review Results**
82
+
83
+ {generation_info}
84
+ **Quality Score:** {quality_score:.2f}/1.0
85
+ **Status:** {status_emoji} {final_status.upper()}
86
+ **Iterations:** {iterations}
87
+ **Architecture:** A2A Agent Communication
88
+
89
+ **πŸ’‘ Recommendations:**
90
+ """
91
+
92
+ if recommendations:
93
+ for i, rec in enumerate(recommendations[:5], 1):
94
+ review_text += f"{i}. {rec}\n"
95
+ else:
96
+ review_text += "β€’ Image meets quality standards\n"
97
+
98
+ # Add workflow history
99
+ workflow_history = review_data.get('workflow_history', [])
100
+ if workflow_history and len(workflow_history) > 1:
101
+ review_text += "\n**πŸ“‹ A2A Workflow History:**\n"
102
+ for item in workflow_history:
103
+ iteration = item.get('iteration', 'N/A')
104
+ score = item.get('review_score', 'N/A')
105
+ review_text += f"β€’ Iteration {iteration}: Score {score:.2f}\n"
106
+ else:
107
+ review_text = "⚠️ Review data not available"
108
+
109
+ return image, review_text
110
+
111
+ except Exception as e:
112
+ return None, f"❌ Error processing results: {str(e)}"
113
+
114
+ def generate_marketing_image_a2a(prompt, style, max_retries, review_threshold, review_guidelines):
115
+ """Main function for the Gradio interface using A2A Orchestrator"""
116
+ if not prompt.strip():
117
+ return None, "⚠️ Please enter a prompt to generate an image."
118
+
119
+ if not A2A_AVAILABLE or not orchestrator:
120
+ return None, "❌ A2A Orchestrator not available. Please check setup."
121
+
122
+ try:
123
+ logger.info(f"🎭 Starting A2A workflow for: {prompt}")
124
+
125
+ # Use the A2A orchestrator to coordinate agents
126
+ result = asyncio.run(
127
+ orchestrator.generate_image_with_review(
128
+ prompt=prompt,
129
+ style=style,
130
+ max_retries=max_retries,
131
+ review_threshold=review_threshold,
132
+ review_guidelines=review_guidelines
133
+ )
134
+ )
135
+
136
+ if result["success"]:
137
+ image, review_text = process_generated_image_and_results(result)
138
+ success_message = f"βœ… A2A Image generation successful!\n\n{review_text}"
139
+ return image, success_message
140
+ else:
141
+ error_message = f"❌ A2A Generation failed: {result.get('error', 'Unknown error')}"
142
+ return None, error_message
143
+
144
+ except Exception as e:
145
+ error_message = f"❌ A2A Error: {str(e)}"
146
+ logger.error(error_message)
147
+ return None, error_message
148
+
149
+ async def check_a2a_agents():
150
+ """Check if A2A agents are available"""
151
+ if not orchestrator:
152
+ return {"agent1": False, "agent2": False, "orchestrator": False}
153
+
154
+ try:
155
+ health_status = await orchestrator.check_agents_health()
156
+ health_status["orchestrator"] = True
157
+ return health_status
158
+ except Exception as e:
159
+ logger.error(f"Error checking agent health: {e}")
160
+ return {"agent1": False, "agent2": False, "orchestrator": False}
161
+
162
+ def get_a2a_system_status():
163
+ """Get A2A system status for display"""
164
+ if not A2A_AVAILABLE:
165
+ return "**πŸ”§ A2A System Status:**\n\n❌ A2A not available\n⚠️ Install google-a2a to enable A2A functionality"
166
+
167
+ try:
168
+ health_status = asyncio.run(check_a2a_agents())
169
+
170
+ status_text = "**πŸ”§ A2A System Status:**\n\n"
171
+ status_text += f"{'βœ…' if health_status.get('orchestrator', False) else '❌'} A2A Orchestrator\n"
172
+ status_text += f"{'βœ…' if health_status.get('agent1', False) else '❌'} Agent1 (Image Generator)\n"
173
+ status_text += f"{'βœ…' if health_status.get('agent2', False) else '❌'} Agent2 (Marketing Reviewer)\n"
174
+
175
+ all_healthy = all(health_status.values())
176
+ if all_healthy:
177
+ status_text += "\nπŸŽ‰ All A2A agents are running!"
178
+ else:
179
+ status_text += "\n⚠️ Some A2A agents are not responding."
180
+ status_text += "\nRun: `python a2a_servers.py` to start agents"
181
+
182
+ return status_text
183
+
184
+ except Exception as e:
185
+ return f"**πŸ”§ A2A System Status:**\n\n❌ Error checking status: {str(e)}"
186
+
187
+ # Define suggested prompts (same as before)
188
+ SUGGESTED_PROMPTS = {
189
+ "Modern office team collaboration": ("A modern office space with diverse professionals collaborating around a sleek conference table, natural lighting, professional attire, English signage visible", "realistic"),
190
+ "Executive boardroom meeting": ("Professional executive boardroom with polished conference table, city skyline view, business documents, English presentations on screens", "realistic"),
191
+ "Customer service excellence": ("Professional customer service representative with headset in modern call center, English signage, clean corporate environment", "realistic"),
192
+ "Product showcase display": ("Clean product showcase on white background with professional lighting, English product labels, minimalist marketing aesthetic", "realistic"),
193
+ "Creative workspace design": ("Creative workspace with colorful design elements, inspirational English quotes on walls, modern furniture, artistic marketing materials", "artistic"),
194
+ "Brand presentation setup": ("Professional brand presentation setup with English branded materials, corporate colors, marketing displays, conference room setting", "realistic")
195
+ }
196
+
197
+ # Create Gradio interface
198
+ with gr.Blocks(title="A2A Marketing Image Generator", theme=gr.themes.Soft()) as demo:
199
+ gr.Markdown("""
200
+ # 🎨 A2A Marketing Image Generator
201
+ ### Professional AI image generation with proper A2A agent architecture
202
+
203
+ **Agent1** (MCP-Imagen3) ↔ **A2A** ↔ **Agent2** (Marketing Reviewer) ↔ **A2A** ↔ **Orchestrator**
204
+ """)
205
+
206
+ with gr.Row():
207
+ with gr.Column(scale=1):
208
+ gr.Markdown("### βš™οΈ Configuration")
209
+
210
+ # Main inputs
211
+ prompt = gr.Textbox(
212
+ label="Describe your marketing image",
213
+ placeholder="e.g., A modern office space with natural lighting, featuring diverse professionals collaborating around a sleek conference table",
214
+ lines=4,
215
+ info="Be specific about the scene, style, mood, and any marketing elements you want to include"
216
+ )
217
+
218
+ style = gr.Dropdown(
219
+ choices=["realistic", "artistic", "cartoon", "photographic", "illustration"],
220
+ value="realistic",
221
+ label="Art Style",
222
+ info="Choose the artistic style for your generated image"
223
+ )
224
+
225
+ review_guidelines = gr.Textbox(
226
+ label="πŸ” Marketing Review Guidelines (Optional)",
227
+ placeholder="e.g., All text must be in English only, focus on professional appearance, ensure brand colors are prominent, check accessibility compliance, verify readability",
228
+ lines=3,
229
+ info="Provide specific marketing guidelines for the Marketing Reviewer to evaluate against your brand standards"
230
+ )
231
+
232
+ # Advanced settings
233
+ with gr.Accordion("πŸ”§ Advanced Settings", open=False):
234
+ max_retries = gr.Slider(
235
+ minimum=1,
236
+ maximum=5,
237
+ value=3,
238
+ step=1,
239
+ label="Max Retries",
240
+ info="Maximum number of retry attempts if generation fails"
241
+ )
242
+
243
+ review_threshold = gr.Slider(
244
+ minimum=0.0,
245
+ maximum=1.0,
246
+ value=0.8,
247
+ step=0.1,
248
+ label="Quality Threshold",
249
+ info="Minimum quality score required for auto-approval"
250
+ )
251
+
252
+ # Generate button
253
+ generate_btn = gr.Button("πŸš€ Generate with A2A Architecture", variant="primary", size="lg")
254
+
255
+ # Status
256
+ gr.Markdown("πŸ” **Mode**: A2A Agent-to-Agent Communication")
257
+
258
+ # System status
259
+ with gr.Accordion("πŸ“Š A2A System Status", open=False):
260
+ status_display = gr.Markdown(get_a2a_system_status())
261
+ refresh_status_btn = gr.Button("πŸ”„ Refresh A2A Status", size="sm")
262
+
263
+ with gr.Column(scale=2):
264
+ # Results display
265
+ gr.Markdown("### πŸ–ΌοΈ Generated Image & A2A Review")
266
+
267
+ image_output = gr.Image(
268
+ label="Generated Marketing Image",
269
+ type="pil",
270
+ height=400,
271
+ show_download_button=True
272
+ )
273
+
274
+ review_output = gr.Markdown(
275
+ value="Click **Generate with A2A Architecture** to create your marketing image using agent-to-agent communication",
276
+ label="A2A Review Results"
277
+ )
278
+
279
+ # Suggested prompts section
280
+ gr.Markdown("---")
281
+ gr.Markdown("### πŸ’‘ Suggested Marketing Prompts")
282
+
283
+ with gr.Row():
284
+ with gr.Column():
285
+ gr.Markdown("**🏒 Professional/Corporate**")
286
+ for prompt_name in ["Modern office team collaboration", "Executive boardroom meeting", "Customer service excellence"]:
287
+ suggested_prompt, suggested_style = SUGGESTED_PROMPTS[prompt_name]
288
+ btn = gr.Button(prompt_name, size="sm")
289
+ btn.click(
290
+ fn=lambda p=suggested_prompt, s=suggested_style: (p, s),
291
+ outputs=[prompt, style]
292
+ )
293
+
294
+ with gr.Column():
295
+ gr.Markdown("**🎨 Creative/Marketing**")
296
+ for prompt_name in ["Product showcase display", "Creative workspace design", "Brand presentation setup"]:
297
+ suggested_prompt, suggested_style = SUGGESTED_PROMPTS[prompt_name]
298
+ btn = gr.Button(prompt_name, size="sm")
299
+ btn.click(
300
+ fn=lambda p=suggested_prompt, s=suggested_style: (p, s),
301
+ outputs=[prompt, style]
302
+ )
303
+
304
+ # Event handlers
305
+ generate_btn.click(
306
+ fn=generate_marketing_image_a2a,
307
+ inputs=[prompt, style, max_retries, review_threshold, review_guidelines],
308
+ outputs=[image_output, review_output],
309
+ show_progress=True
310
+ )
311
+
312
+ refresh_status_btn.click(
313
+ fn=get_a2a_system_status,
314
+ outputs=status_display
315
+ )
316
+
317
+ # Footer
318
+ gr.Markdown("""
319
+ ---
320
+ <div style='text-align: center; color: #666; font-size: 0.9rem;'>
321
+ <p>🎨 A2A Marketing Image Generator | Proper Agent-to-Agent Architecture</p>
322
+ <p>Agent1 (MCP-Imagen3) + Agent2 (Reviewer) + A2A Orchestrator + Gradio Interface</p>
323
+ <p>Start agents with: <code>python a2a_servers.py</code></p>
324
+ </div>
325
+ """)
326
+
327
+ if __name__ == "__main__":
328
+ logger.info("πŸš€ Starting A2A Marketing Image Generator")
329
+ logger.info(f"πŸ€– A2A Available: {'βœ… Yes' if A2A_AVAILABLE else '❌ No'}")
330
+
331
+ if A2A_AVAILABLE:
332
+ logger.info("πŸ’‘ Using proper A2A agent-to-agent communication")
333
+ logger.info("πŸ”— Architecture: Gradio β†’ Orchestrator β†’ Agent1 (MCP-Imagen3) β†’ Agent2 (Reviewer)")
334
+ logger.info("πŸ“‹ Make sure to start agents: python a2a_servers.py")
335
+ else:
336
+ logger.warning("πŸ’‘ A2A not available - install google-a2a for full functionality")
337
+
338
+ demo.launch()