arpit13's picture
Update app.py
23d6e10 verified
# AI Image Creator: Enhanced UI and UX
# Part 1: Core Setup, Model Classes and API Configuration
import gradio as gr
import logging
import sys
import random
import time
import os
from huggingface_hub import InferenceClient
from PIL import Image
import io
import base64
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger("ai_image_creator")
# =============== MODEL CLIENTS SETUP ===============
def setup_client(api_key, provider=None):
"""Initialize and return API client"""
try:
if provider:
client = InferenceClient(provider=provider, api_key=api_key)
logger.info(f"{provider} client initialized successfully")
else:
client = InferenceClient(api_key=api_key)
logger.info("Hugging Face client initialized successfully")
return client
except Exception as e:
logger.error(f"Error initializing client: {str(e)}")
return None
# Initialize clients
try:
# Replace with your actual HF API key
hf_api_key = os.getenv("HF_API_KEY1")
hf_client = setup_client(hf_api_key)
logger.info("Hugging Face client created successfully")
# Set up Llama client if API key is provided
llama_api_key = os.getenv("HF_API_KEY2") # Replace with actual key if available
try:
llama_client = setup_client(llama_api_key, "sambanova")
use_llama = True
logger.info("Llama client created successfully")
except Exception as e:
logger.warning(f"Llama client not available: {str(e)}. Will use fallback enhancement.")
llama_client = None
use_llama = False
except Exception as e:
logger.error(f"Failed to create Hugging Face client: {str(e)}")
hf_client = None
llama_client = None
use_llama = False
# =============== DATA MODELS ===============
# Image Models with friendly names, descriptions and icons
IMAGE_MODELS = {
"stabilityai/stable-diffusion-xl-base-1.0": {
"display_name": "SDXL 1.0",
"description": "Best overall quality, slower generation",
"icon": "⭐",
"speed": "slow",
"quality": "excellent"
},
"runwayml/stable-diffusion-v1-5": {
"display_name": "SD 1.5",
"description": "Good for general purpose, faster generation",
"icon": "🚀",
"speed": "fast",
"quality": "good"
},
"stabilityai/stable-diffusion-2-1": {
"display_name": "SD 2.1",
"description": "Improved details, balanced speed and quality",
"icon": "✨",
"speed": "medium",
"quality": "very good"
},
"prompthero/openjourney": {
"display_name": "OpenJourney",
"description": "Midjourney-like stylized results",
"icon": "🎨",
"speed": "medium",
"quality": "stylized"
},
"dreamlike-art/dreamlike-diffusion-1.0": {
"display_name": "Dreamlike",
"description": "Artistic style with dreamy aesthetics",
"icon": "💫",
"speed": "medium",
"quality": "artistic"
}
}
# Creation types with icons and detailed descriptions
CREATION_TYPES = {
"Realistic Photo": {
"description": "Create a photorealistic image with natural details and lighting",
"icon": "📷",
"prompt_hint": "Try to include details about lighting, time of day, and environment"
},
"Digital Art": {
"description": "Create colorful digital artwork with clean lines and vibrant colors",
"icon": "🖌️",
"prompt_hint": "Consider specifying color palette and mood for better results"
},
"Fantasy Illustration": {
"description": "Create magical and fantastical scenes with otherworldly elements",
"icon": "🧙",
"prompt_hint": "Describe magical elements, creatures, and environments in detail"
},
"Concept Art": {
"description": "Create professional concept art for characters, environments or objects",
"icon": "🎮",
"prompt_hint": "Include details about perspective, purpose, and design influences"
},
"Anime/Manga": {
"description": "Create Japanese anime or manga style illustration",
"icon": "🍙",
"prompt_hint": "Specify anime aesthetics like shading style and character features"
},
"Oil Painting": {
"description": "Create an image with oil painting textures and artistic brushstrokes",
"icon": "🖼️",
"prompt_hint": "Consider describing texture, brushwork style, and canvas feel"
},
"Watercolor": {
"description": "Create a soft watercolor illustration with subtle color blending",
"icon": "💧",
"prompt_hint": "Mention color blending, paper texture, and watercolor-specific effects"
},
"Sketch": {
"description": "Create a detailed sketch or drawing with line art focus",
"icon": "✏️",
"prompt_hint": "Describe line weight, hatching style, and sketch medium (pencil, charcoal, etc.)"
},
"3D Rendering": {
"description": "Create an image that looks like a 3D rendered scene with realistic lighting",
"icon": "💻",
"prompt_hint": "Include details about lighting setup, materials, and camera perspective"
},
"Pixel Art": {
"description": "Create retro-style pixel art with limited color palette",
"icon": "👾",
"prompt_hint": "Specify resolution, color limitations, and pixel art style (e.g., 16-bit, 8-bit)"
}
}
# Art styles with icons and detailed descriptions
ART_STYLES = {
"Photorealistic": {
"description": "Detailed realistic style that resembles a photograph with accurate lighting and textures",
"icon": "📸",
"examples": "Works by Chuck Close, Richard Estes, or modern 3D renderings"
},
"Impressionist": {
"description": "Soft brushstrokes that capture light and atmosphere over precise details, like Monet",
"icon": "🌈",
"examples": "Claude Monet, Pierre-Auguste Renoir, Camille Pissarro"
},
"Surrealist": {
"description": "Dreamlike quality with impossible or irrational scenes, like Salvador Dali",
"icon": "🌀",
"examples": "Salvador Dali, René Magritte, Frida Kahlo"
},
"Pop Art": {
"description": "Bold colors, sharp lines and popular culture references, like Andy Warhol",
"icon": "🎭",
"examples": "Andy Warhol, Roy Lichtenstein, Keith Haring"
},
"Minimalist": {
"description": "Simplified forms, limited color palette, and clean composition with minimal elements",
"icon": "⬜",
"examples": "Piet Mondrian, Kazimir Malevich, Agnes Martin"
},
"Abstract": {
"description": "Non-representational style using shapes, colors, and forms to express ideas",
"icon": "🔶",
"examples": "Wassily Kandinsky, Jackson Pollock, Mark Rothko"
},
"Cubist": {
"description": "Geometric shapes and multiple perspectives shown simultaneously, like Picasso",
"icon": "📐",
"examples": "Pablo Picasso, Georges Braque, Juan Gris"
},
"Art Nouveau": {
"description": "Ornate, flowing lines inspired by natural forms with decorative elegance",
"icon": "🌿",
"examples": "Alphonse Mucha, Gustav Klimt, Antoni Gaudí"
},
"Gothic": {
"description": "Dark, medieval-inspired aesthetic with dramatic lighting and architectural elements",
"icon": "🏰",
"examples": "Zdzisław Beksiński, H.R. Giger, medieval architecture"
},
"Cyberpunk": {
"description": "Futuristic dystopian style with neon colors, technology, and urban decay",
"icon": "🤖",
"examples": "Blade Runner, Ghost in the Shell, Akira"
},
"Steampunk": {
"description": "Victorian-era aesthetic combined with steam-powered technology and brass elements",
"icon": "⚙️",
"examples": "Works by James Ng, Keith Thompson, retrofuturistic Jules Verne adaptations"
},
"Retro/Vintage": {
"description": "Nostalgic style reminiscent of past decades with period-appropriate elements",
"icon": "📺",
"examples": "1950s advertisements, vintage travel posters, pulp magazine covers"
},
"Art Deco": {
"description": "Geometric patterns, bold colors, and luxurious materials in a symmetrical style",
"icon": "🏢",
"examples": "Works from the 1920s-30s, Chrysler Building, Tamara de Lempicka paintings"
},
"Baroque": {
"description": "Dramatic, ornate style with rich details, contrast, and dynamic composition",
"icon": "👑",
"examples": "Caravaggio, Rembrandt, Peter Paul Rubens"
},
"Ukiyo-e": {
"description": "Traditional Japanese woodblock print style with flat areas of color and strong outlines",
"icon": "🌊",
"examples": "Hokusai's Great Wave, Hiroshige's landscapes, traditional Japanese prints"
},
"Comic Book": {
"description": "Bold outlines, bright colors, and action-oriented composition like classic comics",
"icon": "💥",
"examples": "Jack Kirby, Steve Ditko, modern Marvel/DC art styles"
},
"Psychedelic": {
"description": "Vibrant, swirling colors with abstract patterns inspired by 1960s art",
"icon": "🌈",
"examples": "1960s concert posters, Peter Max, Alex Grey"
},
"Vaporwave": {
"description": "Glitch aesthetics with pastel colors, 80s/90s nostalgia and digital elements",
"icon": "📼",
"examples": "Retrowave aesthetics, 80s digital graphics, glitch art"
},
"Studio Ghibli": {
"description": "Whimsical, detailed animation style inspired by Japanese animated films",
"icon": "🐉",
"examples": "Spirited Away, My Neighbor Totoro, Howl's Moving Castle"
},
"Hyperrealism": {
"description": "Extremely detailed realism that exceeds photograph-like precision",
"icon": "🔍",
"examples": "Works by Roberto Bernardi, Denis Peterson, Gottfried Helnwein"
}
}
# Moods with icons and descriptions
MOODS = {
"Happy": {
"description": "Bright, cheerful atmosphere with warm colors",
"icon": "😊",
"color_palette": "Warm and vibrant colors: yellows, bright oranges, light blues"
},
"Sad": {
"description": "Melancholic atmosphere with muted colors",
"icon": "😢",
"color_palette": "Muted blues, grays, desaturated colors, cool tones"
},
"Mysterious": {
"description": "Enigmatic atmosphere with shadows and hidden elements",
"icon": "🔮",
"color_palette": "Deep purples, dark blues, hints of teal, selective lighting"
},
"Peaceful": {
"description": "Serene, calm atmosphere with gentle lighting",
"icon": "🕊️",
"color_palette": "Soft blues, gentle greens, pastel colors, balanced light"
},
"Tense": {
"description": "Suspenseful atmosphere with dramatic lighting",
"icon": "😰",
"color_palette": "High contrast, dark shadows, selective reds, strong highlights"
},
"Whimsical": {
"description": "Playful, imaginative atmosphere with fanciful elements",
"icon": "🦄",
"color_palette": "Pastels, candy colors, unexpected color combinations"
},
"Dark": {
"description": "Gloomy atmosphere with deep shadows and low lighting",
"icon": "🌑",
"color_palette": "Dark blues, blacks, deep greens, minimal highlights"
},
"Energetic": {
"description": "Dynamic, vibrant atmosphere with strong colors and movement",
"icon": "⚡",
"color_palette": "Saturated primary colors, bold contrasts, vibrant hues"
},
"Romantic": {
"description": "Soft, dreamy atmosphere with warm, gentle lighting",
"icon": "❤️",
"color_palette": "Soft pinks, gentle reds, golden highlights, warm tones"
},
"Epic": {
"description": "Grand, impressive atmosphere with dramatic scale and lighting",
"icon": "🏔️",
"color_palette": "Bold colors, dramatic contrast, atmospheric lighting, expansive scale"
}
}
# Example prompts with rich metadata
EXAMPLE_PROMPTS = [
{
"text": "A serene lake at sunset with mountains in the background and a small wooden boat floating nearby",
"thumbnail_desc": "Peaceful lake scene at sunset",
"creation_type": "Realistic Photo",
"art_style": "Photorealistic",
"mood": "Peaceful",
"tags": ["nature", "landscape", "water", "sunset"]
},
{
"text": "A futuristic cityscape with flying cars, neon lights, and tall skyscrapers under a night sky with two moons",
"thumbnail_desc": "Futuristic city with flying cars",
"creation_type": "Concept Art",
"art_style": "Cyberpunk",
"mood": "Mysterious",
"tags": ["scifi", "future", "urban", "night"]
},
{
"text": "A close-up portrait of an elderly craftsman with weathered hands working on an intricate wooden carving in his workshop",
"thumbnail_desc": "Elderly craftsman working with wood",
"creation_type": "Oil Painting",
"art_style": "Hyperrealism",
"mood": "Peaceful",
"tags": ["portrait", "craftsmanship", "elderly", "detail"]
},
{
"text": "A magical forest with glowing mushrooms, fairy lights, and a small cottage with smoke coming from the chimney",
"thumbnail_desc": "Magical forest with glowing elements",
"creation_type": "Fantasy Illustration",
"art_style": "Studio Ghibli",
"mood": "Whimsical",
"tags": ["fantasy", "forest", "magic", "cottage"]
},
{
"text": "A cybernetic samurai with glowing blue circuits standing in a rainy Tokyo street at night",
"thumbnail_desc": "Cybernetic samurai in rainy Tokyo",
"creation_type": "Digital Art",
"art_style": "Cyberpunk",
"mood": "Dark",
"tags": ["character", "cyberpunk", "samurai", "rain"]
},
{
"text": "A cute cat with dragon wings and tiny horns sleeping on a pile of gold coins",
"thumbnail_desc": "Cat with dragon features on gold",
"creation_type": "Fantasy Illustration",
"art_style": "Comic Book",
"mood": "Whimsical",
"tags": ["creature", "fantasy", "cute", "treasure"]
},
{
"text": "An ancient temple covered in vines and moss, partially sunken into a crystal-clear cenote in the jungle",
"thumbnail_desc": "Ancient temple in jungle cenote",
"creation_type": "Concept Art",
"art_style": "Photorealistic",
"mood": "Mysterious",
"tags": ["architecture", "ruins", "jungle", "water"]
},
{
"text": "A cozy coffee shop interior with rain falling outside the windows, soft lighting, and a few people reading books",
"thumbnail_desc": "Cozy rainy day in coffee shop",
"creation_type": "Digital Art",
"art_style": "Impressionist",
"mood": "Peaceful",
"tags": ["interior", "rainy", "cozy", "urban"]
}
]
# CSS for enhanced UI styling - Will be included in part 2
# =============== HELPER FUNCTIONS ===============
# Helper function to format dropdown choices with icons
def format_dropdown_choices(options_dict):
return [f"{options_dict[key].get('icon', '•')} {key}" for key in options_dict.keys()]
# Helper function to extract the key from formatted choice
def extract_key(formatted_choice):
# Skip the icon and space at the beginning
parts = formatted_choice.split(' ', 1)
if len(parts) > 1:
return parts[1]
return formatted_choice
# Function to load example prompt
def load_example(example_index):
if example_index < 0 or example_index >= len(EXAMPLE_PROMPTS):
return "", "", "", ""
example = EXAMPLE_PROMPTS[example_index]
creation = f"{CREATION_TYPES[example['creation_type']]['icon']} {example['creation_type']}"
art = f"{ART_STYLES[example['art_style']]['icon']} {example['art_style']}"
mood = f"{MOODS[example['mood']]['icon']} {example['mood']}"
return example["text"], creation, art, mood
# Get model key from formatted display name
def get_model_key(formatted_name):
# Extract display name without the icon
if ' ' in formatted_name:
display_name = formatted_name.split(' ', 1)[1]
# Find the corresponding key
for key, info in IMAGE_MODELS.items():
if info['display_name'] == display_name:
return key
return list(IMAGE_MODELS.keys())[0] # Default to first model if not found
# AI Image Creator: Enhanced UI and UX
# Part 2: Enhanced UI Components and Styling
# CSS for styling the interface - Comprehensive styling for modern UI
css = """
/* Main theme colors with CSS variables for better customization */
:root {
--primary-color: #4F46E5;
--primary-hover: #4338CA;
--secondary-color: #7C3AED;
--secondary-hover: #6D28D9;
--background-color: #F8FAFC;
--card-color: #FFFFFF;
--text-color: #1E293B;
--text-muted: #64748B;
--accent-color: #3B82F6;
--success-color: #10B981;
--success-hover: #059669;
--warning-color: #F59E0B;
--error-color: #EF4444;
--error-hover: #DC2626;
--border-color: #E2E8F0;
--border-hover: #CBD5E1;
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--radius-sm: 0.375rem;
--radius: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Global styles and resets */
body, html {
font-family: var(--font-sans);
color: var(--text-color);
background-color: var(--background-color);
line-height: 1.5;
margin: 0;
padding: 0;
}
/* Container with responsive padding */
.container {
max-width: 1400px;
margin: 0 auto;
padding: 1rem;
}
@media (max-width: 640px) {
.container {
padding: 0.5rem;
}
}
/* Card styling with elevation and hover effects */
.gr-panel {
border-radius: var(--radius) !important;
border: 1px solid var(--border-color) !important;
box-shadow: var(--shadow) !important;
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
background-color: var(--card-color) !important;
}
.gr-panel:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-lg) !important;
}
/* Button styling with gradient and hover states */
button.primary {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)) !important;
color: white !important;
border: none !important;
border-radius: var(--radius) !important;
font-weight: 600 !important;
letter-spacing: 0.025em !important;
padding: 0.75rem 1.5rem !important;
transition: all 0.3s ease !important;
box-shadow: var(--shadow-sm) !important;
outline: none !important;
text-transform: none !important;
}
button.primary:hover {
transform: translateY(-1px);
box-shadow: var(--shadow) !important;
opacity: 0.9;
}
button.primary:active {
transform: translateY(0);
opacity: 0.8;
}
button.primary[disabled], button.primary[disabled]:hover {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
/* Secondary button styling */
button.secondary {
background-color: transparent !important;
color: var(--primary-color) !important;
border: 1px solid var(--primary-color) !important;
border-radius: var(--radius) !important;
font-weight: 500 !important;
padding: 0.625rem 1.25rem !important;
transition: all 0.2s ease !important;
text-transform: none !important;
}
button.secondary:hover {
background-color: rgba(79, 70, 229, 0.05) !important;
border-color: var(--primary-hover) !important;
}
/* Style for the example buttons */
.example-button {
font-size: 0.875rem !important;
padding: 0.5rem 0.75rem !important;
background-color: transparent !important;
border: 1px solid var(--border-color) !important;
border-radius: var(--radius) !important;
transition: all 0.2s !important;
text-align: left !important;
justify-content: flex-start !important;
height: auto !important;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
color: var(--text-color) !important;
}
.example-button:hover {
background-color: rgba(79, 70, 229, 0.05) !important;
border-color: var(--primary-color) !important;
transform: translateY(-1px);
}
/* Form controls styling */
.gr-input, .gr-textarea, .gr-dropdown {
border-radius: var(--radius) !important;
border: 1px solid var(--border-color) !important;
transition: border-color 0.2s, box-shadow 0.2s !important;
font-family: var(--font-sans) !important;
color: var(--text-color) !important;
}
.gr-input:focus, .gr-textarea:focus, .gr-dropdown:focus-within {
border-color: var(--primary-color) !important;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2) !important;
outline: none !important;
}
.gr-form {
gap: 1rem !important;
}
.gr-input-label, .gr-dropdown-label, .gr-textarea-label, .gr-checkbox-label, .gr-radio-label {
font-size: 0.875rem !important;
font-weight: 500 !important;
color: var(--text-color) !important;
margin-bottom: 0.25rem !important;
}
/* Input placeholder styling */
.gr-input::placeholder, .gr-textarea::placeholder {
color: var(--text-muted) !important;
opacity: 0.7;
}
/* Input and textarea styling */
textarea, input[type="text"] {
border-radius: var(--radius) !important;
border: 1px solid var(--border-color) !important;
padding: 0.75rem 1rem !important;
transition: border-color 0.2s, box-shadow 0.2s !important;
font-family: var(--font-sans) !important;
}
textarea:focus, input[type="text"]:focus {
border-color: var(--primary-color) !important;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2) !important;
outline: none !important;
}
/* Dropdown styling */
.gr-dropdown {
border-radius: var(--radius) !important;
border: 1px solid var(--border-color) !important;
background-color: var(--card-color) !important;
}
.gr-dropdown > div {
border-radius: var(--radius) !important;
min-height: 38px !important;
}
.gr-dropdown > div > span {
font-size: 0.9375rem !important;
}
/* Dropdown menu styling */
.gr-dropdown ul {
background-color: var(--card-color) !important;
border: 1px solid var(--border-color) !important;
border-radius: var(--radius) !important;
box-shadow: var(--shadow) !important;
}
.gr-dropdown ul li {
padding: 0.5rem 0.75rem !important;
}
.gr-dropdown ul li:hover {
background-color: rgba(79, 70, 229, 0.05) !important;
}
/* Custom header with gradient background */
.app-header {
text-align: center;
padding: 1.75rem 1rem;
margin-bottom: 2rem;
background: linear-gradient(135deg, rgba(79, 70, 229, 0.08), rgba(124, 58, 237, 0.08));
border-radius: var(--radius-lg);
border-bottom: 3px solid var(--primary-color);
position: relative;
overflow: hidden;
}
.app-header::before {
content: '';
position: absolute;
top: -50px;
left: -50px;
right: -50px;
height: 100px;
background: linear-gradient(135deg, rgba(79, 70, 229, 0.2), rgba(124, 58, 237, 0.2));
transform: rotate(-5deg);
z-index: 0;
}
.app-header h1 {
font-size: 2.5rem !important;
font-weight: 800 !important;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 0.5rem !important;
position: relative;
z-index: 1;
}
.app-header p {
font-size: 1.25rem !important;
color: var(--text-color);
opacity: 0.8;
max-width: 40rem;
margin: 0 auto;
position: relative;
z-index: 1;
}
/* Responsive header */
@media (max-width: 640px) {
.app-header h1 {
font-size: 2rem !important;
}
.app-header p {
font-size: 1rem !important;
}
}
/* Examples gallery with grid layout */
.example-gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 1rem;
margin: 1rem 0;
}
.example-item {
border-radius: var(--radius);
overflow: hidden;
cursor: pointer;
border: 2px solid transparent;
transition: all 0.2s;
display: flex;
flex-direction: column;
background-color: var(--card-color);
}
.example-item:hover {
transform: translateY(-2px);
border-color: var(--accent-color);
box-shadow: var(--shadow);
}
.example-item:active {
transform: translateY(0);
}
.example-item-image {
width: 100%;
aspect-ratio: 1;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-muted);
font-size: 1.5rem;
border-bottom: 1px solid var(--border-color);
}
.example-item-caption {
padding: 0.5rem;
font-size: 0.75rem;
line-height: 1.25;
color: var(--text-color);
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
/* Loading indicator with animation */
.loading-indicator {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.8);
z-index: 1000;
backdrop-filter: blur(2px);
border-radius: var(--radius);
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(79, 70, 229, 0.2);
border-radius: 50%;
border-top-color: var(--primary-color);
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Info cards with subtle styling */
.info-card {
background-color: var(--card-color);
border-radius: var(--radius);
padding: 1rem;
border: 1px solid var(--border-color);
margin-bottom: 1rem;
transition: all 0.2s;
}
.info-card:hover {
border-color: var(--border-hover);
box-shadow: var(--shadow-sm);
}
.info-card h3 {
margin-top: 0;
margin-bottom: 0.5rem;
font-size: 1rem;
font-weight: 600;
color: var(--primary-color);
display: flex;
align-items: center;
gap: 0.5rem;
}
.info-card p {
margin: 0;
font-size: 0.875rem;
color: var(--text-muted);
line-height: 1.5;
}
/* Model info panel with branded styling */
.model-info {
background-color: rgba(79, 70, 229, 0.05);
border-left: 3px solid var(--primary-color);
padding: 0.75rem 1rem;
border-radius: 0 var(--radius) var(--radius) 0;
margin: 1rem 0;
}
.model-info h3 {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0;
margin-bottom: 0.5rem;
font-size: 1rem;
font-weight: 600;
color: var(--primary-color);
}
.model-info p {
margin: 0 0 0.5rem 0;
font-size: 0.875rem;
color: var(--text-color);
}
.model-info .model-id {
font-size: 0.75rem;
color: var(--text-muted);
font-family: monospace;
background-color: rgba(0, 0, 0, 0.03);
padding: 0.25rem 0.5rem;
border-radius: 4px;
margin-top: 0.5rem;
word-break: break-all;
}
/* Parameter pills for displaying selections */
.parameter-pill {
display: inline-flex;
align-items: center;
background-color: rgba(79, 70, 229, 0.1);
color: var(--primary-color);
border-radius: 16px;
padding: 0.25rem 0.75rem;
margin-right: 0.5rem;
margin-bottom: 0.5rem;
font-size: 0.75rem;
font-weight: 500;
user-select: none;
}
.parameter-pill .icon {
margin-right: 0.25rem;
}
/* Badge for showing model speed/quality */
.badge {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 9999px;
padding: 0.125rem 0.5rem;
font-size: 0.75rem;
font-weight: 500;
margin-left: 0.5rem;
}
.badge-success {
background-color: rgba(16, 185, 129, 0.1);
color: var(--success-color);
}
.badge-warning {
background-color: rgba(245, 158, 11, 0.1);
color: var(--warning-color);
}
.badge-error {
background-color: rgba(239, 68, 68, 0.1);
color: var(--error-color);
}
.badge-info {
background-color: rgba(59, 130, 246, 0.1);
color: var(--accent-color);
}
/* Enhanced accordion styling */
.gr-accordion {
border: 1px solid var(--border-color) !important;
border-radius: var(--radius) !important;
margin-bottom: 1rem !important;
overflow: hidden;
}
.gr-accordion > div:first-child {
padding: 0.75rem 1rem !important;
background-color: rgba(0, 0, 0, 0.02) !important;
font-weight: 600 !important;
color: var(--text-color) !important;
font-size: 0.9375rem !important;
}
.gr-accordion > div:last-child {
padding: 1rem !important;
}
/* Tooltip styling */
.tooltip {
position: relative;
display: inline-block;
cursor: help;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 200px;
background-color: var(--text-color);
color: white;
text-align: center;
border-radius: var(--radius-sm);
padding: 0.5rem 0.75rem;
position: absolute;
z-index: 1000;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
opacity: 0;
transition: opacity 0.3s;
font-size: 0.75rem;
box-shadow: var(--shadow);
pointer-events: none;
}
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: var(--text-color) transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
/* History item styling */
.history-item {
display: flex;
align-items: center;
padding: 0.75rem;
border-radius: var(--radius);
margin-bottom: 0.75rem;
background-color: var(--card-color);
border: 1px solid var(--border-color);
cursor: pointer;
transition: all 0.2s;
}
.history-item:hover {
background-color: rgba(79, 70, 229, 0.05);
transform: translateY(-1px);
}
.history-item-image {
width: 48px;
height: 48px;
border-radius: var(--radius-sm);
object-fit: cover;
margin-right: 0.75rem;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-muted);
font-size: 1.25rem;
}
.history-item-content {
flex: 1;
overflow: hidden;
}
.history-item-title {
margin: 0;
font-size: 0.875rem;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--text-color);
}
.history-item-subtitle {
margin: 0;
font-size: 0.75rem;
color: var(--text-muted);
margin-top: 0.25rem;
}
/* Tabs styling */
.tabs {
display: flex;
border-bottom: 1px solid var(--border-color);
margin-bottom: 1rem;
}
.tab {
padding: 0.75rem 1rem;
cursor: pointer;
border-bottom: 2px solid transparent;
font-weight: 500;
font-size: 0.9375rem;
color: var(--text-muted);
transition: all 0.2s;
}
.tab:hover {
color: var(--primary-color);
}
.tab.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
/* Progress bar */
.progress-container {
width: 100%;
height: 8px;
background-color: rgba(79, 70, 229, 0.1);
border-radius: 4px;
overflow: hidden;
margin: 0.5rem 0;
}
.progress-bar {
height: 100%;
background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
width: 0%;
transition: width 0.3s ease;
border-radius: 4px;
}
/* Image output container */
.image-output-container {
position: relative;
border-radius: var(--radius);
overflow: hidden;
transition: all 0.2s;
background-color: #f5f5f5;
min-height: 300px;
}
.image-output-container img {
width: 100%;
display: block;
border-radius: var(--radius);
}
.image-placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: var(--text-muted);
font-size: 1rem;
text-align: center;
padding: 1rem;
}
.image-placeholder .icon {
font-size: 3rem;
margin-bottom: 1rem;
opacity: 0.6;
}
/* Image controls overlay */
.image-controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 0.75rem;
background: linear-gradient(to top, rgba(0,0,0,0.7), rgba(0,0,0,0));
display: flex;
justify-content: flex-end;
opacity: 0;
transition: opacity 0.2s;
}
.image-output-container:hover .image-controls {
opacity: 1;
}
.image-control-button {
background-color: rgba(255, 255, 255, 0.9);
border: none;
border-radius: 50%;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin-left: 0.5rem;
color: var(--text-color);
transition: all 0.2s;
}
.image-control-button:hover {
background-color: white;
transform: translateY(-2px);
box-shadow: var(--shadow);
}
/* Character counter */
.character-counter {
text-align: right;
font-size: 0.75rem;
color: var(--text-muted);
margin-top: 0.25rem;
transition: color 0.2s;
}
.character-counter.warning {
color: var(--warning-color);
}
.character-counter.error {
color: var(--error-color);
}
/* Status message */
.status-message {
padding: 0.75rem 1rem;
border-radius: var(--radius);
margin: 1rem 0;
font-size: 0.875rem;
display: flex;
align-items: center;
}
.status-message .icon {
margin-right: 0.75rem;
font-size: 1.25rem;
}
.status-success {
background-color: rgba(16, 185, 129, 0.1);
color: var(--success-color);
border-left: 3px solid var(--success-color);
}
.status-error {
background-color: rgba(239, 68, 68, 0.1);
color: var(--error-color);
border-left: 3px solid var(--error-color);
}
.status-warning {
background-color: rgba(245, 158, 11, 0.1);
color: var(--warning-color);
border-left: 3px solid var(--warning-color);
}
.status-info {
background-color: rgba(59, 130, 246, 0.1);
color: var(--accent-color);
border-left: 3px solid var(--accent-color);
}
/* Responsive adjustments */
@media (max-width: 768px) {
.example-gallery {
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
}
.gr-panel {
padding: 0.75rem !important;
}
.gr-accordion > div:first-child {
padding: 0.625rem 0.75rem !important;
}
.gr-accordion > div:last-child {
padding: 0.75rem !important;
}
button.primary {
padding: 0.625rem 1.25rem !important;
}
}
"""
# =============== ENHANCED UI COMPONENTS ===============
# Function to create and show application UI
def create_ui():
with gr.Blocks(title="", css=css) as interface:
# Custom header with branding
with gr.Row(elem_classes="app-header"):
with gr.Column():
gr.HTML("""
<h1>✨Memory Magic Studio</h1>
<p>Capture the magic of your imagination and watch it come to life.🪄</p>
""")
# Main content area
with gr.Row(equal_height=False):
# Left column - Input controls
with gr.Column(scale=1, min_width=380):
# Description input with character counter
with gr.Group(elem_classes="input-group"):
description_input = gr.Textbox(
label="Describe what you want to see",
placeholder="Be detailed and specific about colors, composition, lighting, and subject...",
lines=4,
max_lines=8,
elem_id="description-input"
)
# Character counter with dynamic updates
char_counter = gr.HTML(
value="<div class='character-counter'>0 characters</div>",
elem_classes="char-counter-container"
)
# Creation settings with enhanced dropdowns
with gr.Group(elem_classes="settings-group"):
gr.HTML("<h3 style='margin-top: 0; font-size: 1rem; margin-bottom: 0.75rem;'>🛠️ Image Settings</h3>")
# Creation Type and Art Style in one row
with gr.Row():
# Creation type dropdown with icons
creation_type = gr.Dropdown(
choices=format_dropdown_choices(CREATION_TYPES),
value=f"{CREATION_TYPES['Digital Art']['icon']} Digital Art",
label="Creation Type",
elem_classes="enhanced-dropdown"
)
# Art style dropdown with icons
art_style = gr.Dropdown(
choices=format_dropdown_choices(ART_STYLES),
value=f"{ART_STYLES['Photorealistic']['icon']} Photorealistic",
label="Art Style",
elem_classes="enhanced-dropdown"
)
# Mood and Model in one row
with gr.Row():
# Mood dropdown with icons
mood_dropdown = gr.Dropdown(
choices=format_dropdown_choices(MOODS),
value=f"{MOODS['Peaceful']['icon']} Peaceful",
label="Mood",
elem_classes="enhanced-dropdown"
)
# Model selector with display names
formatted_models = [f"{info['icon']} {info['display_name']}" for model_key, info in IMAGE_MODELS.items()]
model_selector = gr.Dropdown(
choices=formatted_models,
value=f"{IMAGE_MODELS['stabilityai/stable-diffusion-xl-base-1.0']['icon']} {IMAGE_MODELS['stabilityai/stable-diffusion-xl-base-1.0']['display_name']}",
label="Model",
elem_classes="enhanced-dropdown"
)
# Examples gallery with clear visual structure
with gr.Group(elem_classes="examples-group"):
gr.HTML("<h3 style='margin-top: 0; font-size: 1rem; margin-bottom: 0.75rem;'>🌟 Try an example:</h3>")
# Gallery of examples
with gr.Row(elem_classes="example-gallery"):
for i, example in enumerate(EXAMPLE_PROMPTS):
with gr.Column(elem_classes="example-item"):
# Example card with visual element and caption
example_card = gr.Button(
example["thumbnail_desc"],
elem_classes="example-button"
)
# Event handler for example selection
example_card.click(
fn=lambda idx=i: load_example(idx),
outputs=[description_input, creation_type, art_style, mood_dropdown]
)
# Information panels for selected options
with gr.Group(elem_classes="info-panels"):
# Creation type info
creation_info = gr.HTML(value="", elem_classes="option-info")
# Art style info
art_info = gr.HTML(value="", elem_classes="option-info")
# Model info panel
model_info = gr.HTML(value="", elem_classes="option-info")
# Generate button with clear call to action
with gr.Group(elem_classes="action-group"):
# Generate button with progress indicator
generate_button = gr.Button(
"✨ Generate Image",
variant="primary",
elem_classes="primary",
elem_id="generate-button"
)
# Generation status message
generation_status = gr.HTML(value="", elem_classes="generation-status")
# Tips section in collapsible accordion
with gr.Accordion("📝 Tips for better results", open=True):
gr.HTML("""
<div class="tips-container">
<h3>Tips for better results:</h3>
<ul>
<li><strong>Be specific and detailed</strong> - Include information about subjects, environment, lighting, colors, perspective, time of day, etc.</li>
<li><strong>Use descriptive adjectives</strong> - Words like "vibrant", "moody", "ethereal", "weathered" help set the tone.</li>
<li><strong>Experiment with art styles</strong> - Different styles can dramatically change the look and feel.</li>
<li><strong>Combine with the right model</strong> - SDXL provides the highest quality but takes longer.</li>
<li><strong>Think about composition</strong> - Mention foreground/background elements and their relationships.</li>
</ul>
</div>
""")
# Right column - Output display
with gr.Column(scale=1, min_width=480):
# Image display area with placeholder
with gr.Group(elem_classes="output-container"):
# Output image with interactive elements
image_output = gr.Image(
label="Generated Image",
elem_id="image-output",
type="pil",
height=512
)
# Image generation details
with gr.Accordion("Image Details", open=True):
parameters_display = gr.HTML(value="")
# Enhanced prompt display
with gr.Accordion("Enhanced Prompt", open=False):
prompt_output = gr.Textbox(
label="AI-Enhanced Prompt Used",
lines=5,
elem_id="prompt-output",
elem_classes="prompt-display"
)
# Technical details for advanced users
with gr.Accordion("Technical Details", open=False):
technical_info = gr.HTML("""
<div class="technical-info">
<h4>How Image Generation Works</h4>
<p>Images are generated using Stable Diffusion, a latent text-to-image diffusion model. Your text prompt is:
<ol>
<li>Enhanced with AI to add descriptive details and quality terms</li>
<li>Processed through a neural network that gradually transforms random noise into an image</li>
<li>Refined based on the parameters you select (model, style, mood)</li>
</ol>
</p>
<p>Different models have different strengths:
<ul>
<li><strong>SDXL 1.0</strong>: Highest quality, best composition and details</li>
<li><strong>SD 1.5</strong>: Faster generation, good for general purpose</li>
<li><strong>SD 2.1</strong>: Better with human faces, improved consistency</li>
<li><strong>OpenJourney</strong>: Midjourney-like stylized artistic results</li>
<li><strong>Dreamlike</strong>: Dreamy, ethereal aesthetic with artistic flair</li>
</ul>
</p>
</div>
""")
# Set up event handlers within the Blocks context
description_input.change(
fn=update_char_count,
inputs=description_input,
outputs=char_counter
)
creation_type.change(
fn=update_creation_info,
inputs=creation_type,
outputs=creation_info
)
art_style.change(
fn=update_art_style_info,
inputs=art_style,
outputs=art_info
)
model_selector.change(
fn=update_model_info,
inputs=model_selector,
outputs=model_info
)
generate_button.click(
fn=generate_with_status,
inputs=[
description_input,
creation_type,
art_style,
mood_dropdown,
model_selector
],
outputs=[
image_output,
generation_status,
prompt_output,
parameters_display
]
)
# Load default values on page load
interface.load(
fn=lambda: (
update_creation_info(f"{CREATION_TYPES['Digital Art']['icon']} Digital Art"),
update_art_style_info(f"{ART_STYLES['Photorealistic']['icon']} Photorealistic"),
update_model_info(f"{IMAGE_MODELS['stabilityai/stable-diffusion-xl-base-1.0']['icon']} {IMAGE_MODELS['stabilityai/stable-diffusion-xl-base-1.0']['display_name']}")
),
outputs=[creation_info, art_info, model_info]
)
return interface, description_input, creation_type, art_style, mood_dropdown, model_selector, generate_button, image_output, generation_status, prompt_output, parameters_display, char_counter, creation_info, art_info, model_info
# Helper function to update character count with color coding
def update_char_count(text):
count = len(text)
if count == 0:
color_class = ""
elif count < 20:
color_class = "warning"
elif count > 300:
color_class = "warning"
elif count > 500:
color_class = "error"
else:
color_class = ""
return f"<div class='character-counter {color_class}'>{count} characters</div>"
# Helper function to update creation type info
def update_creation_info(choice):
key = extract_key(choice)
if key in CREATION_TYPES:
info = CREATION_TYPES[key]
return f"""<div class="info-card">
<h3>{info['icon']} {key}</h3>
<p>{info['description']}</p>
<p style="margin-top: 0.5rem; font-style: italic; opacity: 0.8;">💡 {info['prompt_hint']}</p>
</div>"""
return ""
# Helper function to update art style info
def update_art_style_info(choice):
key = extract_key(choice)
if key in ART_STYLES:
info = ART_STYLES[key]
return f"""<div class="info-card">
<h3>{info['icon']} {key}</h3>
<p>{info['description']}</p>
<p style="margin-top: 0.5rem; font-style: italic; opacity: 0.8;">🎨 Examples: {info['examples']}</p>
</div>"""
return ""
# Helper function to update model info
def update_model_info(formatted_choice):
# Extract display name without the icon
if ' ' in formatted_choice:
display_name = formatted_choice.split(' ', 1)[1]
# Find the corresponding key and info
for key, info in IMAGE_MODELS.items():
if info['display_name'] == display_name:
# Create speed badge
speed_badge = ""
if info.get('speed') == 'fast':
speed_badge = '<span class="badge badge-success">Fast</span>'
elif info.get('speed') == 'medium':
speed_badge = '<span class="badge badge-warning">Medium</span>'
elif info.get('speed') == 'slow':
speed_badge = '<span class="badge badge-error">Slower</span>'
# Create quality badge
quality_badge = ""
if info.get('quality') == 'excellent':
quality_badge = '<span class="badge badge-success">Excellent Quality</span>'
elif info.get('quality') == 'very good':
quality_badge = '<span class="badge badge-success">Very Good Quality</span>'
elif info.get('quality') == 'good':
quality_badge = '<span class="badge badge-info">Good Quality</span>'
elif info.get('quality') == 'stylized':
quality_badge = '<span class="badge badge-info">Stylized</span>'
elif info.get('quality') == 'artistic':
quality_badge = '<span class="badge badge-info">Artistic</span>'
return f"""<div class="model-info">
<h3>{info['icon']} {info['display_name']} {speed_badge} {quality_badge}</h3>
<p>{info['description']}</p>
<div class="model-id">{key}</div>
</div>"""
return ""
# Helper function to update status message
def update_status(message, is_error=False, is_warning=False, is_info=False):
if is_error:
status_class = "status-error"
icon = "❌"
elif is_warning:
status_class = "status-warning"
icon = "⚠️"
elif is_info:
status_class = "status-info"
icon = "ℹ️"
else:
status_class = "status-success"
icon = "✅"
return f"""<div class="status-message {status_class}">
<span class="icon">{icon}</span>
<span>{message}</span>
</div>"""
# Helper function to format parameters display as pills
def format_parameters(creation_type_val, art_style_val, mood_val, model_name):
creation_key = extract_key(creation_type_val)
art_key = extract_key(art_style_val)
mood_key = extract_key(mood_val)
# Get model info
model_display_name = "Unknown Model"
model_id = ""
model_icon = "🤖"
for key, info in IMAGE_MODELS.items():
if f"{info['icon']} {info['display_name']}" == model_name:
model_display_name = info['display_name']
model_id = key
model_icon = info['icon']
break
html = """<div style="margin-bottom: 1rem;">
<div style="font-weight: 500; margin-bottom: 0.75rem;">Generated with these parameters:</div>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">"""
# Add creation type pill
if creation_key in CREATION_TYPES:
html += f"""<div class="parameter-pill">
<span class="icon">{CREATION_TYPES[creation_key]['icon']}</span> {creation_key}
</div>"""
# Add art style pill
if art_key in ART_STYLES:
html += f"""<div class="parameter-pill">
<span class="icon">{ART_STYLES[art_key]['icon']}</span> {art_key}
</div>"""
# Add mood pill
if mood_key in MOODS:
html += f"""<div class="parameter-pill">
<span class="icon">{MOODS[mood_key]['icon']}</span> {mood_key}
</div>"""
# Add model pill
html += f"""<div class="parameter-pill">
<span class="icon">{model_icon}</span> {model_display_name}
</div>"""
# Close container
html += """</div>
<div style="margin-top: 1rem; font-size: 0.75rem; color: var(--text-muted);">
Image generated on {timestamp}
</div>
</div>""".replace("{timestamp}", time.strftime("%Y-%m-%d at %H:%M:%S"))
return html
# AI Image Creator: Enhanced UI and UX
# Part 3: Processing Logic, Prompt Enhancement, and Application Flow
# =============== PROMPT ENHANCEMENT LOGIC ===============
# Function to enhance prompt with Llama 4 with improved logical understanding
def enhance_prompt_with_llama(user_input, creation_type, art_style, mood):
"""
Enhance user input with Llama 4 model to create detailed image generation prompts
Args:
user_input (str): User's original description
creation_type (str): Selected creation type (e.g., "Digital Art")
art_style (str): Selected art style (e.g., "Photorealistic")
mood (str): Selected mood (e.g., "Peaceful")
Returns:
str: Enhanced prompt optimized for image generation
"""
try:
if not use_llama or llama_client is None:
logger.warning("Llama enhancement not available, using fallback")
return enhance_prompt_fallback(user_input, creation_type, art_style, mood)
logger.info(f"Enhancing prompt with Llama 4 for creation type: {creation_type}, art style: {art_style}")
# Enhanced Llama 4 system prompt with detailed instructions
system_prompt = """You are a world-class prompt engineer who specializes in creating detailed, effective prompts for text-to-image AI models.
Your task is to transform a user's simple description into a comprehensive, detailed image generation prompt that will create stunning visuals. Consider all the provided elements (description, creation type, art style, mood) and combine them into a cohesive, detailed prompt.
MOST IMPORTANTLY - ADD LOGICAL DETAILS:
- Analyze what the user wants and add logical details that would make the scene realistic or coherent
- If describing something fantastical (e.g., "flying cat"), add logical details about how this could work (e.g., "a cat with majestic feathered wings spread wide")
- Think about environment, lighting, perspective, time of day, weather, and other contextual elements
- Create a vivid, imaginable scene with spatial relationships clearly defined
PROMPT STRUCTURE GUIDELINES:
1. Start with the core subject and its primary characteristics
2. Add environment and setting details
3. Describe lighting, atmosphere, and mood
4. Include specific visual style and artistic technique references
5. Add technical quality terms (8K, detailed, masterful, etc.)
FORMAT YOUR RESPONSE AS A SINGLE PARAGRAPH with no additional comments, explanations, or bullet points. Use natural language without awkward comma separations. Aim for 75-150 words.
AVOID:
- Do not include quotation marks in your response
- Do not preface with "here's a prompt" or similar text
- Do not use placeholders
- Do not add negative prompts
- Do not write in list format or use bullet points
Respond only with the enhanced prompt and nothing else."""
# Get creation type description
creation_info = CREATION_TYPES.get(creation_type, {"description": "Create a detailed image", "icon": "🎨"})
creation_description = creation_info["description"]
# Get art style description
style_info = ART_STYLES.get(art_style, {"description": "with detailed and professional quality", "icon": "🖌️"})
style_description = style_info["description"]
# Get mood description
mood_info = MOODS.get(mood, {"description": "atmospheric", "icon": "✨"})
mood_description = mood_info["description"]
# Prepare the user prompt for Llama
user_prompt = f"""Description: {user_input}
Creation Type: {creation_type} - {creation_description}
Art Style: {art_style} - {style_description}
Mood: {mood} - {mood_description}
Please create a comprehensive, detailed image generation prompt that combines all these elements."""
try:
# Request enhancement from Llama 4
completion = llama_client.chat.completions.create(
model="meta-llama/Llama-4-Scout-17B-16E-Instruct",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
max_tokens=500,
temperature=0.7, # Slight creativity while maintaining coherence
)
enhanced = completion.choices[0].message.content
logger.info(f"Llama 4 enhanced prompt: {enhanced[:100]}...")
return enhanced if enhanced else user_input
except Exception as e:
logger.error(f"Error during Llama enhancement: {str(e)}")
return enhance_prompt_fallback(user_input, creation_type, art_style, mood)
except Exception as e:
logger.error(f"Error in Llama enhancement: {str(e)}")
return enhance_prompt_fallback(user_input, creation_type, art_style, mood)
# Fallback prompt enhancement without Llama
def enhance_prompt_fallback(user_input, creation_type, art_style, mood):
"""
Enhance user input without requiring Llama API using rule-based enhancement
Args:
user_input (str): User's original description
creation_type (str): Selected creation type (e.g., "Digital Art")
art_style (str): Selected art style (e.g., "Photorealistic")
mood (str): Selected mood (e.g., "Peaceful")
Returns:
str: Enhanced prompt using predefined rules and templates
"""
logger.info(f"Using fallback enhancement for: {user_input[:50]}...")
# Quality terms by creation type
quality_terms = {
"Realistic Photo": [
"photorealistic", "high resolution", "detailed",
"natural lighting", "sharp focus", "professional photography",
"crisp details", "realistic textures", "DSLR photo"
],
"Digital Art": [
"vibrant colors", "clean lines", "digital illustration",
"polished", "professional digital art", "detailed rendering",
"digital painting", "colorful", "vector-like precision"
],
"Fantasy Illustration": [
"magical atmosphere", "fantasy art", "detailed illustration",
"epic", "otherworldly", "imaginative scene",
"fantasy environment", "magical lighting", "mythical qualities"
],
"Concept Art": [
"professional concept art", "detailed design", "conceptual illustration",
"industry standard", "visual development", "production artwork",
"concept design", "detailed environment", "character design"
],
"Anime/Manga": [
"anime style", "manga illustration", "cel shaded",
"Japanese animation", "2D character art", "anime aesthetic",
"clean linework", "anime proportions", "stylized features"
],
"Oil Painting": [
"oil on canvas", "textured brushwork", "rich colors",
"traditional painting", "artistic brushstrokes", "gallery quality",
"glazed layers", "impasto technique", "classical painting style"
],
"Watercolor": [
"watercolor painting", "soft color bleeding", "delicate washes",
"transparent layers", "loose brushwork", "gentle transitions",
"watercolor paper texture", "wet-on-wet technique", "fluid color blending"
],
"Sketch": [
"detailed sketch", "pencil drawing", "line art",
"hand-drawn", "fine details", "shading techniques",
"graphite", "charcoal texture", "gestural lines"
],
"3D Rendering": [
"3D render", "volumetric lighting", "ray tracing",
"3D modeling", "realistic textures", "computer graphics",
"physically based rendering", "global illumination", "ambient occlusion"
],
"Pixel Art": [
"pixel art", "8-bit style", "retro game aesthetic",
"limited color palette", "pixelated", "nostalgic game art",
"16-bit look", "pixel perfect", "dithering effects"
]
}
# Style modifiers for different art styles - more detailed descriptions
style_modifiers = {
"Photorealistic": "highly detailed photorealistic style with perfect lighting, natural shadows, and lifelike textures",
"Impressionist": "impressionist style with visible brushstrokes capturing light and atmosphere over precise details, reminiscent of Claude Monet",
"Surrealist": "surrealist style with dreamlike and impossible elements, juxtaposed reality, inspired by Salvador Dali",
"Pop Art": "pop art style with bold colors, sharp lines, halftone patterns and cultural references, like Andy Warhol",
"Minimalist": "minimalist style with simplified forms, limited color palette, clean composition, and essential elements only",
"Abstract": "abstract style using non-representational shapes, colors, and forms to express emotion rather than reality",
"Cubist": "cubist style with geometric forms, multiple perspectives shown simultaneously, fractured surfaces, like Pablo Picasso",
"Art Nouveau": "art nouveau style with ornate flowing lines inspired by natural forms, decorative elegance, and organic shapes",
"Gothic": "gothic style with dark atmosphere, dramatic elements, pointed arches, and medieval-inspired architecture",
"Cyberpunk": "cyberpunk style with neon colors, high tech low life aesthetic, futuristic technology, and urban decay",
"Steampunk": "steampunk style with Victorian aesthetics, brass machinery, steam-powered technology, and retrofuturistic design",
"Retro/Vintage": "retro style with nostalgic elements from past decades, aged texture, and period-appropriate colors and design",
"Art Deco": "art deco style with geometric patterns, bold colors, symmetry, luxurious materials, and streamlined forms",
"Baroque": "baroque style with dramatic lighting, rich details, contrast, dynamic composition, and ornate decorations",
"Ukiyo-e": "ukiyo-e style Japanese woodblock print aesthetic with flat areas of color, strong outlines, and traditional subjects",
"Comic Book": "comic book style with bold outlines, vibrant colors, dynamic action poses, and expressive characters",
"Psychedelic": "psychedelic style with vibrant swirling colors, abstract patterns, distorted perspective, and 1960s-inspired visuals",
"Vaporwave": "vaporwave aesthetic with glitch art, pastel colors, 80s/90s nostalgia, ancient statues, and digital elements",
"Studio Ghibli": "Studio Ghibli anime style with whimsical detailed environments, soft colors, and charming character design",
"Hyperrealism": "hyperrealistic style with extreme detail beyond photography, perfect textures, and meticulous precision"
}
# Mood modifiers for different moods - enhanced descriptions
mood_modifiers = {
"Happy": "bright cheerful atmosphere with warm golden lighting, vibrant colors, and uplifting elements",
"Sad": "melancholic atmosphere with muted colors, soft shadows, and somber emotional tone",
"Mysterious": "enigmatic atmosphere with shadows, fog, hidden elements, and dramatic lighting contrasts",
"Peaceful": "serene calm atmosphere with gentle lighting, soft colors, and tranquil composition",
"Tense": "suspenseful atmosphere with dramatic lighting, stark contrasts, and unsettling composition",
"Whimsical": "playful whimsical atmosphere with imaginative elements, saturated colors, and fantastical details",
"Dark": "dark gloomy atmosphere with deep shadows, limited lighting, and ominous elements",
"Energetic": "dynamic vibrant atmosphere with strong colors, motion effects, and active composition",
"Romantic": "soft romantic atmosphere with dreamy lighting, gentle colors, and intimate ambiance",
"Epic": "grand epic atmosphere with dramatic scale, sweeping vistas, and majestic lighting"
}
# Get terms for the specific creation type, or use generic terms
type_terms = quality_terms.get(creation_type, [
"high quality", "detailed", "professional", "masterful", "high resolution", "sharp details"
])
# Common quality terms enhanced with trending and technical terms
common_terms = [
"8K resolution", "highly detailed", "professional", "masterpiece",
"trending on artstation", "award winning", "stunning", "intricate details",
"perfect composition", "cinematic lighting"
]
# Get style modifier
style_modifier = style_modifiers.get(art_style, "detailed professional style")
# Get mood modifier
mood_modifier = mood_modifiers.get(mood, "atmospheric")
# Basic prompt structure - core subject and style elements
prompt_parts = [
user_input,
style_modifier,
mood_modifier
]
# Add randomly selected quality terms for variety
selected_type_terms = random.sample(type_terms, min(3, len(type_terms)))
selected_common_terms = random.sample(common_terms, min(3, len(common_terms)))
# Combine terms
quality_description = ", ".join(selected_type_terms + selected_common_terms)
# Final enhanced prompt
enhanced_prompt = f"{', '.join(prompt_parts)}, {quality_description}"
logger.info(f"Fallback enhanced prompt: {enhanced_prompt[:100]}...")
return enhanced_prompt
# =============== IMAGE GENERATION FUNCTIONS ===============
# Generate image function with loading state handling and retry mechanism
def generate_image(description, creation_type, art_style, mood, model_name, retries=1):
"""
Generate image based on user inputs by enhancing prompt and calling image model API
Args:
description (str): User's original description
creation_type (str): Selected creation type
art_style (str): Selected art style
mood (str): Selected mood
model_name (str): Model identifier
retries (int): Number of retries if generation fails
Returns:
tuple: (image, status_message, enhanced_prompt)
"""
try:
# Validate input
if not description.strip():
return None, "Please enter a description for your image", ""
logger.info(f"Generating image with model: {model_name}")
# Enhance prompt with Llama or fallback
enhanced_prompt = enhance_prompt_with_llama(description, creation_type, art_style, mood)
# Validate client availability
if hf_client is None:
logger.error("Hugging Face client not available")
return None, "Error: Unable to connect to image generation service. Please try again later.", enhanced_prompt
# Add negative prompt to avoid common issues
negative_prompt = "low quality, blurry, distorted, deformed, disfigured, bad anatomy, watermark, signature, text, poorly drawn, amateur, ugly"
try:
# Generate image with progress tracking
logger.info(f"Sending request to model {model_name} with prompt: {enhanced_prompt[:100]}...")
# Log start time for performance tracking
start_time = time.time()
# Generate the image
image = hf_client.text_to_image(
prompt=enhanced_prompt,
model=model_name,
negative_prompt=negative_prompt
)
# Calculate generation time
generation_time = time.time() - start_time
logger.info(f"Image generated successfully in {generation_time:.2f} seconds")
# Success message with generation details
if use_llama:
enhancement_method = "Llama 4 AI"
else:
enhancement_method = "rule-based enhancement"
success_message = f"Image created successfully in {generation_time:.1f}s using {model_name.split('/')[-1]} model and {enhancement_method}"
return image, success_message, enhanced_prompt
except Exception as e:
error_message = str(e)
logger.error(f"Error during image generation: {error_message}")
# Retry logic for transient errors
if retries > 0:
logger.info(f"Retrying image generation, {retries} attempts remaining")
time.sleep(1) # Small delay before retry
return generate_image(description, creation_type, art_style, mood, model_name, retries - 1)
# Format user-friendly error message
if "429" in error_message:
friendly_error = "Server is currently busy. Please try again in a few moments."
elif "401" in error_message or "403" in error_message:
friendly_error = "Authentication error with the image service. Please check API settings."
elif "timeout" in error_message.lower():
friendly_error = "Request timed out. The server might be under heavy load."
else:
friendly_error = f"Error generating image: {error_message}"
return None, friendly_error, enhanced_prompt
except Exception as e:
logger.error(f"Unexpected error in generate_image: {str(e)}")
return None, f"Unexpected error: {str(e)}", ""
# Wrapper function for generate_image with status updates
def generate_with_status(description, creation_type_val, art_style_val, mood_val, model_name):
"""
Wrapper for generate_image that handles UI status updates and parameter formatting
Args:
description (str): User's original description
creation_type_val (str): Formatted creation type with icon
art_style_val (str): Formatted art style with icon
mood_val (str): Formatted mood with icon
model_name (str): Formatted model name with icon
Returns:
tuple: (image, status_html, enhanced_prompt, parameters_html)
"""
# Check if description is empty
if not description.strip():
return None, update_status("Please enter a description", is_error=True), "", ""
# Extract keys from formatted values
creation_key = extract_key(creation_type_val)
art_key = extract_key(art_style_val)
mood_key = extract_key(mood_val)
# Get model key from formatted name
model_key = None
for key, info in IMAGE_MODELS.items():
if f"{info['icon']} {info['display_name']}" == model_name:
model_key = key
break
if not model_key:
return None, update_status("Invalid model selection", is_error=True), "", ""
try:
# Generate the image
image, message, enhanced_prompt = generate_image(
description, creation_key, art_key, mood_key, model_key
)
if image is None:
return None, update_status(message, is_error=True), "", ""
# Format parameters display
params_html = format_parameters(creation_type_val, art_style_val, mood_val, model_name)
# Success message
success_message = update_status(message)
return image, success_message, enhanced_prompt, params_html
except Exception as e:
error_message = str(e)
logger.error(f"Error in generate_with_status: {error_message}")
return None, update_status(f"Error: {error_message}", is_error=True), "", ""
# =============== MAIN APPLICATION FLOW ===============
def main():
"""
Main application entry point - creates UI and sets up event handlers
"""
# Create the UI components - event handlers are now defined inside create_ui
interface, *_ = create_ui()
# Launch the interface with appropriate parameters for Gradio version
# Check Gradio version to decide on the correct parameters to use
try:
# Use simple parameters that work across versions
interface.launch(
share=False, # Set to True to create a public link
debug=False # Set to True for development
)
except Exception as e:
logger.error(f"Error launching Gradio interface: {str(e)}")
# Fallback to the most basic launch parameters
interface.launch()
# =============== APP EXECUTION ===============
if __name__ == "__main__":
# Start the application
main()