|
""" |
|
Marketing Image Generator with Agent Review - Complete Gradio App |
|
|
|
Integrated single-file application that includes: |
|
1. Image Generator Agent (using Google Imagen) |
|
2. Image Reviewer Agent (using Google Gemini Vision) |
|
3. Gradio UI for Hugging Face deployment |
|
|
|
This combines the functionality of the entire marketing image generation system |
|
into one deployable file for Hugging Face Spaces. |
|
""" |
|
|
|
import gradio as gr |
|
import os |
|
import base64 |
|
import io |
|
import time |
|
import re |
|
import logging |
|
import asyncio |
|
from typing import Dict, Any, List, Optional |
|
from PIL import Image |
|
import google.generativeai as genai |
|
from google import genai as genai_sdk |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
MAX_IMAGE_SIZE = 1024 |
|
DEFAULT_QUALITY_THRESHOLD = 0.8 |
|
|
|
|
|
def setup_google_auth(): |
|
"""Setup Google authentication with multiple fallback options""" |
|
|
|
|
|
gcp_service_account = os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON") |
|
if gcp_service_account: |
|
try: |
|
import json |
|
from google.oauth2 import service_account |
|
import google.auth |
|
|
|
|
|
service_account_info = json.loads(gcp_service_account) |
|
credentials = service_account.Credentials.from_service_account_info(service_account_info) |
|
|
|
|
|
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'temp_service_account.json' |
|
with open('temp_service_account.json', 'w') as f: |
|
json.dump(service_account_info, f) |
|
|
|
logger.info("Google Cloud service account configured successfully") |
|
return "service_account" |
|
|
|
except Exception as e: |
|
logger.warning(f"Failed to setup service account: {e}") |
|
|
|
|
|
api_keys = [ |
|
os.getenv("GOOGLE_API_KEY"), |
|
os.getenv("GOOGLE_AI_STUDIO_API_KEY"), |
|
os.getenv("GCP_KEY_1"), |
|
os.getenv("GCP_KEY_2"), |
|
os.getenv("GCP_KEY_3") |
|
] |
|
|
|
google_api_key = next((key for key in api_keys if key), None) |
|
if google_api_key: |
|
try: |
|
genai.configure(api_key=google_api_key) |
|
logger.info("Google AI Studio API key configured successfully") |
|
return google_api_key |
|
except Exception as e: |
|
logger.warning(f"Failed to configure API key: {e}") |
|
|
|
logger.warning("No Google authentication found - using fallback mode") |
|
return None |
|
|
|
|
|
GOOGLE_AUTH = setup_google_auth() |
|
|
|
|
|
|
|
class ImageGeneratorAgent: |
|
"""Agent responsible for generating marketing images using Google Imagen""" |
|
|
|
def __init__(self): |
|
self.name = "image_generator_agent" |
|
|
|
async def enhance_prompt(self, prompt: str, style: str) -> str: |
|
"""Enhance user prompt for better image generation""" |
|
if not GOOGLE_AUTH: |
|
|
|
style_enhancers = { |
|
"realistic": "photorealistic, high detail, professional photography, marketing quality", |
|
"artistic": "artistic masterpiece, creative composition, marketing appeal", |
|
"cartoon": "cartoon style, vibrant colors, playful, marketing friendly", |
|
"illustration": "professional illustration, clean design, marketing material", |
|
"photographic": "professional photograph, high quality, studio lighting, marketing shot" |
|
} |
|
enhancer = style_enhancers.get(style, "high quality, professional") |
|
return f"{prompt}, {enhancer}, 4K resolution, sharp focus" |
|
|
|
try: |
|
enhancement_prompt = f""" |
|
You are an expert prompt engineer for AI image generation. Enhance this marketing image prompt for optimal results with Google Imagen. |
|
|
|
Original prompt: "{prompt}" |
|
Desired style: "{style}" |
|
|
|
Create an enhanced version that: |
|
1. Maintains the core marketing intent |
|
2. Adds specific technical details for image quality |
|
3. Includes appropriate style descriptors for "{style}" style |
|
4. Adds professional marketing composition guidance |
|
5. Keeps the enhanced prompt under 150 words |
|
|
|
Return only the enhanced prompt without explanation. |
|
""" |
|
|
|
model = genai.GenerativeModel('gemini-2.0-flash-exp') |
|
response = model.generate_content(enhancement_prompt) |
|
enhanced = response.text.strip() |
|
|
|
logger.info(f"Enhanced prompt: {enhanced[:100]}...") |
|
return enhanced |
|
|
|
except Exception as e: |
|
logger.warning(f"Failed to enhance prompt with AI: {e}") |
|
style_enhancers = { |
|
"realistic": "photorealistic, high detail, professional photography, marketing quality", |
|
"artistic": "artistic masterpiece, creative composition, marketing appeal", |
|
"cartoon": "cartoon style, vibrant colors, playful, marketing friendly", |
|
"illustration": "professional illustration, clean design, marketing material", |
|
"photographic": "professional photograph, high quality, studio lighting" |
|
} |
|
enhancer = style_enhancers.get(style, "high quality, professional") |
|
return f"{prompt}, {enhancer}, 4K resolution, sharp focus" |
|
|
|
async def generate_image(self, prompt: str, style: str = "realistic") -> Dict[str, Any]: |
|
"""Generate image using Google Imagen""" |
|
try: |
|
|
|
enhanced_prompt = await self.enhance_prompt(prompt, style) |
|
|
|
|
|
if GOOGLE_AUTH: |
|
image_data = await self._generate_with_imagen(enhanced_prompt) |
|
if image_data: |
|
return { |
|
"success": True, |
|
"image_data": image_data, |
|
"enhanced_prompt": enhanced_prompt, |
|
"method": "Google Imagen" |
|
} |
|
|
|
|
|
return await self._generate_fallback(enhanced_prompt, style) |
|
|
|
except Exception as e: |
|
logger.error(f"Image generation failed: {e}") |
|
return { |
|
"success": False, |
|
"error": str(e), |
|
"enhanced_prompt": prompt |
|
} |
|
|
|
async def _generate_with_imagen(self, enhanced_prompt: str) -> Optional[str]: |
|
"""Generate image using Google Imagen API""" |
|
try: |
|
|
|
if GOOGLE_AUTH == "service_account": |
|
|
|
client = genai_sdk.Client() |
|
else: |
|
|
|
client = genai_sdk.Client(api_key=GOOGLE_AUTH) |
|
|
|
result = client.models.generate_images( |
|
model="imagen-3.0-generate-002", |
|
prompt=enhanced_prompt, |
|
config={ |
|
"number_of_images": 1, |
|
"output_mime_type": "image/png" |
|
} |
|
) |
|
|
|
if result and hasattr(result, 'generated_images') and len(result.generated_images) > 0: |
|
generated_image = result.generated_images[0] |
|
|
|
if hasattr(generated_image, 'image') and hasattr(generated_image.image, 'image_bytes'): |
|
image_bytes = generated_image.image.image_bytes |
|
base64_image = base64.b64encode(image_bytes).decode('utf-8') |
|
return f"data:image/png;base64,{base64_image}" |
|
|
|
return None |
|
|
|
except Exception as e: |
|
logger.warning(f"Imagen API failed: {e}") |
|
return None |
|
|
|
async def _generate_fallback(self, enhanced_prompt: str, style: str) -> Dict[str, Any]: |
|
"""Generate fallback placeholder image""" |
|
try: |
|
|
|
import hashlib |
|
prompt_hash = int(hashlib.md5(enhanced_prompt.encode()).hexdigest()[:8], 16) |
|
|
|
|
|
colors = [ |
|
(70, 130, 180), |
|
(60, 179, 113), |
|
(255, 140, 0), |
|
(106, 90, 205), |
|
(220, 20, 60), |
|
(255, 215, 0), |
|
(147, 112, 219), |
|
(32, 178, 170) |
|
] |
|
|
|
color = colors[prompt_hash % len(colors)] |
|
img = Image.new('RGB', (1024, 1024), color) |
|
|
|
|
|
try: |
|
from PIL import ImageDraw, ImageFont |
|
draw = ImageDraw.Draw(img) |
|
|
|
|
|
try: |
|
font = ImageFont.truetype("/System/Library/Fonts/Arial.ttf", 48) |
|
except: |
|
font = ImageFont.load_default() |
|
|
|
|
|
text = f"Marketing Image\n{style.title()} Style" |
|
draw.multiline_text((50, 450), text, fill=(255, 255, 255), font=font, align="center") |
|
|
|
except Exception as e: |
|
logger.warning(f"Could not add text overlay: {e}") |
|
|
|
|
|
img_buffer = io.BytesIO() |
|
img.save(img_buffer, format='PNG') |
|
img_buffer.seek(0) |
|
base64_image = base64.b64encode(img_buffer.read()).decode('utf-8') |
|
|
|
return { |
|
"success": True, |
|
"image_data": f"data:image/png;base64,{base64_image}", |
|
"enhanced_prompt": enhanced_prompt, |
|
"method": "Fallback Demo" |
|
} |
|
|
|
except Exception as e: |
|
logger.error(f"Fallback generation failed: {e}") |
|
return {"success": False, "error": str(e)} |
|
|
|
|
|
|
|
class ImageReviewerAgent: |
|
"""Agent responsible for reviewing generated images for quality and relevance""" |
|
|
|
def __init__(self): |
|
self.name = "image_reviewer_agent" |
|
|
|
def parse_prompt_elements(self, prompt: str) -> Dict[str, List[str]]: |
|
"""Parse prompt to extract key elements for validation""" |
|
prompt_lower = prompt.lower() |
|
|
|
|
|
patterns = { |
|
"subjects": [ |
|
r'\b(person|man|woman|child|people|human|figure|team|group)\b', |
|
r'\b(product|device|phone|laptop|car|building|office|space)\b', |
|
r'\b(logo|brand|company|business|service)\b' |
|
], |
|
"style": [ |
|
r'\b(realistic|photorealistic|photograph|photo)\b', |
|
r'\b(artistic|painting|drawing|illustration)\b', |
|
r'\b(modern|contemporary|minimalist|professional)\b', |
|
r'\b(cartoon|animated|3d|rendered)\b' |
|
], |
|
"colors": [ |
|
r'\b(blue|red|green|yellow|orange|purple|pink|black|white|gray|grey)\b', |
|
r'\b(bright|dark|light|vibrant|muted|pastel|neon)\b', |
|
r'\b(colorful|monochrome|gradient)\b' |
|
], |
|
"settings": [ |
|
r'\b(office|studio|outdoor|indoor|background|scene)\b', |
|
r'\b(professional|corporate|casual|formal)\b', |
|
r'\b(lighting|natural light|studio lighting)\b' |
|
], |
|
"marketing": [ |
|
r'\b(marketing|advertisement|promotional|campaign|brand)\b', |
|
r'\b(professional|business|corporate|commercial)\b', |
|
r'\b(hero|banner|social media|web|digital)\b' |
|
] |
|
} |
|
|
|
def extract_matches(patterns_list: List[str], text: str) -> List[str]: |
|
matches = set() |
|
for pattern in patterns_list: |
|
found = re.findall(pattern, text) |
|
matches.update(found) |
|
return list(matches) |
|
|
|
return { |
|
key: extract_matches(pattern_list, prompt_lower) |
|
for key, pattern_list in patterns.items() |
|
} |
|
|
|
async def review_image(self, image_data: str, original_prompt: str, enhanced_prompt: str) -> Dict[str, Any]: |
|
"""Review generated image for quality and relevance""" |
|
try: |
|
logger.info("Starting image review analysis") |
|
|
|
|
|
prompt_elements = self.parse_prompt_elements(original_prompt) |
|
|
|
|
|
if GOOGLE_AUTH and image_data.startswith("data:image"): |
|
ai_review = await self._ai_powered_review(image_data, original_prompt, enhanced_prompt, prompt_elements) |
|
if ai_review: |
|
return ai_review |
|
|
|
|
|
return await self._prompt_based_review(original_prompt, enhanced_prompt, prompt_elements) |
|
|
|
except Exception as e: |
|
logger.error(f"Image review failed: {e}") |
|
return self._fallback_review(original_prompt) |
|
|
|
async def _ai_powered_review(self, image_data: str, original_prompt: str, enhanced_prompt: str, prompt_elements: Dict) -> Optional[Dict[str, Any]]: |
|
"""Review image using Google Gemini Vision""" |
|
try: |
|
|
|
if not image_data.startswith("data:image"): |
|
return None |
|
|
|
image_b64 = image_data.split(',')[1] |
|
image_bytes = base64.b64decode(image_b64) |
|
image = Image.open(io.BytesIO(image_bytes)) |
|
|
|
|
|
analysis_prompt = f""" |
|
Analyze this marketing image that was generated from: "{original_prompt}" |
|
Enhanced prompt used: "{enhanced_prompt}" |
|
|
|
Key elements to verify: |
|
- Subjects: {', '.join(prompt_elements.get('subjects', []))} |
|
- Style: {', '.join(prompt_elements.get('style', []))} |
|
- Colors: {', '.join(prompt_elements.get('colors', []))} |
|
- Setting: {', '.join(prompt_elements.get('settings', []))} |
|
- Marketing elements: {', '.join(prompt_elements.get('marketing', []))} |
|
|
|
Rate the image on: |
|
1. Technical Quality (0.0-1.0): clarity, composition, lighting, resolution |
|
2. Prompt Relevance (0.0-1.0): how well it matches the original request |
|
3. Marketing Effectiveness (0.0-1.0): professional appeal, brand suitability |
|
|
|
Provide response in this format: |
|
QUALITY_SCORE: [0.0-1.0] |
|
RELEVANCE_SCORE: [0.0-1.0] |
|
MARKETING_SCORE: [0.0-1.0] |
|
|
|
STRENGTHS: [List 2-3 strong points] |
|
ISSUES: [List 2-3 improvement areas] |
|
RECOMMENDATIONS: [List 2-3 specific suggestions] |
|
|
|
OVERALL_ASSESSMENT: [Brief summary of the image's marketing potential] |
|
""" |
|
|
|
model = genai.GenerativeModel('gemini-2.0-flash-exp') |
|
response = model.generate_content([analysis_prompt, image]) |
|
analysis_text = response.text |
|
|
|
return self._parse_ai_review(analysis_text, original_prompt) |
|
|
|
except Exception as e: |
|
logger.warning(f"AI-powered review failed: {e}") |
|
return None |
|
|
|
def _parse_ai_review(self, analysis_text: str, original_prompt: str) -> Dict[str, Any]: |
|
"""Parse AI review response into structured feedback""" |
|
|
|
def extract_score(text: str, score_type: str) -> float: |
|
pattern = rf"{score_type}_SCORE:\s*([\d.]+)" |
|
match = re.search(pattern, text, re.IGNORECASE) |
|
if match: |
|
try: |
|
return min(1.0, max(0.0, float(match.group(1)))) |
|
except ValueError: |
|
pass |
|
return 0.7 |
|
|
|
def extract_list_section(text: str, section: str) -> List[str]: |
|
pattern = rf"{section}:\s*(.+?)(?=\n[A-Z_]+:|$)" |
|
match = re.search(pattern, text, re.IGNORECASE | re.DOTALL) |
|
if match: |
|
items_text = match.group(1).strip() |
|
items = [item.strip().strip('-β’*').strip() |
|
for item in re.split(r'\n|,', items_text) |
|
if item.strip() and len(item.strip()) > 3] |
|
return items[:3] |
|
return [] |
|
|
|
try: |
|
|
|
quality_score = extract_score(analysis_text, "QUALITY") |
|
relevance_score = extract_score(analysis_text, "RELEVANCE") |
|
marketing_score = extract_score(analysis_text, "MARKETING") |
|
|
|
|
|
strengths = extract_list_section(analysis_text, "STRENGTHS") |
|
issues = extract_list_section(analysis_text, "ISSUES") |
|
recommendations = extract_list_section(analysis_text, "RECOMMENDATIONS") |
|
|
|
|
|
assessment_match = re.search(r"OVERALL_ASSESSMENT:\s*(.+?)(?=\n[A-Z_]+:|$)", |
|
analysis_text, re.IGNORECASE | re.DOTALL) |
|
overall_assessment = assessment_match.group(1).strip() if assessment_match else "Good marketing image potential" |
|
|
|
|
|
overall_score = (quality_score * 0.3 + relevance_score * 0.4 + marketing_score * 0.3) |
|
|
|
|
|
passed = overall_score >= 0.7 and relevance_score >= 0.6 |
|
|
|
return { |
|
"success": True, |
|
"overall_score": round(overall_score, 2), |
|
"quality_score": round(quality_score, 2), |
|
"relevance_score": round(relevance_score, 2), |
|
"marketing_score": round(marketing_score, 2), |
|
"passed": passed, |
|
"strengths": strengths, |
|
"issues": issues, |
|
"recommendations": recommendations, |
|
"overall_assessment": overall_assessment, |
|
"review_method": "AI-Powered (Gemini Vision)" |
|
} |
|
|
|
except Exception as e: |
|
logger.error(f"Error parsing AI review: {e}") |
|
return self._fallback_review(original_prompt) |
|
|
|
async def _prompt_based_review(self, original_prompt: str, enhanced_prompt: str, prompt_elements: Dict) -> Dict[str, Any]: |
|
"""Review based on prompt analysis when AI review isn't available""" |
|
|
|
issues = [] |
|
recommendations = [] |
|
strengths = [] |
|
|
|
|
|
total_elements = sum(len(elements) for elements in prompt_elements.values()) |
|
|
|
|
|
if total_elements >= 8: |
|
base_score = 0.8 |
|
strengths.append("Comprehensive prompt with detailed specifications") |
|
elif total_elements >= 5: |
|
base_score = 0.7 |
|
strengths.append("Good prompt detail level") |
|
elif total_elements >= 3: |
|
base_score = 0.6 |
|
issues.append("Prompt could use more specific details") |
|
else: |
|
base_score = 0.5 |
|
issues.append("Prompt lacks sufficient detail for optimal results") |
|
recommendations.append("Add more specific details about subjects, style, and setting") |
|
|
|
|
|
marketing_elements = prompt_elements.get('marketing', []) |
|
if marketing_elements: |
|
base_score += 0.1 |
|
strengths.append("Contains marketing-focused language") |
|
else: |
|
recommendations.append("Consider adding marketing-specific context") |
|
|
|
|
|
style_elements = prompt_elements.get('style', []) |
|
if style_elements: |
|
strengths.append(f"Clear style direction: {', '.join(style_elements[:2])}") |
|
else: |
|
issues.append("No clear artistic style specified") |
|
recommendations.append("Specify desired artistic style (realistic, artistic, etc.)") |
|
|
|
|
|
subject_elements = prompt_elements.get('subjects', []) |
|
if subject_elements: |
|
strengths.append(f"Clear subjects identified: {', '.join(subject_elements[:2])}") |
|
else: |
|
issues.append("Main subjects not clearly specified") |
|
recommendations.append("Clearly define what should be the main focus") |
|
|
|
|
|
quality_score = min(1.0, base_score + 0.1) |
|
relevance_score = base_score |
|
marketing_score = base_score + (0.1 if marketing_elements else -0.1) |
|
|
|
overall_score = (quality_score * 0.3 + relevance_score * 0.4 + marketing_score * 0.3) |
|
passed = overall_score >= 0.6 |
|
|
|
return { |
|
"success": True, |
|
"overall_score": round(overall_score, 2), |
|
"quality_score": round(quality_score, 2), |
|
"relevance_score": round(relevance_score, 2), |
|
"marketing_score": round(marketing_score, 2), |
|
"passed": passed, |
|
"strengths": strengths[:3], |
|
"issues": issues[:3], |
|
"recommendations": recommendations[:3], |
|
"overall_assessment": f"Prompt-based analysis shows {'good' if passed else 'moderate'} marketing image potential", |
|
"review_method": "Prompt Analysis" |
|
} |
|
|
|
def _fallback_review(self, original_prompt: str) -> Dict[str, Any]: |
|
"""Fallback review when all else fails""" |
|
word_count = len(original_prompt.split()) |
|
base_score = min(0.8, max(0.4, 0.4 + (word_count * 0.02))) |
|
|
|
return { |
|
"success": True, |
|
"overall_score": base_score, |
|
"quality_score": base_score, |
|
"relevance_score": base_score, |
|
"marketing_score": base_score, |
|
"passed": base_score >= 0.6, |
|
"strengths": ["Prompt provided for image generation"], |
|
"issues": ["Unable to perform detailed analysis"], |
|
"recommendations": ["Consider regenerating with more detailed prompt"], |
|
"overall_assessment": "Basic review completed", |
|
"review_method": "Fallback" |
|
} |
|
|
|
|
|
|
|
|
|
generator_agent = ImageGeneratorAgent() |
|
reviewer_agent = ImageReviewerAgent() |
|
|
|
def generate_marketing_image_with_review( |
|
prompt: str, |
|
style: str = "realistic", |
|
quality_threshold: float = 0.8, |
|
max_iterations: int = 2, |
|
progress=gr.Progress(track_tqdm=True) |
|
): |
|
""" |
|
Main workflow: Generate image and review it |
|
""" |
|
|
|
if not prompt.strip(): |
|
return None, "Please enter a prompt to generate an image.", "β No Prompt", "" |
|
|
|
try: |
|
progress(0.1, desc="Initializing generation workflow...") |
|
|
|
|
|
progress(0.3, desc="Generating marketing image...") |
|
generation_result = asyncio.run(generator_agent.generate_image(prompt, style)) |
|
|
|
if not generation_result.get("success"): |
|
error_msg = f"Image generation failed: {generation_result.get('error', 'Unknown error')}" |
|
return None, error_msg, "β Generation Failed", "" |
|
|
|
image_data = generation_result["image_data"] |
|
enhanced_prompt = generation_result["enhanced_prompt"] |
|
|
|
|
|
if image_data.startswith("data:image"): |
|
image_b64 = image_data.split(',')[1] |
|
image_bytes = base64.b64decode(image_b64) |
|
display_image = Image.open(io.BytesIO(image_bytes)) |
|
else: |
|
display_image = None |
|
|
|
progress(0.6, desc="Reviewing image quality...") |
|
|
|
|
|
review_result = asyncio.run(reviewer_agent.review_image(image_data, prompt, enhanced_prompt)) |
|
|
|
progress(0.9, desc="Finalizing results...") |
|
|
|
|
|
if review_result.get("success"): |
|
|
|
quality_info = f""" |
|
## π― Review Results |
|
|
|
**Overall Score:** {review_result['overall_score']:.2f}/1.0 |
|
**Status:** {'β
Approved' if review_result['passed'] else 'β οΈ Needs Improvement'} |
|
|
|
### Detailed Scores |
|
- **Quality:** {review_result['quality_score']:.2f}/1.0 |
|
- **Relevance:** {review_result['relevance_score']:.2f}/1.0 |
|
- **Marketing Appeal:** {review_result['marketing_score']:.2f}/1.0 |
|
|
|
### πͺ Strengths |
|
{chr(10).join(f"β’ {strength}" for strength in review_result.get('strengths', []))} |
|
|
|
### β οΈ Areas for Improvement |
|
{chr(10).join(f"β’ {issue}" for issue in review_result.get('issues', []))} |
|
|
|
### π‘ Recommendations |
|
{chr(10).join(f"β’ {rec}" for rec in review_result.get('recommendations', []))} |
|
|
|
### π Assessment |
|
{review_result.get('overall_assessment', 'Review completed')} |
|
|
|
--- |
|
*Review Method: {review_result.get('review_method', 'Standard')}* |
|
*Enhanced Prompt: {enhanced_prompt[:100]}...* |
|
""" |
|
|
|
review_status = "β
Approved" if review_result['passed'] else "β οΈ Needs Review" |
|
|
|
|
|
debug_info = f""" |
|
**Generation Details:** |
|
- Method: {generation_result.get('method', 'Unknown')} |
|
- Original Prompt: {prompt} |
|
- Enhanced Prompt: {enhanced_prompt} |
|
- Style: {style} |
|
- API Status: {'β
Connected' if GOOGLE_AUTH else 'β οΈ Demo Mode'} |
|
""" |
|
|
|
else: |
|
quality_info = f"Review failed: {review_result.get('error', 'Unknown error')}" |
|
review_status = "β Review Failed" |
|
debug_info = f"Generation Method: {generation_result.get('method', 'Unknown')}" |
|
|
|
progress(1.0, desc="Complete!") |
|
|
|
return display_image, quality_info, review_status, debug_info |
|
|
|
except Exception as e: |
|
logger.error(f"Workflow error: {str(e)}") |
|
error_msg = f"Workflow failed: {str(e)}" |
|
return None, error_msg, "β Error", f"Error details: {str(e)}" |
|
|
|
|
|
|
|
def create_gradio_interface(): |
|
"""Create the complete Gradio interface""" |
|
|
|
custom_css = """ |
|
.gradio-container { |
|
max-width: 1400px !important; |
|
margin: auto !important; |
|
} |
|
.header-text { |
|
text-align: center; |
|
color: #1f77b4; |
|
margin-bottom: 2rem; |
|
} |
|
.quality-info { |
|
background-color: #f8f9fa; |
|
padding: 1rem; |
|
border-radius: 0.5rem; |
|
border-left: 4px solid #1f77b4; |
|
font-family: monospace; |
|
} |
|
.status-approved { color: #28a745; font-weight: bold; } |
|
.status-warning { color: #ffc107; font-weight: bold; } |
|
.status-error { color: #dc3545; font-weight: bold; } |
|
""" |
|
|
|
with gr.Blocks(css=custom_css, title="Marketing Image Generator with AI Review") as interface: |
|
|
|
|
|
gr.Markdown(""" |
|
# π¨ Marketing Image Generator with AI Review |
|
### Professional marketing images with automated quality assurance |
|
|
|
This system combines **Google Imagen** for image generation with **Google Gemini Vision** for intelligent quality review. |
|
Perfect for creating professional marketing materials with AI-powered feedback. |
|
""", elem_classes=["header-text"]) |
|
|
|
|
|
api_status = "π’ Google AI Connected" if GOOGLE_AUTH else "π‘ Demo Mode (No API Key)" |
|
gr.Markdown(f"**Status:** {api_status}") |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=2): |
|
|
|
gr.Markdown("## π Describe Your Marketing Image") |
|
|
|
prompt = gr.Textbox( |
|
label="Marketing Image Description", |
|
placeholder="e.g., A professional team of diverse colleagues collaborating in a modern office space with natural lighting, for a corporate website hero image", |
|
lines=4, |
|
info="Be specific about subjects, setting, style, and intended marketing use" |
|
) |
|
|
|
with gr.Row(): |
|
style = gr.Dropdown( |
|
choices=["realistic", "artistic", "cartoon", "illustration", "photographic"], |
|
value="realistic", |
|
label="Art Style", |
|
info="Choose the visual style that fits your brand" |
|
) |
|
|
|
quality_threshold = gr.Slider( |
|
minimum=0.0, |
|
maximum=1.0, |
|
value=0.7, |
|
step=0.1, |
|
label="Quality Threshold", |
|
info="Minimum score for approval (0.0 = lenient, 1.0 = strict)" |
|
) |
|
|
|
with gr.Accordion("π§ Advanced Options", open=False): |
|
max_iterations = gr.Slider( |
|
minimum=1, |
|
maximum=3, |
|
value=2, |
|
step=1, |
|
label="Max Review Iterations", |
|
info="Maximum attempts to improve the image" |
|
) |
|
|
|
generate_btn = gr.Button( |
|
"π Generate & Review Marketing Image", |
|
variant="primary", |
|
size="lg" |
|
) |
|
|
|
with gr.Column(scale=3): |
|
|
|
gr.Markdown("## πΌοΈ Generated Image & Analysis") |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=2): |
|
generated_image = gr.Image( |
|
label="Your Marketing Image", |
|
type="pil", |
|
interactive=False, |
|
height=400 |
|
) |
|
|
|
with gr.Column(scale=1): |
|
review_status = gr.Textbox( |
|
label="Review Status", |
|
value="β³ Ready to Generate", |
|
interactive=False, |
|
max_lines=1 |
|
) |
|
|
|
quality_info = gr.Markdown( |
|
label="AI Quality Analysis", |
|
value="*Generate an image to see detailed AI quality analysis and recommendations*", |
|
elem_classes=["quality-info"] |
|
) |
|
|
|
|
|
with gr.Accordion("π§ Technical Details", open=False): |
|
debug_info = gr.Markdown( |
|
value="*Technical information will appear here after generation*" |
|
) |
|
|
|
|
|
gr.Markdown("## π‘ Example Marketing Prompts") |
|
|
|
examples = gr.Examples( |
|
examples=[ |
|
["A diverse team of professionals collaborating around a modern conference table in a bright office space, corporate website hero image", "realistic"], |
|
["A sleek product showcase featuring a smartphone on a clean white background with dramatic lighting, for e-commerce", "photographic"], |
|
["A friendly customer service representative wearing a headset, smiling while helping clients in a contemporary office", "realistic"], |
|
["A minimalist workspace setup with laptop, coffee, and plants, perfect for productivity app marketing", "artistic"], |
|
["An abstract representation of data flow and connectivity, modern tech company branding", "illustration"], |
|
["A celebration scene with confetti and happy people, perfect for achievement or success marketing", "realistic"] |
|
], |
|
inputs=[prompt, style], |
|
label="Click any example to try it out!" |
|
) |
|
|
|
|
|
generate_btn.click( |
|
fn=generate_marketing_image_with_review, |
|
inputs=[prompt, style, quality_threshold, max_iterations], |
|
outputs=[generated_image, quality_info, review_status, debug_info], |
|
show_progress=True |
|
) |
|
|
|
|
|
gr.Markdown(""" |
|
--- |
|
<div style='text-align: center; color: #666; font-size: 0.9rem;'> |
|
<p>π¨ <strong>Marketing Image Generator with AI Review</strong></p> |
|
<p>Powered by Google Imagen & Gemini Vision | Built for Professional Marketing Teams</p> |
|
<p><em>Generate β Review β Perfect: Your AI-powered creative workflow</em></p> |
|
</div> |
|
""") |
|
|
|
return interface |
|
|
|
|
|
|
|
|
|
demo = create_gradio_interface() |
|
|
|
if __name__ == "__main__": |
|
logger.info("Starting Marketing Image Generator with AI Review") |
|
demo.launch( |
|
server_name="0.0.0.0", |
|
server_port=7860, |
|
share=False, |
|
show_error=True, |
|
) |
|
|