Noo88ear commited on
Commit
d9d9089
Β·
verified Β·
1 Parent(s): 3c21d4d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +671 -725
app.py CHANGED
@@ -1,25 +1,24 @@
1
  """
2
- Marketing Image Generator with Agent Review - Complete Gradio App
3
 
4
- Integrated single-file application that includes:
5
- 1. Image Generator Agent (using Google Imagen)
6
- 2. Image Reviewer Agent (using Google Gemini Vision)
7
- 3. Gradio UI for Hugging Face deployment
8
-
9
- This combines the functionality of the entire marketing image generation system
10
- into one deployable file for Hugging Face Spaces.
11
  """
12
 
13
  import gradio as gr
14
- import os
 
 
15
  import base64
 
16
  import io
17
- import time
 
18
  import re
19
  import logging
20
  import asyncio
 
21
  from typing import Dict, Any, List, Optional
22
- from PIL import Image
23
  import google.generativeai as genai
24
  from google import genai as genai_sdk
25
 
@@ -27,789 +26,736 @@ from google import genai as genai_sdk
27
  logging.basicConfig(level=logging.INFO)
28
  logger = logging.getLogger(__name__)
29
 
30
- # Configuration
31
- MAX_IMAGE_SIZE = 1024
32
- DEFAULT_QUALITY_THRESHOLD = 0.8
33
-
34
- # Initialize Google API with multiple authentication methods
35
- def setup_google_auth():
36
- """Setup Google authentication with multiple fallback options"""
37
-
38
- # Method 1: Try service account JSON (for Google Cloud APIs)
39
- gcp_service_account = os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON")
40
- if gcp_service_account:
41
- try:
42
- import json
43
- from google.oauth2 import service_account
44
- import google.auth
45
-
46
- # Parse the service account JSON
47
- service_account_info = json.loads(gcp_service_account)
48
- credentials = service_account.Credentials.from_service_account_info(service_account_info)
49
-
50
- # Set up for Google Cloud APIs
51
- os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'temp_service_account.json'
52
- with open('temp_service_account.json', 'w') as f:
53
- json.dump(service_account_info, f)
54
-
55
- logger.info("Google Cloud service account configured successfully")
56
- return "service_account"
57
-
58
- except Exception as e:
59
- logger.warning(f"Failed to setup service account: {e}")
60
-
61
- # Method 2: Try API keys (for Google AI Studio)
62
- api_keys = [
63
- os.getenv("GOOGLE_API_KEY"),
64
- os.getenv("GOOGLE_AI_STUDIO_API_KEY"),
65
- os.getenv("GCP_KEY_1"),
66
- os.getenv("GCP_KEY_2"),
67
- os.getenv("GCP_KEY_3")
68
- ]
69
-
70
- google_api_key = next((key for key in api_keys if key), None)
71
- if google_api_key:
72
- try:
73
- genai.configure(api_key=google_api_key)
74
- logger.info("Google AI Studio API key configured successfully")
75
- return google_api_key
76
- except Exception as e:
77
- logger.warning(f"Failed to configure API key: {e}")
78
-
79
- logger.warning("No Google authentication found - using fallback mode")
80
- return None
81
-
82
- # Setup authentication
83
- GOOGLE_AUTH = setup_google_auth()
84
 
85
- # ====== IMAGE GENERATOR AGENT ======
 
86
 
87
- class ImageGeneratorAgent:
88
- """Agent responsible for generating marketing images using Google Imagen"""
89
-
90
- def __init__(self):
91
- self.name = "image_generator_agent"
92
-
93
- async def enhance_prompt(self, prompt: str, style: str) -> str:
94
- """Enhance user prompt for better image generation"""
95
- if not GOOGLE_AUTH:
96
- # Basic enhancement without AI
97
- style_enhancers = {
98
- "realistic": "photorealistic, high detail, professional photography, marketing quality",
99
- "artistic": "artistic masterpiece, creative composition, marketing appeal",
100
- "cartoon": "cartoon style, vibrant colors, playful, marketing friendly",
101
- "illustration": "professional illustration, clean design, marketing material",
102
- "photographic": "professional photograph, high quality, studio lighting, marketing shot"
103
- }
104
- enhancer = style_enhancers.get(style, "high quality, professional")
105
- return f"{prompt}, {enhancer}, 4K resolution, sharp focus"
106
 
107
- try:
108
- enhancement_prompt = f"""
109
- You are an expert prompt engineer for AI image generation. Enhance this marketing image prompt for optimal results with Google Imagen.
 
 
 
 
 
 
 
110
 
111
- Original prompt: "{prompt}"
112
- Desired style: "{style}"
 
 
 
 
 
113
 
114
- Create an enhanced version that:
115
- 1. Maintains the core marketing intent
116
- 2. Adds specific technical details for image quality
117
- 3. Includes appropriate style descriptors for "{style}" style
118
- 4. Adds professional marketing composition guidance
119
- 5. Keeps the enhanced prompt under 150 words
120
 
121
- Return only the enhanced prompt without explanation.
122
- """
123
-
124
- model = genai.GenerativeModel('gemini-2.0-flash-exp')
125
- response = model.generate_content(enhancement_prompt)
126
- enhanced = response.text.strip()
127
-
128
- logger.info(f"Enhanced prompt: {enhanced[:100]}...")
129
- return enhanced
130
-
131
- except Exception as e:
132
- logger.warning(f"Failed to enhance prompt with AI: {e}")
133
- style_enhancers = {
134
- "realistic": "photorealistic, high detail, professional photography, marketing quality",
135
- "artistic": "artistic masterpiece, creative composition, marketing appeal",
136
- "cartoon": "cartoon style, vibrant colors, playful, marketing friendly",
137
- "illustration": "professional illustration, clean design, marketing material",
138
- "photographic": "professional photograph, high quality, studio lighting"
139
- }
140
- enhancer = style_enhancers.get(style, "high quality, professional")
141
- return f"{prompt}, {enhancer}, 4K resolution, sharp focus"
142
-
143
- async def generate_image(self, prompt: str, style: str = "realistic") -> Dict[str, Any]:
144
- """Generate image using Google Imagen"""
145
- try:
146
- # Enhance the prompt first
147
- enhanced_prompt = await self.enhance_prompt(prompt, style)
148
-
149
- # Try Google Imagen API
150
- if GOOGLE_AUTH:
151
- image_data = await self._generate_with_imagen(enhanced_prompt)
152
- if image_data:
153
- return {
154
- "success": True,
155
- "image_data": image_data,
156
- "enhanced_prompt": enhanced_prompt,
157
- "method": "Google Imagen"
158
- }
159
-
160
- # Fallback to placeholder for demo
161
- return await self._generate_fallback(enhanced_prompt, style)
162
-
163
- except Exception as e:
164
- logger.error(f"Image generation failed: {e}")
165
- return {
166
- "success": False,
167
- "error": str(e),
168
- "enhanced_prompt": prompt
169
- }
170
-
171
- async def _generate_with_imagen(self, enhanced_prompt: str) -> Optional[str]:
172
- """Generate image using Google Imagen API"""
173
  try:
174
- # Handle different authentication methods
175
- if GOOGLE_AUTH == "service_account":
176
- # Use service account authentication
177
- client = genai_sdk.Client() # Will use GOOGLE_APPLICATION_CREDENTIALS
178
- else:
179
- # Use API key authentication
180
- client = genai_sdk.Client(api_key=GOOGLE_AUTH)
181
-
182
- result = client.models.generate_images(
183
- model="imagen-3.0-generate-002",
184
- prompt=enhanced_prompt,
185
- config={
186
- "number_of_images": 1,
187
- "output_mime_type": "image/png"
188
- }
189
- )
190
-
191
- if result and hasattr(result, 'generated_images') and len(result.generated_images) > 0:
192
- generated_image = result.generated_images[0]
193
-
194
- if hasattr(generated_image, 'image') and hasattr(generated_image.image, 'image_bytes'):
195
- image_bytes = generated_image.image.image_bytes
196
- base64_image = base64.b64encode(image_bytes).decode('utf-8')
197
- return f"data:image/png;base64,{base64_image}"
198
-
199
- return None
 
 
 
 
 
 
 
 
 
 
 
200
 
201
  except Exception as e:
202
- logger.warning(f"Imagen API failed: {e}")
203
- return None
204
-
205
- async def _generate_fallback(self, enhanced_prompt: str, style: str) -> Dict[str, Any]:
206
- """Generate fallback placeholder image"""
207
- try:
208
- # Create a simple colored image based on prompt
209
- import hashlib
210
- prompt_hash = int(hashlib.md5(enhanced_prompt.encode()).hexdigest()[:8], 16)
211
-
212
- # Generate deterministic but varied colors
213
- colors = [
214
- (70, 130, 180), # Steel Blue
215
- (60, 179, 113), # Medium Sea Green
216
- (255, 140, 0), # Dark Orange
217
- (106, 90, 205), # Slate Blue
218
- (220, 20, 60), # Crimson
219
- (255, 215, 0), # Gold
220
- (147, 112, 219), # Medium Purple
221
- (32, 178, 170) # Light Sea Green
222
- ]
223
-
224
- color = colors[prompt_hash % len(colors)]
225
- img = Image.new('RGB', (1024, 1024), color)
226
-
227
- # Add some simple text overlay
228
  try:
229
- from PIL import ImageDraw, ImageFont
230
- draw = ImageDraw.Draw(img)
231
-
232
- # Try to use a font, fallback to default
233
- try:
234
- font = ImageFont.truetype("/System/Library/Fonts/Arial.ttf", 48)
235
- except:
236
- font = ImageFont.load_default()
237
-
238
- # Add text
239
- text = f"Marketing Image\n{style.title()} Style"
240
- draw.multiline_text((50, 450), text, fill=(255, 255, 255), font=font, align="center")
241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  except Exception as e:
243
- logger.warning(f"Could not add text overlay: {e}")
244
-
245
- # Convert to base64
246
- img_buffer = io.BytesIO()
247
- img.save(img_buffer, format='PNG')
248
- img_buffer.seek(0)
249
- base64_image = base64.b64encode(img_buffer.read()).decode('utf-8')
250
-
251
- return {
252
- "success": True,
253
- "image_data": f"data:image/png;base64,{base64_image}",
254
- "enhanced_prompt": enhanced_prompt,
255
- "method": "Fallback Demo"
256
- }
257
-
258
- except Exception as e:
259
- logger.error(f"Fallback generation failed: {e}")
260
- return {"success": False, "error": str(e)}
261
-
262
- # ====== IMAGE REVIEWER AGENT ======
263
-
264
- class ImageReviewerAgent:
265
- """Agent responsible for reviewing generated images for quality and relevance"""
266
-
267
- def __init__(self):
268
- self.name = "image_reviewer_agent"
269
-
270
- def parse_prompt_elements(self, prompt: str) -> Dict[str, List[str]]:
271
- """Parse prompt to extract key elements for validation"""
272
- prompt_lower = prompt.lower()
273
-
274
- # Define patterns for different element types
275
- patterns = {
276
- "subjects": [
277
- r'\b(person|man|woman|child|people|human|figure|team|group)\b',
278
- r'\b(product|device|phone|laptop|car|building|office|space)\b',
279
- r'\b(logo|brand|company|business|service)\b'
280
- ],
281
- "style": [
282
- r'\b(realistic|photorealistic|photograph|photo)\b',
283
- r'\b(artistic|painting|drawing|illustration)\b',
284
- r'\b(modern|contemporary|minimalist|professional)\b',
285
- r'\b(cartoon|animated|3d|rendered)\b'
286
- ],
287
- "colors": [
288
- r'\b(blue|red|green|yellow|orange|purple|pink|black|white|gray|grey)\b',
289
- r'\b(bright|dark|light|vibrant|muted|pastel|neon)\b',
290
- r'\b(colorful|monochrome|gradient)\b'
291
- ],
292
- "settings": [
293
- r'\b(office|studio|outdoor|indoor|background|scene)\b',
294
- r'\b(professional|corporate|casual|formal)\b',
295
- r'\b(lighting|natural light|studio lighting)\b'
296
- ],
297
- "marketing": [
298
- r'\b(marketing|advertisement|promotional|campaign|brand)\b',
299
- r'\b(professional|business|corporate|commercial)\b',
300
- r'\b(hero|banner|social media|web|digital)\b'
301
- ]
302
- }
303
 
304
- def extract_matches(patterns_list: List[str], text: str) -> List[str]:
305
- matches = set()
306
- for pattern in patterns_list:
307
- found = re.findall(pattern, text)
308
- matches.update(found)
309
- return list(matches)
310
 
311
  return {
312
- key: extract_matches(pattern_list, prompt_lower)
313
- for key, pattern_list in patterns.items()
 
 
 
 
 
 
 
 
314
  }
315
-
316
- async def review_image(self, image_data: str, original_prompt: str, enhanced_prompt: str) -> Dict[str, Any]:
317
- """Review generated image for quality and relevance"""
318
- try:
319
- logger.info("Starting image review analysis")
320
-
321
- # Parse prompt elements
322
- prompt_elements = self.parse_prompt_elements(original_prompt)
323
-
324
- # Try AI-powered review if API available
325
- if GOOGLE_AUTH and image_data.startswith("data:image"):
326
- ai_review = await self._ai_powered_review(image_data, original_prompt, enhanced_prompt, prompt_elements)
327
- if ai_review:
328
- return ai_review
329
-
330
- # Fallback to prompt-based analysis
331
- return await self._prompt_based_review(original_prompt, enhanced_prompt, prompt_elements)
332
-
333
- except Exception as e:
334
- logger.error(f"Image review failed: {e}")
335
- return self._fallback_review(original_prompt)
336
-
337
- async def _ai_powered_review(self, image_data: str, original_prompt: str, enhanced_prompt: str, prompt_elements: Dict) -> Optional[Dict[str, Any]]:
338
- """Review image using Google Gemini Vision"""
339
- try:
340
- # Extract image from data URL
341
- if not image_data.startswith("data:image"):
342
- return None
343
-
344
- image_b64 = image_data.split(',')[1]
345
- image_bytes = base64.b64decode(image_b64)
346
- image = Image.open(io.BytesIO(image_bytes))
347
-
348
- # Create detailed analysis prompt
349
- analysis_prompt = f"""
350
- Analyze this marketing image that was generated from: "{original_prompt}"
351
- Enhanced prompt used: "{enhanced_prompt}"
352
-
353
- Key elements to verify:
354
- - Subjects: {', '.join(prompt_elements.get('subjects', []))}
355
- - Style: {', '.join(prompt_elements.get('style', []))}
356
- - Colors: {', '.join(prompt_elements.get('colors', []))}
357
- - Setting: {', '.join(prompt_elements.get('settings', []))}
358
- - Marketing elements: {', '.join(prompt_elements.get('marketing', []))}
359
-
360
- Rate the image on:
361
- 1. Technical Quality (0.0-1.0): clarity, composition, lighting, resolution
362
- 2. Prompt Relevance (0.0-1.0): how well it matches the original request
363
- 3. Marketing Effectiveness (0.0-1.0): professional appeal, brand suitability
364
-
365
- Provide response in this format:
366
- QUALITY_SCORE: [0.0-1.0]
367
- RELEVANCE_SCORE: [0.0-1.0]
368
- MARKETING_SCORE: [0.0-1.0]
369
-
370
- STRENGTHS: [List 2-3 strong points]
371
- ISSUES: [List 2-3 improvement areas]
372
- RECOMMENDATIONS: [List 2-3 specific suggestions]
373
-
374
- OVERALL_ASSESSMENT: [Brief summary of the image's marketing potential]
375
- """
376
-
377
- model = genai.GenerativeModel('gemini-2.0-flash-exp')
378
- response = model.generate_content([analysis_prompt, image])
379
- analysis_text = response.text
380
-
381
- return self._parse_ai_review(analysis_text, original_prompt)
382
-
383
- except Exception as e:
384
- logger.warning(f"AI-powered review failed: {e}")
385
- return None
386
-
387
- def _parse_ai_review(self, analysis_text: str, original_prompt: str) -> Dict[str, Any]:
388
- """Parse AI review response into structured feedback"""
389
-
390
- def extract_score(text: str, score_type: str) -> float:
391
- pattern = rf"{score_type}_SCORE:\s*([\d.]+)"
392
- match = re.search(pattern, text, re.IGNORECASE)
393
- if match:
394
- try:
395
- return min(1.0, max(0.0, float(match.group(1))))
396
- except ValueError:
397
- pass
398
- return 0.7
399
-
400
- def extract_list_section(text: str, section: str) -> List[str]:
401
- pattern = rf"{section}:\s*(.+?)(?=\n[A-Z_]+:|$)"
402
- match = re.search(pattern, text, re.IGNORECASE | re.DOTALL)
403
- if match:
404
- items_text = match.group(1).strip()
405
- items = [item.strip().strip('-β€’*').strip()
406
- for item in re.split(r'\n|,', items_text)
407
- if item.strip() and len(item.strip()) > 3]
408
- return items[:3] # Limit to 3 items
409
- return []
410
 
411
- try:
412
- # Extract scores
413
- quality_score = extract_score(analysis_text, "QUALITY")
414
- relevance_score = extract_score(analysis_text, "RELEVANCE")
415
- marketing_score = extract_score(analysis_text, "MARKETING")
416
-
417
- # Extract feedback sections
418
- strengths = extract_list_section(analysis_text, "STRENGTHS")
419
- issues = extract_list_section(analysis_text, "ISSUES")
420
- recommendations = extract_list_section(analysis_text, "RECOMMENDATIONS")
421
-
422
- # Extract overall assessment
423
- assessment_match = re.search(r"OVERALL_ASSESSMENT:\s*(.+?)(?=\n[A-Z_]+:|$)",
424
- analysis_text, re.IGNORECASE | re.DOTALL)
425
- overall_assessment = assessment_match.group(1).strip() if assessment_match else "Good marketing image potential"
426
-
427
- # Calculate weighted overall score (emphasize marketing effectiveness)
428
- overall_score = (quality_score * 0.3 + relevance_score * 0.4 + marketing_score * 0.3)
429
-
430
- # Determine pass/fail
431
- passed = overall_score >= 0.7 and relevance_score >= 0.6
432
-
433
- return {
434
- "success": True,
435
- "overall_score": round(overall_score, 2),
436
- "quality_score": round(quality_score, 2),
437
- "relevance_score": round(relevance_score, 2),
438
- "marketing_score": round(marketing_score, 2),
439
- "passed": passed,
440
- "strengths": strengths,
441
- "issues": issues,
442
- "recommendations": recommendations,
443
- "overall_assessment": overall_assessment,
444
- "review_method": "AI-Powered (Gemini Vision)"
445
- }
446
-
447
- except Exception as e:
448
- logger.error(f"Error parsing AI review: {e}")
449
- return self._fallback_review(original_prompt)
450
 
451
- async def _prompt_based_review(self, original_prompt: str, enhanced_prompt: str, prompt_elements: Dict) -> Dict[str, Any]:
452
- """Review based on prompt analysis when AI review isn't available"""
453
-
454
- issues = []
455
- recommendations = []
456
- strengths = []
457
-
458
- # Analyze prompt completeness
459
- total_elements = sum(len(elements) for elements in prompt_elements.values())
460
-
461
- # Base scoring
462
- if total_elements >= 8:
463
- base_score = 0.8
464
- strengths.append("Comprehensive prompt with detailed specifications")
465
- elif total_elements >= 5:
466
- base_score = 0.7
467
- strengths.append("Good prompt detail level")
468
- elif total_elements >= 3:
469
- base_score = 0.6
470
- issues.append("Prompt could use more specific details")
471
- else:
472
- base_score = 0.5
473
- issues.append("Prompt lacks sufficient detail for optimal results")
474
- recommendations.append("Add more specific details about subjects, style, and setting")
475
-
476
- # Check for marketing-specific elements
477
- marketing_elements = prompt_elements.get('marketing', [])
478
- if marketing_elements:
479
- base_score += 0.1
480
- strengths.append("Contains marketing-focused language")
481
- else:
482
- recommendations.append("Consider adding marketing-specific context")
483
 
484
- # Check for style specification
485
- style_elements = prompt_elements.get('style', [])
486
- if style_elements:
487
- strengths.append(f"Clear style direction: {', '.join(style_elements[:2])}")
488
- else:
489
- issues.append("No clear artistic style specified")
490
- recommendations.append("Specify desired artistic style (realistic, artistic, etc.)")
491
 
492
- # Check for subject clarity
493
- subject_elements = prompt_elements.get('subjects', [])
494
- if subject_elements:
495
- strengths.append(f"Clear subjects identified: {', '.join(subject_elements[:2])}")
496
- else:
497
- issues.append("Main subjects not clearly specified")
498
- recommendations.append("Clearly define what should be the main focus")
499
 
500
- # Calculate scores
501
- quality_score = min(1.0, base_score + 0.1) # Slight boost for quality
502
- relevance_score = base_score # Based on prompt completeness
503
- marketing_score = base_score + (0.1 if marketing_elements else -0.1)
504
 
505
- overall_score = (quality_score * 0.3 + relevance_score * 0.4 + marketing_score * 0.3)
506
- passed = overall_score >= 0.6
 
 
507
 
508
- return {
509
- "success": True,
510
- "overall_score": round(overall_score, 2),
511
- "quality_score": round(quality_score, 2),
512
- "relevance_score": round(relevance_score, 2),
513
- "marketing_score": round(marketing_score, 2),
514
- "passed": passed,
515
- "strengths": strengths[:3],
516
- "issues": issues[:3],
517
- "recommendations": recommendations[:3],
518
- "overall_assessment": f"Prompt-based analysis shows {'good' if passed else 'moderate'} marketing image potential",
519
- "review_method": "Prompt Analysis"
520
- }
 
 
 
521
 
522
- def _fallback_review(self, original_prompt: str) -> Dict[str, Any]:
523
- """Fallback review when all else fails"""
524
- word_count = len(original_prompt.split())
525
- base_score = min(0.8, max(0.4, 0.4 + (word_count * 0.02)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
 
527
- return {
528
- "success": True,
529
- "overall_score": base_score,
530
- "quality_score": base_score,
531
- "relevance_score": base_score,
532
- "marketing_score": base_score,
533
- "passed": base_score >= 0.6,
534
- "strengths": ["Prompt provided for image generation"],
535
- "issues": ["Unable to perform detailed analysis"],
536
- "recommendations": ["Consider regenerating with more detailed prompt"],
537
- "overall_assessment": "Basic review completed",
538
- "review_method": "Fallback"
539
- }
540
 
541
- # ====== MAIN APPLICATION WORKFLOW ======
542
-
543
- # Initialize agents
544
- generator_agent = ImageGeneratorAgent()
545
- reviewer_agent = ImageReviewerAgent()
546
-
547
- def generate_marketing_image_with_review(
548
- prompt: str,
549
- style: str = "realistic",
550
- quality_threshold: float = 0.8,
551
- max_iterations: int = 2,
552
- progress=gr.Progress(track_tqdm=True)
553
- ):
554
- """
555
- Main workflow: Generate image and review it
556
- """
557
-
558
- if not prompt.strip():
559
- return None, "Please enter a prompt to generate an image.", "❌ No Prompt", ""
560
-
561
  try:
562
- progress(0.1, desc="Initializing generation workflow...")
563
 
564
- # Step 1: Generate image
565
- progress(0.3, desc="Generating marketing image...")
566
- generation_result = asyncio.run(generator_agent.generate_image(prompt, style))
567
 
568
- if not generation_result.get("success"):
569
- error_msg = f"Image generation failed: {generation_result.get('error', 'Unknown error')}"
570
- return None, error_msg, "❌ Generation Failed", ""
 
571
 
572
- image_data = generation_result["image_data"]
573
- enhanced_prompt = generation_result["enhanced_prompt"]
 
 
574
 
575
- # Convert base64 to PIL Image for display
576
- if image_data.startswith("data:image"):
577
- image_b64 = image_data.split(',')[1]
578
- image_bytes = base64.b64decode(image_b64)
579
- display_image = Image.open(io.BytesIO(image_bytes))
580
- else:
581
- display_image = None
582
 
583
- progress(0.6, desc="Reviewing image quality...")
 
584
 
585
- # Step 2: Review the generated image
586
- review_result = asyncio.run(reviewer_agent.review_image(image_data, prompt, enhanced_prompt))
 
 
587
 
588
- progress(0.9, desc="Finalizing results...")
 
 
 
 
 
 
589
 
590
- # Step 3: Format results
591
- if review_result.get("success"):
592
- # Build quality information display
593
- quality_info = f"""
594
- ## 🎯 Review Results
595
 
596
- **Overall Score:** {review_result['overall_score']:.2f}/1.0
597
- **Status:** {'βœ… Approved' if review_result['passed'] else '⚠️ Needs Improvement'}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
598
 
599
- ### Detailed Scores
600
- - **Quality:** {review_result['quality_score']:.2f}/1.0
601
- - **Relevance:** {review_result['relevance_score']:.2f}/1.0
602
- - **Marketing Appeal:** {review_result['marketing_score']:.2f}/1.0
 
 
 
 
603
 
604
- ### πŸ’ͺ Strengths
605
- {chr(10).join(f"β€’ {strength}" for strength in review_result.get('strengths', []))}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
606
 
607
- ### ⚠️ Areas for Improvement
608
- {chr(10).join(f"β€’ {issue}" for issue in review_result.get('issues', []))}
 
 
 
 
 
609
 
610
- ### πŸ’‘ Recommendations
611
- {chr(10).join(f"β€’ {rec}" for rec in review_result.get('recommendations', []))}
 
 
 
 
 
 
 
612
 
613
- ### πŸ“ Assessment
614
- {review_result.get('overall_assessment', 'Review completed')}
 
 
 
 
615
 
616
- ---
617
- *Review Method: {review_result.get('review_method', 'Standard')}*
618
- *Enhanced Prompt: {enhanced_prompt[:100]}...*
619
- """
620
-
621
- review_status = "βœ… Approved" if review_result['passed'] else "⚠️ Needs Review"
622
-
623
- # Add generation method info
624
- debug_info = f"""
625
- **Generation Details:**
626
- - Method: {generation_result.get('method', 'Unknown')}
627
- - Original Prompt: {prompt}
628
- - Enhanced Prompt: {enhanced_prompt}
629
- - Style: {style}
630
- - API Status: {'βœ… Connected' if GOOGLE_AUTH else '⚠️ Demo Mode'}
631
- """
632
-
633
- else:
634
- quality_info = f"Review failed: {review_result.get('error', 'Unknown error')}"
635
- review_status = "❌ Review Failed"
636
- debug_info = f"Generation Method: {generation_result.get('method', 'Unknown')}"
637
-
638
- progress(1.0, desc="Complete!")
639
-
640
- return display_image, quality_info, review_status, debug_info
641
-
642
- except Exception as e:
643
- logger.error(f"Workflow error: {str(e)}")
644
- error_msg = f"Workflow failed: {str(e)}"
645
- return None, error_msg, "❌ Error", f"Error details: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
646
 
647
- # ====== GRADIO INTERFACE ======
 
 
 
 
 
648
 
649
- def create_gradio_interface():
650
- """Create the complete Gradio interface"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
 
652
- custom_css = """
653
- .gradio-container {
654
- max-width: 1400px !important;
655
- margin: auto !important;
656
- }
657
- .header-text {
658
- text-align: center;
659
- color: #1f77b4;
660
- margin-bottom: 2rem;
661
- }
662
- .quality-info {
663
- background-color: #f8f9fa;
664
- padding: 1rem;
665
- border-radius: 0.5rem;
666
- border-left: 4px solid #1f77b4;
667
- font-family: monospace;
668
- }
669
- .status-approved { color: #28a745; font-weight: bold; }
670
- .status-warning { color: #ffc107; font-weight: bold; }
671
- .status-error { color: #dc3545; font-weight: bold; }
672
- """
673
 
674
- with gr.Blocks(css=custom_css, title="Marketing Image Generator with AI Review") as interface:
675
-
676
- # Header
677
- gr.Markdown("""
678
- # 🎨 Marketing Image Generator with AI Review
679
- ### Professional marketing images with automated quality assurance
680
-
681
- This system combines **Google Imagen** for image generation with **Google Gemini Vision** for intelligent quality review.
682
- Perfect for creating professional marketing materials with AI-powered feedback.
683
- """, elem_classes=["header-text"])
684
-
685
- # API Status indicator
686
- api_status = "🟒 Google AI Connected" if GOOGLE_AUTH else "🟑 Demo Mode (No API Key)"
687
- gr.Markdown(f"**Status:** {api_status}")
688
-
689
- with gr.Row():
690
- with gr.Column(scale=2):
691
- # Input Section
 
 
 
 
 
 
 
 
 
 
692
  gr.Markdown("## πŸ“ Describe Your Marketing Image")
693
 
694
- prompt = gr.Textbox(
695
  label="Marketing Image Description",
696
- placeholder="e.g., A professional team of diverse colleagues collaborating in a modern office space with natural lighting, for a corporate website hero image",
697
  lines=4,
698
- info="Be specific about subjects, setting, style, and intended marketing use"
699
  )
700
 
701
  with gr.Row():
702
- style = gr.Dropdown(
703
- choices=["realistic", "artistic", "cartoon", "illustration", "photographic"],
704
- value="realistic",
705
- label="Art Style",
706
- info="Choose the visual style that fits your brand"
707
- )
 
708
 
709
- quality_threshold = gr.Slider(
710
- minimum=0.0,
711
- maximum=1.0,
712
- value=0.7,
713
- step=0.1,
714
- label="Quality Threshold",
715
- info="Minimum score for approval (0.0 = lenient, 1.0 = strict)"
716
- )
717
 
718
- with gr.Accordion("πŸ”§ Advanced Options", open=False):
719
- max_iterations = gr.Slider(
720
- minimum=1,
721
- maximum=3,
722
- value=2,
723
- step=1,
724
- label="Max Review Iterations",
725
- info="Maximum attempts to improve the image"
726
- )
 
 
 
 
 
 
 
 
 
 
 
727
 
728
  generate_btn = gr.Button(
729
- "πŸš€ Generate & Review Marketing Image",
730
  variant="primary",
 
731
  size="lg"
732
  )
733
-
734
- with gr.Column(scale=3):
735
- # Output Section
736
- gr.Markdown("## πŸ–ΌοΈ Generated Image & Analysis")
737
 
738
- with gr.Row():
739
- with gr.Column(scale=2):
740
- generated_image = gr.Image(
741
- label="Your Marketing Image",
742
- type="pil",
743
- interactive=False,
744
- height=400
745
- )
746
-
747
- with gr.Column(scale=1):
748
- review_status = gr.Textbox(
749
- label="Review Status",
750
- value="⏳ Ready to Generate",
751
- interactive=False,
752
- max_lines=1
753
- )
754
 
755
- quality_info = gr.Markdown(
756
- label="AI Quality Analysis",
757
- value="*Generate an image to see detailed AI quality analysis and recommendations*",
758
- elem_classes=["quality-info"]
759
- )
760
-
761
- # Debug/Technical Info (Collapsible)
762
- with gr.Accordion("πŸ”§ Technical Details", open=False):
763
- debug_info = gr.Markdown(
764
- value="*Technical information will appear here after generation*"
 
 
 
 
 
 
 
 
 
 
 
 
765
  )
766
 
767
- # Examples Section
768
- gr.Markdown("## πŸ’‘ Example Marketing Prompts")
769
-
770
- examples = gr.Examples(
771
- examples=[
772
- ["A diverse team of professionals collaborating around a modern conference table in a bright office space, corporate website hero image", "realistic"],
773
- ["A sleek product showcase featuring a smartphone on a clean white background with dramatic lighting, for e-commerce", "photographic"],
774
- ["A friendly customer service representative wearing a headset, smiling while helping clients in a contemporary office", "realistic"],
775
- ["A minimalist workspace setup with laptop, coffee, and plants, perfect for productivity app marketing", "artistic"],
776
- ["An abstract representation of data flow and connectivity, modern tech company branding", "illustration"],
777
- ["A celebration scene with confetti and happy people, perfect for achievement or success marketing", "realistic"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
778
  ],
779
- inputs=[prompt, style],
780
- label="Click any example to try it out!"
781
- )
782
-
783
- # Connect the workflow
784
- generate_btn.click(
785
- fn=generate_marketing_image_with_review,
786
- inputs=[prompt, style, quality_threshold, max_iterations],
787
- outputs=[generated_image, quality_info, review_status, debug_info],
788
- show_progress=True
789
- )
790
-
791
- # Footer
792
- gr.Markdown("""
793
- ---
794
- <div style='text-align: center; color: #666; font-size: 0.9rem;'>
795
- <p>🎨 <strong>Marketing Image Generator with AI Review</strong></p>
796
- <p>Powered by Google Imagen & Gemini Vision | Built for Professional Marketing Teams</p>
797
- <p><em>Generate β†’ Review β†’ Perfect: Your AI-powered creative workflow</em></p>
798
- </div>
799
- """)
 
 
 
 
800
 
801
- return interface
802
-
803
- # ====== APPLICATION ENTRY POINT ======
804
-
805
- # Create the interface
806
- demo = create_gradio_interface()
 
 
 
 
 
 
 
 
 
 
807
 
 
808
  if __name__ == "__main__":
809
- logger.info("Starting Marketing Image Generator with AI Review")
810
  demo.launch(
811
  server_name="0.0.0.0",
812
  server_port=7860,
813
- share=False,
814
  show_error=True,
815
- )
 
 
1
  """
2
+ Marketing Image Generator with Agent Review - Improved Gradio Version
3
 
4
+ This is an enhanced Gradio app for Hugging Face Spaces deployment with
5
+ better UI/UX design, cleaner layout, and improved functionality.
 
 
 
 
 
6
  """
7
 
8
  import gradio as gr
9
+ import requests
10
+ import json
11
+ import time
12
  import base64
13
+ from PIL import Image, ImageDraw, ImageFont
14
  import io
15
+ import traceback
16
+ import os
17
  import re
18
  import logging
19
  import asyncio
20
+ import hashlib
21
  from typing import Dict, Any, List, Optional
 
22
  import google.generativeai as genai
23
  from google import genai as genai_sdk
24
 
 
26
  logging.basicConfig(level=logging.INFO)
27
  logger = logging.getLogger(__name__)
28
 
29
+ # Configuration for Hugging Face deployment
30
+ GOOGLE_SERVICE_ACCOUNT_JSON = os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON", "")
31
+ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY", "")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ # Initialize Google AI with service account JSON or API key
34
+ google_auth_configured = False
35
 
36
+ if GOOGLE_SERVICE_ACCOUNT_JSON:
37
+ try:
38
+ # Parse the JSON credentials
39
+ credentials_dict = json.loads(GOOGLE_SERVICE_ACCOUNT_JSON)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ # Create credentials from service account info
42
+ from google.oauth2 import service_account
43
+ credentials = service_account.Credentials.from_service_account_info(credentials_dict)
44
+
45
+ # Configure Google AI
46
+ genai.configure(credentials=credentials)
47
+ google_auth_configured = True
48
+ logger.info("βœ… Google Cloud service account configured")
49
+ except Exception as e:
50
+ logger.error(f"❌ Error configuring Google Cloud service account: {str(e)}")
51
 
52
+ if not google_auth_configured and GOOGLE_API_KEY:
53
+ try:
54
+ genai.configure(api_key=GOOGLE_API_KEY)
55
+ google_auth_configured = True
56
+ logger.info("βœ… Google API key configured")
57
+ except Exception as e:
58
+ logger.error(f"❌ Error configuring Google API key: {str(e)}")
59
 
60
+ if not google_auth_configured:
61
+ logger.warning("⚠️ No Google authentication configured - running in demo mode")
 
 
 
 
62
 
63
+ def create_enhanced_placeholder_image(prompt, style, aspect_ratio):
64
+ """Create an enhanced placeholder image with better design"""
65
+ try:
66
+ # Set dimensions based on aspect ratio
67
+ if aspect_ratio == "16:9":
68
+ width, height = 1024, 576
69
+ elif aspect_ratio == "1:1":
70
+ width, height = 1024, 1024
71
+ elif aspect_ratio == "4:3":
72
+ width, height = 1024, 768
73
+ else: # 3:2
74
+ width, height = 1024, 683
75
+
76
+ # Generate deterministic but varied colors based on prompt
77
+ prompt_hash = int(hashlib.md5(prompt.encode()).hexdigest()[:8], 16)
78
+
79
+ # Style-based color schemes
80
+ color_schemes = {
81
+ "Professional": [(45, 55, 72), (74, 85, 104), (113, 128, 150)],
82
+ "Creative": [(236, 72, 153), (168, 85, 247), (59, 130, 246)],
83
+ "Minimalist": [(156, 163, 175), (209, 213, 219), (243, 244, 246)],
84
+ "Bold": [(239, 68, 68), (245, 101, 101), (252, 165, 165)],
85
+ "Elegant": [(91, 33, 182), (124, 58, 237), (167, 139, 250)],
86
+ "Playful": [(34, 197, 94), (74, 222, 128), (134, 239, 172)],
87
+ "Corporate": [(30, 58, 138), (30, 64, 175), (59, 130, 246)],
88
+ "Modern": [(17, 24, 39), (55, 65, 81), (107, 114, 128)]
89
+ }
90
+
91
+ colors = color_schemes.get(style, color_schemes["Professional"])
92
+ base_color = colors[prompt_hash % len(colors)]
93
+
94
+ # Create gradient background
95
+ img = Image.new('RGB', (width, height), base_color)
96
+ draw = ImageDraw.Draw(img)
97
+
98
+ # Add gradient effect
99
+ for i in range(height):
100
+ alpha = i / height
101
+ gradient_color = tuple(int(base_color[j] * (1 - alpha * 0.3)) for j in range(3))
102
+ draw.line([(0, i), (width, i)], fill=gradient_color)
103
+
104
+ # Add geometric elements for visual interest
105
+ overlay_color = tuple(min(255, c + 40) for c in base_color)
106
+
107
+ # Draw some decorative elements
108
+ for i in range(5):
109
+ x = (prompt_hash * (i + 1)) % (width - 100)
110
+ y = (prompt_hash * (i + 2)) % (height - 100)
111
+ size = 20 + (prompt_hash % 50)
112
+ draw.ellipse([x, y, x + size, y + size], fill=overlay_color)
113
+
114
+ # Add text overlay
115
  try:
116
+ # Try to load a system font, fallback to default
117
+ try:
118
+ font_large = ImageFont.truetype("/System/Library/Fonts/Arial.ttf", 48)
119
+ font_medium = ImageFont.truetype("/System/Library/Fonts/Arial.ttf", 24)
120
+ font_small = ImageFont.truetype("/System/Library/Fonts/Arial.ttf", 18)
121
+ except:
122
+ font_large = ImageFont.load_default()
123
+ font_medium = ImageFont.load_default()
124
+ font_small = ImageFont.load_default()
125
+
126
+ # Add main title
127
+ title = f"Marketing Image"
128
+ title_bbox = draw.textbbox((0, 0), title, font=font_large)
129
+ title_width = title_bbox[2] - title_bbox[0]
130
+ title_x = (width - title_width) // 2
131
+ title_y = height // 3
132
+
133
+ # Add semi-transparent background for text
134
+ text_bg_color = (0, 0, 0, 128)
135
+ draw.rectangle([title_x - 20, title_y - 10, title_x + title_width + 20, title_y + 70],
136
+ fill=(0, 0, 0, 80))
137
+
138
+ draw.text((title_x, title_y), title, fill=(255, 255, 255), font=font_large)
139
+
140
+ # Add style info
141
+ style_text = f"Style: {style}"
142
+ style_bbox = draw.textbbox((0, 0), style_text, font=font_medium)
143
+ style_width = style_bbox[2] - style_bbox[0]
144
+ style_x = (width - style_width) // 2
145
+ draw.text((style_x, title_y + 60), style_text, fill=(255, 255, 255), font=font_medium)
146
+
147
+ # Add prompt preview
148
+ prompt_preview = prompt[:50] + "..." if len(prompt) > 50 else prompt
149
+ prompt_bbox = draw.textbbox((0, 0), prompt_preview, font=font_small)
150
+ prompt_width = prompt_bbox[2] - prompt_bbox[0]
151
+ prompt_x = (width - prompt_width) // 2
152
+ draw.text((prompt_x, title_y + 100), prompt_preview, fill=(200, 200, 200), font=font_small)
153
 
154
  except Exception as e:
155
+ logger.warning(f"Could not add text overlay: {e}")
156
+
157
+ return img
158
+
159
+ except Exception as e:
160
+ logger.error(f"Error creating placeholder image: {e}")
161
+ # Fallback to simple colored rectangle
162
+ return Image.new('RGB', (1024, 576), color='#1f77b4')
163
+
164
+ def generate_image_with_review(prompt, style, aspect_ratio, num_images, quality_threshold=0.8):
165
+ """Generate an image with automated review using Google APIs or enhanced placeholder"""
166
+ try:
167
+ logger.info(f"Generating image for prompt: {prompt[:50]}...")
168
+
169
+ # If Google auth is configured, try real API calls
170
+ if google_auth_configured:
 
 
 
 
 
 
 
 
 
 
171
  try:
172
+ # Enhance prompt first
173
+ enhanced_prompt = enhance_prompt_with_ai(prompt, style)
 
 
 
 
 
 
 
 
 
 
174
 
175
+ # Try to generate with Google Imagen
176
+ real_image = generate_with_google_imagen(enhanced_prompt)
177
+ if real_image:
178
+ # Review the real image
179
+ review_result = review_image_with_ai(real_image, prompt, enhanced_prompt)
180
+ return {
181
+ "image": real_image,
182
+ "quality_score": review_result.get("quality_score", 0.85),
183
+ "review_comments": review_result.get("comments", "AI-generated image reviewed successfully"),
184
+ "status": "approved" if review_result.get("quality_score", 0.85) >= quality_threshold else "needs_improvement",
185
+ "prompt": prompt,
186
+ "enhanced_prompt": enhanced_prompt,
187
+ "style": style,
188
+ "aspect_ratio": aspect_ratio,
189
+ "method": "Google Imagen + AI Review",
190
+ "timestamp": time.time()
191
+ }
192
  except Exception as e:
193
+ logger.warning(f"Google API generation failed: {e}")
194
+
195
+ # Fallback to enhanced placeholder
196
+ placeholder_image = create_enhanced_placeholder_image(prompt, style, aspect_ratio)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
+ # Simulate quality analysis based on prompt quality
199
+ quality_score = analyze_prompt_quality(prompt, style)
 
 
 
 
200
 
201
  return {
202
+ "image": placeholder_image,
203
+ "quality_score": quality_score,
204
+ "review_comments": generate_review_comments(prompt, style, quality_score),
205
+ "status": "approved" if quality_score >= quality_threshold else "needs_improvement",
206
+ "prompt": prompt,
207
+ "enhanced_prompt": enhance_prompt_basic(prompt, style),
208
+ "style": style,
209
+ "aspect_ratio": aspect_ratio,
210
+ "method": "Enhanced Demo Mode",
211
+ "timestamp": time.time()
212
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
+ except Exception as e:
215
+ logger.error(f"Error in image generation: {str(e)}")
216
+ return None
217
+
218
+ def enhance_prompt_with_ai(prompt, style):
219
+ """Enhance prompt using AI if available"""
220
+ if not google_auth_configured:
221
+ return enhance_prompt_basic(prompt, style)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
+ try:
224
+ model = genai.GenerativeModel('gemini-2.0-flash-exp')
225
+ enhancement_prompt = f"""
226
+ Enhance this marketing image prompt for optimal results:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
+ Original: "{prompt}"
229
+ Style: "{style}"
 
 
 
 
 
230
 
231
+ Make it more specific for marketing image generation. Add details about:
232
+ - Composition and framing
233
+ - Lighting and mood
234
+ - Professional quality indicators
235
+ - Brand-appropriate elements
 
 
236
 
237
+ Keep it under 150 words. Return only the enhanced prompt.
238
+ """
 
 
239
 
240
+ response = model.generate_content(enhancement_prompt)
241
+ enhanced = response.text.strip()
242
+ logger.info(f"AI-enhanced prompt: {enhanced[:100]}...")
243
+ return enhanced
244
 
245
+ except Exception as e:
246
+ logger.warning(f"AI prompt enhancement failed: {e}")
247
+ return enhance_prompt_basic(prompt, style)
248
+
249
+ def enhance_prompt_basic(prompt, style):
250
+ """Basic prompt enhancement without AI"""
251
+ style_enhancers = {
252
+ "Professional": "professional photography, corporate setting, high quality, clean composition",
253
+ "Creative": "creative composition, artistic flair, innovative design, vibrant colors",
254
+ "Minimalist": "clean minimal design, simple composition, white space, elegant",
255
+ "Bold": "bold colors, strong contrast, dynamic composition, eye-catching",
256
+ "Elegant": "sophisticated, refined, luxury feel, premium quality",
257
+ "Playful": "fun, engaging, colorful, approachable, friendly",
258
+ "Corporate": "business professional, corporate branding, trustworthy, authoritative",
259
+ "Modern": "contemporary design, sleek, cutting-edge, stylish"
260
+ }
261
 
262
+ enhancer = style_enhancers.get(style, "high quality, professional")
263
+ return f"{prompt}, {enhancer}, marketing quality, 4K resolution, sharp focus"
264
+
265
+ def generate_with_google_imagen(enhanced_prompt):
266
+ """Generate image using Google Imagen API"""
267
+ try:
268
+ if GOOGLE_SERVICE_ACCOUNT_JSON:
269
+ client = genai_sdk.Client()
270
+ else:
271
+ client = genai_sdk.Client(api_key=GOOGLE_API_KEY)
272
+
273
+ result = client.models.generate_images(
274
+ model="imagen-3.0-generate-002",
275
+ prompt=enhanced_prompt,
276
+ config={
277
+ "number_of_images": 1,
278
+ "output_mime_type": "image/png"
279
+ }
280
+ )
281
 
282
+ if result and hasattr(result, 'generated_images') and len(result.generated_images) > 0:
283
+ generated_image = result.generated_images[0]
284
+ if hasattr(generated_image, 'image') and hasattr(generated_image.image, 'image_bytes'):
285
+ image_bytes = generated_image.image.image_bytes
286
+ image = Image.open(io.BytesIO(image_bytes))
287
+ logger.info("Successfully generated real image with Google Imagen!")
288
+ return image
289
+
290
+ return None
291
+
292
+ except Exception as e:
293
+ logger.warning(f"Google Imagen generation failed: {e}")
294
+ return None
295
 
296
+ def review_image_with_ai(image, original_prompt, enhanced_prompt):
297
+ """Review image using Google Gemini Vision"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  try:
299
+ model = genai.GenerativeModel('gemini-2.0-flash-exp')
300
 
301
+ analysis_prompt = f"""
302
+ Analyze this marketing image generated from: "{original_prompt}"
 
303
 
304
+ Rate the image on a scale of 0.0 to 1.0 for:
305
+ 1. Technical quality (clarity, composition, lighting)
306
+ 2. Marketing effectiveness (professional appeal, brand suitability)
307
+ 3. Prompt matching (how well it matches the request)
308
 
309
+ Provide:
310
+ - Overall quality score (0.0-1.0)
311
+ - Brief review comments for marketing use
312
+ - Specific strengths and areas for improvement
313
 
314
+ Format: Quality Score: X.XX | Comments: [your analysis]
315
+ """
 
 
 
 
 
316
 
317
+ response = model.generate_content([analysis_prompt, image])
318
+ analysis = response.text
319
 
320
+ # Parse the response
321
+ import re
322
+ score_match = re.search(r'Quality Score:\s*([\d.]+)', analysis)
323
+ quality_score = float(score_match.group(1)) if score_match else 0.85
324
 
325
+ comments_match = re.search(r'Comments:\s*(.+)', analysis, re.DOTALL)
326
+ comments = comments_match.group(1).strip() if comments_match else analysis
327
+
328
+ return {
329
+ "quality_score": min(1.0, max(0.0, quality_score)),
330
+ "comments": comments[:200] + "..." if len(comments) > 200 else comments
331
+ }
332
 
333
+ except Exception as e:
334
+ logger.warning(f"AI image review failed: {e}")
335
+ return {"quality_score": 0.75, "comments": "Image generated successfully"}
 
 
336
 
337
+ def analyze_prompt_quality(prompt, style):
338
+ """Analyze prompt quality and return a score"""
339
+ score = 0.5 # Base score
340
+
341
+ # Length analysis
342
+ word_count = len(prompt.split())
343
+ if 10 <= word_count <= 50:
344
+ score += 0.2
345
+ elif word_count > 5:
346
+ score += 0.1
347
+
348
+ # Content analysis
349
+ marketing_keywords = ['marketing', 'professional', 'brand', 'corporate', 'business', 'campaign']
350
+ visual_keywords = ['lighting', 'composition', 'color', 'background', 'style']
351
+ descriptive_keywords = ['modern', 'clean', 'elegant', 'bold', 'creative', 'minimalist']
352
+
353
+ for keyword_list in [marketing_keywords, visual_keywords, descriptive_keywords]:
354
+ if any(keyword in prompt.lower() for keyword in keyword_list):
355
+ score += 0.1
356
+
357
+ # Style alignment
358
+ if style.lower() in prompt.lower():
359
+ score += 0.1
360
+
361
+ return min(1.0, score)
362
 
363
+ def generate_review_comments(prompt, style, quality_score):
364
+ """Generate contextual review comments"""
365
+ if quality_score >= 0.8:
366
+ return f"Excellent marketing image potential. The {style.lower()} style aligns well with the prompt requirements. Ready for professional use."
367
+ elif quality_score >= 0.6:
368
+ return f"Good marketing image with {style.lower()} styling. Consider adding more specific details for enhanced results."
369
+ else:
370
+ return f"Basic image generated. For better marketing results, try adding more descriptive details and specific {style.lower()} elements."
371
 
372
+ def process_generation(prompt, style, aspect_ratio, num_images, quality_threshold):
373
+ """Process image generation and return results for Gradio"""
374
+ if not prompt.strip():
375
+ return None, "❌ Please enter a prompt", "Error", "Error", "Please provide a description for your marketing image."
376
+
377
+ try:
378
+ result = generate_image_with_review(prompt, style, aspect_ratio, num_images, quality_threshold)
379
+
380
+ if result:
381
+ status_emoji = "βœ…" if result["status"] == "approved" else "⚠️"
382
+ return (
383
+ result["image"],
384
+ f"🎯 {result['quality_score']:.2f}/1.0",
385
+ f"{status_emoji} {result['status'].replace('_', ' ').title()}",
386
+ f"🎨 {result['style']} | πŸ“ {result['aspect_ratio']} | ⚑ {result['method']}",
387
+ f"πŸ’¬ {result['review_comments']}"
388
+ )
389
+ else:
390
+ return None, "❌ Generation failed", "Error", "Error", "An error occurred during image generation. Please try again."
391
+
392
+ except Exception as e:
393
+ logger.error(f"Process generation error: {str(e)}")
394
+ return None, "❌ System error", "Error", "Error", f"System error: {str(e)}"
395
 
396
+ # Custom CSS for enhanced styling
397
+ custom_css = """
398
+ .gradio-container {
399
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
400
+ max-width: 1400px !important;
401
+ margin: 0 auto !important;
402
+ }
403
 
404
+ .main-header {
405
+ text-align: center;
406
+ padding: 2rem 1rem;
407
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
408
+ color: white;
409
+ border-radius: 16px;
410
+ margin-bottom: 2rem;
411
+ box-shadow: 0 10px 25px rgba(102, 126, 234, 0.2);
412
+ }
413
 
414
+ .main-header h1 {
415
+ font-size: 2.5rem;
416
+ font-weight: 700;
417
+ margin: 0 0 0.5rem 0;
418
+ text-shadow: 0 2px 4px rgba(0,0,0,0.1);
419
+ }
420
 
421
+ .main-header p {
422
+ font-size: 1.2rem;
423
+ opacity: 0.95;
424
+ margin: 0;
425
+ font-weight: 300;
426
+ }
427
+
428
+ .status-indicator {
429
+ padding: 1rem;
430
+ border-radius: 12px;
431
+ margin-bottom: 1.5rem;
432
+ display: flex;
433
+ align-items: center;
434
+ gap: 0.75rem;
435
+ font-weight: 600;
436
+ }
437
+
438
+ .status-success {
439
+ background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
440
+ border: 2px solid #10b981;
441
+ color: #065f46;
442
+ }
443
+
444
+ .status-warning {
445
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
446
+ border: 2px solid #f59e0b;
447
+ color: #92400e;
448
+ }
449
+
450
+ .input-section {
451
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
452
+ border: 2px solid #e2e8f0;
453
+ border-radius: 16px;
454
+ padding: 2rem;
455
+ margin-bottom: 2rem;
456
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
457
+ }
458
+
459
+ .output-section {
460
+ background: white;
461
+ border: 2px solid #e2e8f0;
462
+ border-radius: 16px;
463
+ padding: 2rem;
464
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
465
+ }
466
+
467
+ .generate-btn {
468
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
469
+ border: none !important;
470
+ color: white !important;
471
+ font-weight: 600 !important;
472
+ padding: 1rem 2rem !important;
473
+ border-radius: 12px !important;
474
+ font-size: 1.1rem !important;
475
+ transition: all 0.3s ease !important;
476
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3) !important;
477
+ }
478
+
479
+ .generate-btn:hover {
480
+ transform: translateY(-2px) !important;
481
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4) !important;
482
+ }
483
+
484
+ .metric-display {
485
+ background: #f8fafc;
486
+ border: 1px solid #e2e8f0;
487
+ border-radius: 12px;
488
+ padding: 1rem;
489
+ text-align: center;
490
+ font-weight: 600;
491
+ }
492
+
493
+ .info-section {
494
+ background: linear-gradient(135deg, #fafafa 0%, #f4f4f5 100%);
495
+ padding: 1.5rem;
496
+ border-radius: 12px;
497
+ border: 1px solid #e4e4e7;
498
+ }
499
 
500
+ .info-section h3 {
501
+ color: #374151;
502
+ font-size: 1.1rem;
503
+ margin-bottom: 1rem;
504
+ font-weight: 600;
505
+ }
506
 
507
+ .info-section ul {
508
+ margin: 0;
509
+ padding-left: 1.2rem;
510
+ }
511
+
512
+ .info-section li {
513
+ margin-bottom: 0.5rem;
514
+ color: #6b7280;
515
+ line-height: 1.5;
516
+ }
517
+
518
+ .footer-info {
519
+ text-align: center;
520
+ color: #6b7280;
521
+ font-size: 0.9rem;
522
+ margin-top: 2rem;
523
+ padding: 1rem;
524
+ background: #f9fafb;
525
+ border-radius: 8px;
526
+ }
527
+ """
528
+
529
+ # Create the enhanced Gradio interface
530
+ with gr.Blocks(
531
+ title="Marketing Image Generator with AI Review",
532
+ theme=gr.themes.Soft(
533
+ primary_hue="blue",
534
+ secondary_hue="purple",
535
+ neutral_hue="slate"
536
+ ),
537
+ css=custom_css
538
+ ) as demo:
539
 
540
+ # Main header
541
+ gr.HTML("""
542
+ <div class="main-header">
543
+ <h1>🎨 Marketing Image Generator with AI Review</h1>
544
+ <p>Create professional marketing images with automated quality assurance</p>
545
+ </div>
546
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
 
548
+ # Status indicator
549
+ if google_auth_configured:
550
+ gr.HTML("""
551
+ <div class="status-indicator status-success">
552
+ <span style="font-size: 1.2rem;">βœ…</span>
553
+ <div>
554
+ <strong>Ready for Production</strong><br>
555
+ <small>Google Cloud AI services are configured and active</small>
556
+ </div>
557
+ </div>
558
+ """)
559
+ else:
560
+ gr.HTML("""
561
+ <div class="status-indicator status-warning">
562
+ <span style="font-size: 1.2rem;">⚠️</span>
563
+ <div>
564
+ <strong>Demo Mode Active</strong><br>
565
+ <small>Enhanced placeholders will be generated. Configure Google Cloud for full AI capabilities.</small>
566
+ </div>
567
+ </div>
568
+ """)
569
+
570
+ with gr.Row():
571
+ with gr.Column(scale=3):
572
+ # Input section
573
+ with gr.Group():
574
+ gr.HTML('<div class="input-section">')
575
+
576
  gr.Markdown("## πŸ“ Describe Your Marketing Image")
577
 
578
+ prompt_input = gr.Textbox(
579
  label="Marketing Image Description",
580
+ placeholder="A professional team of diverse colleagues collaborating around a modern conference table in a bright office space, clean corporate design, high-quality lighting, suitable for website hero section...",
581
  lines=4,
582
+ info="πŸ’‘ Be specific about subjects, setting, mood, and intended marketing use for best results."
583
  )
584
 
585
  with gr.Row():
586
+ with gr.Column():
587
+ style_dropdown = gr.Dropdown(
588
+ choices=["Professional", "Creative", "Minimalist", "Bold", "Elegant", "Playful", "Corporate", "Modern"],
589
+ value="Professional",
590
+ label="🎨 Visual Style",
591
+ info="Choose the style that matches your brand identity"
592
+ )
593
 
594
+ with gr.Column():
595
+ aspect_ratio = gr.Dropdown(
596
+ choices=["16:9", "1:1", "4:3", "3:2"],
597
+ value="16:9",
598
+ label="πŸ“ Aspect Ratio",
599
+ info="Select dimensions for your use case"
600
+ )
 
601
 
602
+ with gr.Row():
603
+ with gr.Column():
604
+ num_images = gr.Slider(
605
+ minimum=1,
606
+ maximum=1, # Simplified for demo
607
+ value=1,
608
+ step=1,
609
+ label="πŸ–ΌοΈ Images to Generate",
610
+ info="Number of variations"
611
+ )
612
+
613
+ with gr.Column():
614
+ quality_slider = gr.Slider(
615
+ minimum=0.5,
616
+ maximum=1.0,
617
+ value=0.8,
618
+ step=0.05,
619
+ label="🎯 Quality Threshold",
620
+ info="Minimum quality score for approval"
621
+ )
622
 
623
  generate_btn = gr.Button(
624
+ "πŸš€ Generate Marketing Image",
625
  variant="primary",
626
+ elem_classes="generate-btn",
627
  size="lg"
628
  )
 
 
 
 
629
 
630
+ gr.HTML('</div>')
631
+
632
+ with gr.Column(scale=1):
633
+ # Info panel
634
+ gr.HTML("""
635
+ <div class="info-section">
636
+ <h3>πŸ” How It Works</h3>
637
+ <ul>
638
+ <li><strong>Describe:</strong> Detail your vision with specific marketing context</li>
639
+ <li><strong>Style:</strong> Choose from professional design styles</li>
640
+ <li><strong>Generate:</strong> AI creates optimized marketing images</li>
641
+ <li><strong>Review:</strong> Automated quality analysis and feedback</li>
642
+ <li><strong>Use:</strong> Download high-quality results</li>
643
+ </ul>
 
 
644
 
645
+ <h3>πŸ’‘ Tips for Best Results</h3>
646
+ <ul>
647
+ <li>Include target audience and use case</li>
648
+ <li>Specify colors, mood, and setting</li>
649
+ <li>Mention brand elements or style preferences</li>
650
+ <li>Be specific about composition and framing</li>
651
+ </ul>
652
+ </div>
653
+ """)
654
+
655
+ # Output section
656
+ gr.HTML('<div class="output-section">')
657
+
658
+ gr.Markdown("## πŸ–ΌοΈ Generated Marketing Image & Analysis")
659
+
660
+ with gr.Row():
661
+ with gr.Column(scale=2):
662
+ image_output = gr.Image(
663
+ label="Generated Marketing Image",
664
+ height=400,
665
+ show_label=True,
666
+ show_download_button=True
667
  )
668
 
669
+ with gr.Column(scale=1):
670
+ gr.Markdown("### πŸ“Š Quality Metrics")
671
+
672
+ quality_output = gr.Textbox(
673
+ label="Quality Score",
674
+ interactive=False,
675
+ elem_classes="metric-display"
676
+ )
677
+
678
+ status_output = gr.Textbox(
679
+ label="Review Status",
680
+ interactive=False,
681
+ elem_classes="metric-display"
682
+ )
683
+
684
+ style_output = gr.Textbox(
685
+ label="Generation Details",
686
+ interactive=False,
687
+ elem_classes="metric-display"
688
+ )
689
+
690
+ review_output = gr.Textbox(
691
+ label="πŸ“‹ AI Quality Review & Recommendations",
692
+ lines=3,
693
+ interactive=False,
694
+ info="Detailed feedback and suggestions from our AI review system"
695
+ )
696
+
697
+ gr.HTML('</div>')
698
+
699
+ # Examples section
700
+ gr.Markdown("## πŸ’‘ Example Prompts")
701
+
702
+ examples = gr.Examples(
703
+ examples=[
704
+ [
705
+ "A diverse team of professionals collaborating around a modern conference table in a bright, contemporary office space with large windows and natural lighting, suitable for corporate website hero section",
706
+ "Professional",
707
+ "16:9",
708
+ 1,
709
+ 0.8
710
  ],
711
+ [
712
+ "A sleek product showcase featuring a smartphone floating above a clean white surface with dramatic studio lighting and subtle reflections, perfect for e-commerce marketing",
713
+ "Minimalist",
714
+ "1:1",
715
+ 1,
716
+ 0.8
717
+ ],
718
+ [
719
+ "A friendly customer service representative wearing a headset, smiling warmly while helping clients in a modern call center environment with soft lighting",
720
+ "Corporate",
721
+ "4:3",
722
+ 1,
723
+ 0.8
724
+ ],
725
+ [
726
+ "An inspiring workspace setup with a laptop, coffee cup, and plants on a wooden desk, warm natural lighting streaming through a window, perfect for productivity app marketing",
727
+ "Modern",
728
+ "16:9",
729
+ 1,
730
+ 0.8
731
+ ]
732
+ ],
733
+ inputs=[prompt_input, style_dropdown, aspect_ratio, num_images, quality_slider],
734
+ label="Click any example to try it out!"
735
+ )
736
 
737
+ # Footer
738
+ gr.HTML("""
739
+ <div class="footer-info">
740
+ <strong>Marketing Image Generator with AI Review</strong><br>
741
+ Powered by Google Imagen3 & Gemini Vision | Built for Professional Marketing Teams<br>
742
+ <em>Transform your marketing vision into professional-quality images with AI-powered review</em>
743
+ </div>
744
+ """)
745
+
746
+ # Connect the generation function
747
+ generate_btn.click(
748
+ fn=process_generation,
749
+ inputs=[prompt_input, style_dropdown, aspect_ratio, num_images, quality_slider],
750
+ outputs=[image_output, quality_output, status_output, style_output, review_output],
751
+ show_progress=True
752
+ )
753
 
754
+ # Launch configuration
755
  if __name__ == "__main__":
 
756
  demo.launch(
757
  server_name="0.0.0.0",
758
  server_port=7860,
 
759
  show_error=True,
760
+ share=False
761
+ )