import gradio as gr import logging import sys import random import time import os import json import uuid import base64 from datetime import datetime from huggingface_hub import InferenceClient from PIL import Image, ImageOps, ImageEnhance, ImageFilter import io import math import hashlib import tempfile import re import numpy as np from pathlib import Path # =============== SETUP LOGGING =============== logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[logging.StreamHandler(sys.stdout)] ) logger = logging.getLogger("imaginova") # =============== APP CONFIGURATION =============== APP_CONFIG = { "name": "Imaginova", "tagline": "Where Imagination Becomes Reality", "version": "3.0.0", "description": "Create magnificent AI-generated artwork from your imagination", "max_history": 50, # Maximum number of images to store in history "cache_enabled": True, # Enable caching to improve performance "enable_analytics": False, # Anonymous usage statistics "default_theme": "auto", # Default theme (light, dark, or auto) "huggingface_space": True, # Running in HF Spaces environment "enable_guided_creation": True, # Enable guided creative mode "max_batch_size": 4, # Maximum images in batch generation "enable_image_editing": True, # Enable image editing features "data_dir": "imaginova_data", # Directory to store persistent data } # Create data directory if it doesn't exist os.makedirs(APP_CONFIG["data_dir"], exist_ok=True) # =============== MODEL CLIENTS SETUP =============== def setup_client(api_key=None, 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: # For Hugging Face Spaces, we can use the internal API if APP_CONFIG["huggingface_space"]: # In Hugging Face Spaces, no API key is needed hf_client = InferenceClient() logger.info("Hugging Face client created successfully in Spaces environment") else: # Replace with your actual HF API key for local development hf_api_key = os.getenv("HF_API_KEY", None) hf_client = setup_client(hf_api_key) logger.info("Hugging Face client created successfully") # Set up prompt enhancer client if API key is provided enhancer_api_key = os.getenv("ENHANCER_API_KEY", None) try: enhancer_client = setup_client(enhancer_api_key, "text-generation") use_ai_enhancer = True logger.info("Prompt enhancer client created successfully") except Exception as e: logger.warning(f"Prompt enhancer not available: {str(e)}. Will use fallback enhancement.") enhancer_client = None use_ai_enhancer = False except Exception as e: logger.error(f"Failed to create Hugging Face client: {str(e)}") hf_client = None enhancer_client = None use_ai_enhancer = False # =============== DATA MODELS =============== # Image Models with friendly names, descriptions and icons IMAGE_MODELS = { "stabilityai/stable-diffusion-xl-base-1.0": { "display_name": "Nova XL", "description": "Premium quality with exceptional detail and composition", "icon": "โญ", "speed": "slow", "quality": "excellent", "strengths": "Composition, detail, realism", "weaknesses": "Generation time, resource intensive", "category": "premium", "recommended_for": ["portraits", "landscapes", "detailed scenes", "professional work"] }, "runwayml/stable-diffusion-v1-5": { "display_name": "Nova Fast", "description": "Quick generation with good all-around results", "icon": "๐Ÿš€", "speed": "fast", "quality": "good", "strengths": "Speed, versatility, community support", "weaknesses": "Less sophisticated than Nova XL", "category": "standard", "recommended_for": ["quick sketches", "iterations", "simpler scenes"] }, "stabilityai/stable-diffusion-2-1": { "display_name": "Nova Balance", "description": "Balanced approach between speed and quality", "icon": "โœจ", "speed": "medium", "quality": "very good", "strengths": "Human faces, consistency, balanced", "weaknesses": "Less stylistic range than Nova Fast", "category": "standard", "recommended_for": ["portraits", "consistent style", "balanced workflow"] }, "prompthero/openjourney": { "display_name": "Nova Art", "description": "Stylized artistic results with vibrant imagination", "icon": "๐ŸŽจ", "speed": "medium", "quality": "stylized", "strengths": "Artistic style, vibrant colors", "weaknesses": "Less photorealistic, inconsistent faces", "category": "specialized", "recommended_for": ["creative artworks", "stylized illustrations", "fantasy concepts"] }, "dreamlike-art/dreamlike-diffusion-1.0": { "display_name": "Nova Dream", "description": "Dreamy, ethereal aesthetics with artistic flair", "icon": "๐Ÿ’ซ", "speed": "medium", "quality": "artistic", "strengths": "Dreamy atmospheres, artistic flair", "weaknesses": "Less precise control, abstract results", "category": "specialized", "recommended_for": ["dreamy scenes", "abstract concepts", "atmospheric images"] }, "cjwbw/anything-v3-better-vae": { "display_name": "Nova Anime", "description": "Specialized for anime and illustration styles", "icon": "๐Ÿ™", "speed": "fast", "quality": "specialized", "strengths": "Anime style, illustrations, characters", "weaknesses": "Not suitable for photorealism", "category": "specialized", "recommended_for": ["anime characters", "manga style", "cartoon illustrations"] }, "eimiss/EimisAnimeDiffusion_1.0v": { "display_name": "Nova Toon", "description": "Enhanced anime and cartoon renderer with vibrant colors", "icon": "๐Ÿ“บ", "speed": "medium", "quality": "specialized", "strengths": "Vibrant anime, consistent character design", "weaknesses": "Limited to cartoon styles", "category": "specialized", "recommended_for": ["vivid anime", "cartoon characters", "stylized portraits"] }, "thibaud/sdxl-lightning": { "display_name": "Nova Lightning", "description": "Ultra-fast version of Nova XL with impressive speed", "icon": "โšก", "speed": "very fast", "quality": "good", "strengths": "Extreme speed, good quality", "weaknesses": "Less detail than Nova XL", "category": "premium", "recommended_for": ["quick iterations", "rapid prototyping", "multiple variations"] }, "stabilityai/sdxl-turbo": { "display_name": "Nova Turbo", "description": "Accelerated high-quality generation with fewer steps", "icon": "๐Ÿ”ฑ", "speed": "fast", "quality": "premium", "strengths": "Speed with premium quality", "weaknesses": "Slightly less detailed than Nova XL", "category": "premium", "recommended_for": ["production quality with speed", "professional work", "detailed concepts"] }, "SG161222/Realistic_Vision_V5.1": { "display_name": "Nova Reality", "description": "Specialized in photorealistic people and scenes", "icon": "๐Ÿ‘๏ธ", "speed": "medium", "quality": "specialized", "strengths": "Realistic humans, lifelike scenes", "weaknesses": "Less versatile for other styles", "category": "specialized", "recommended_for": ["realistic portraits", "photorealistic scenes", "human figures"] } } # 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", "examples": ["portrait photography", "landscape photo", "product photography"], "recommended_models": ["Nova XL", "Nova Reality", "Nova Balance"] }, "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", "examples": ["digital landscape art", "character concept", "futuristic city"], "recommended_models": ["Nova Fast", "Nova Art", "Nova XL"] }, "Fantasy Illustration": { "description": "Create magical and fantastical scenes with otherworldly elements", "icon": "๐Ÿง™", "prompt_hint": "Describe magical elements, creatures, and environments in detail", "examples": ["dragon's lair", "fairy forest", "wizard tower"], "recommended_models": ["Nova Art", "Nova Dream", "Nova XL"] }, "Concept Art": { "description": "Create professional concept art for characters, environments or objects", "icon": "๐ŸŽฎ", "prompt_hint": "Include details about perspective, purpose, and design influences", "examples": ["sci-fi vehicle", "fantasy character design", "alien landscape"], "recommended_models": ["Nova XL", "Nova Art", "Nova Turbo"] }, "Anime/Manga": { "description": "Create Japanese anime or manga style illustration", "icon": "๐Ÿ™", "prompt_hint": "Specify anime aesthetics like shading style and character features", "examples": ["anime portrait", "manga action scene", "chibi character"], "recommended_models": ["Nova Anime", "Nova Toon", "Nova Art"] }, "Oil Painting": { "description": "Create an image with oil painting textures and artistic brushstrokes", "icon": "๐Ÿ–ผ๏ธ", "prompt_hint": "Consider describing texture, brushwork style, and canvas feel", "examples": ["oil portrait", "impressionist landscape", "still life painting"], "recommended_models": ["Nova XL", "Nova Dream", "Nova Art"] }, "Watercolor": { "description": "Create a soft watercolor illustration with subtle color blending", "icon": "๐Ÿ’ง", "prompt_hint": "Mention color blending, paper texture, and watercolor-specific effects", "examples": ["watercolor landscape", "botanical illustration", "watercolor portrait"], "recommended_models": ["Nova Dream", "Nova XL", "Nova Art"] }, "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.)", "examples": ["pencil portrait", "architectural sketch", "nature study drawing"], "recommended_models": ["Nova Balance", "Nova Fast", "Nova XL"] }, "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", "examples": ["3D product render", "architectural visualization", "game environment"], "recommended_models": ["Nova XL", "Nova Reality", "Nova Balance"] }, "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)", "examples": ["pixel game character", "isometric pixel scene", "pixel landscape"], "recommended_models": ["Nova Fast", "Nova Art", "Nova Balance"] }, "Isometric Art": { "description": "Create isometric style illustrations with geometric perspective", "icon": "๐Ÿ“", "prompt_hint": "Describe the scene elements, color scheme, and isometric perspective", "examples": ["isometric room", "isometric city", "isometric landscape"], "recommended_models": ["Nova Fast", "Nova Balance", "Nova Art"] }, "Cinematic Scene": { "description": "Create a dramatic scene with cinematic lighting and composition", "icon": "๐ŸŽฌ", "prompt_hint": "Specify camera angle, lighting setup, and film style references", "examples": ["sci-fi movie scene", "dramatic character moment", "epic landscape shot"], "recommended_models": ["Nova XL", "Nova Turbo", "Nova Reality"] }, "Character Portrait": { "description": "Create a focused portrait of a character with detailed features", "icon": "๐Ÿ‘ค", "prompt_hint": "Describe facial features, expression, clothing, and character background", "examples": ["fantasy character", "sci-fi hero", "historical figure"], "recommended_models": ["Nova XL", "Nova Reality", "Nova Anime"] }, "Landscape": { "description": "Create a stunning natural or urban landscape with atmospheric elements", "icon": "๐Ÿž๏ธ", "prompt_hint": "Include details about terrain, weather, time of day, and focal points", "examples": ["mountain vista", "coastal sunset", "futuristic cityscape"], "recommended_models": ["Nova XL", "Nova Turbo", "Nova Dream"] }, "Abstract Composition": { "description": "Create non-representational art with focus on shapes, colors and textures", "icon": "๐Ÿ”ณ", "prompt_hint": "Describe mood, color relationships, textures, and compositional elements", "examples": ["geometric abstraction", "fluid color composition", "textural abstract"], "recommended_models": ["Nova Dream", "Nova Art", "Nova XL"] }, "Product Visualization": { "description": "Create professional product imagery with studio-quality lighting", "icon": "๐Ÿ“ฆ", "prompt_hint": "Describe the product details, materials, lighting setup, and background", "examples": ["gadget render", "fashion accessory", "food photography"], "recommended_models": ["Nova XL", "Nova Reality", "Nova Turbo"] } } # 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", "technical_terms": ["hyperdetailed", "photographic", "lifelike", "realistic lighting"] }, "Impressionist": { "description": "Soft brushstrokes that capture light and atmosphere over precise details, like Monet", "icon": "๐ŸŒˆ", "examples": "Claude Monet, Pierre-Auguste Renoir, Camille Pissarro", "technical_terms": ["impressionism", "plein air", "visible brushstrokes", "light emphasis"] }, "Surrealist": { "description": "Dreamlike quality with impossible or irrational scenes, like Salvador Dali", "icon": "๐ŸŒ€", "examples": "Salvador Dali, Renรฉ Magritte, Frida Kahlo", "technical_terms": ["surrealism", "dreamlike", "symbolic", "juxtaposition"] }, "Pop Art": { "description": "Bold colors, sharp lines and popular culture references, like Andy Warhol", "icon": "๐ŸŽญ", "examples": "Andy Warhol, Roy Lichtenstein, Keith Haring", "technical_terms": ["pop art", "halftone dots", "bold outlines", "bright flat colors"] }, "Minimalist": { "description": "Simplified forms, limited color palette, and clean composition with minimal elements", "icon": "โฌœ", "examples": "Piet Mondrian, Kazimir Malevich, Agnes Martin", "technical_terms": ["minimalism", "geometric", "simplicity", "negative space"] }, "Abstract": { "description": "Non-representational style using shapes, colors, and forms to express ideas", "icon": "๐Ÿ”ถ", "examples": "Wassily Kandinsky, Jackson Pollock, Mark Rothko", "technical_terms": ["abstract", "non-figurative", "expressive", "color field"] }, "Cubist": { "description": "Geometric shapes and multiple perspectives shown simultaneously, like Picasso", "icon": "๐Ÿ“", "examples": "Pablo Picasso, Georges Braque, Juan Gris", "technical_terms": ["cubism", "geometric", "multiple perspectives", "fragmented"] }, "Art Nouveau": { "description": "Ornate, flowing lines inspired by natural forms with decorative elegance", "icon": "๐ŸŒฟ", "examples": "Alphonse Mucha, Gustav Klimt, Antoni Gaudรญ", "technical_terms": ["art nouveau", "organic curves", "decorative", "floral motifs"] }, "Gothic": { "description": "Dark, medieval-inspired aesthetic with dramatic lighting and architectural elements", "icon": "๐Ÿฐ", "examples": "Zdzisล‚aw Beksiล„ski, H.R. Giger, medieval architecture", "technical_terms": ["gothic", "medieval", "dark fantasy", "ornate details"] }, "Cyberpunk": { "description": "Futuristic dystopian style with neon colors, technology, and urban decay", "icon": "๐Ÿค–", "examples": "Blade Runner, Ghost in the Shell, Akira", "technical_terms": ["cyberpunk", "neon", "high-tech low-life", "dystopian"] }, "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", "technical_terms": ["steampunk", "brass", "victorian", "mechanical"] }, "Retro/Vintage": { "description": "Nostalgic style reminiscent of past decades with period-appropriate elements", "icon": "๐Ÿ“บ", "examples": "1950s advertisements, vintage travel posters, pulp magazine covers", "technical_terms": ["retro", "vintage", "nostalgic", "aged texture"] }, "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", "technical_terms": ["art deco", "geometric", "luxurious", "symmetrical"] }, "Baroque": { "description": "Dramatic, ornate style with rich details, contrast, and dynamic composition", "icon": "๐Ÿ‘‘", "examples": "Caravaggio, Rembrandt, Peter Paul Rubens", "technical_terms": ["baroque", "chiaroscuro", "ornate", "dramatic lighting"] }, "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", "technical_terms": ["ukiyo-e", "woodblock print", "japanese", "flat color"] }, "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", "technical_terms": ["comic art", "bold outlines", "dynamic", "halftone"] }, "Psychedelic": { "description": "Vibrant, swirling colors with abstract patterns inspired by 1960s art", "icon": "๐Ÿ”„", "examples": "1960s concert posters, Peter Max, Alex Grey", "technical_terms": ["psychedelic", "vibrant", "swirling", "fractal patterns"] }, "Vaporwave": { "description": "Glitch aesthetics with pastel colors, 80s/90s nostalgia and digital elements", "icon": "๐Ÿ“ผ", "examples": "Retrowave aesthetics, 80s digital graphics, glitch art", "technical_terms": ["vaporwave", "retrowave", "glitch", "pastel"] }, "Studio Ghibli": { "description": "Whimsical, detailed animation style inspired by Japanese animated films", "icon": "๐Ÿ‰", "examples": "Spirited Away, My Neighbor Totoro, Howl's Moving Castle", "technical_terms": ["anime", "ghibli", "miyazaki", "hand-drawn animation"] }, "Hyperrealism": { "description": "Extremely detailed realism that exceeds photograph-like precision", "icon": "๐Ÿ”", "examples": "Works by Roberto Bernardi, Denis Peterson, Gottfried Helnwein", "technical_terms": ["hyperrealism", "photorealistic", "extreme detail", "precision"] }, "Stained Glass": { "description": "Design resembling stained glass with defined segments and vivid colors", "icon": "๐ŸชŸ", "examples": "Medieval cathedral windows, Tiffany lamps, modern stained glass art", "technical_terms": ["stained glass", "leaded", "translucent", "sectioned"] }, "Synthwave": { "description": "80s-inspired futuristic style with neon grids, sunset gradients and retro elements", "icon": "๐ŸŒ†", "examples": "Retrowave artwork, 80s sci-fi aesthetics, digital sunset landscapes", "technical_terms": ["synthwave", "retrowave", "neon", "grid", "80s futurism"] }, "Low Poly": { "description": "3D style with visible polygonal faces and geometric simplification", "icon": "๐Ÿ“Š", "examples": "Low polygon 3D models, indie game art, geometric illustrations", "technical_terms": ["low poly", "polygonal", "faceted", "geometric"] }, "Watercolor Sketch": { "description": "Combination of line drawing with soft watercolor washes and bleeding colors", "icon": "๐ŸŽจ", "examples": "Urban sketchers, travel journals, architectural sketches with color", "technical_terms": ["urban sketch", "line and wash", "watercolor sketch", "loose style"] }, "Digital Painting": { "description": "Digital art that imitates traditional painting techniques with modern tools", "icon": "๐Ÿ–ฑ๏ธ", "examples": "Contemporary digital artists, concept art, digital illustrations", "technical_terms": ["digital painting", "brushwork", "textured", "painterly digital"] }, "Cel Shaded": { "description": "Comic or animation style with flat colors and defined outlines", "icon": "๐ŸŽญ", "examples": "Western animation, comic books, video game cel-shading", "technical_terms": ["cel shading", "toon shading", "flat color", "outlined"] }, "Cinematic": { "description": "Movie-like composition with dramatic lighting and film color grading", "icon": "๐ŸŽž๏ธ", "examples": "Film stills, cinematography, movie posters", "technical_terms": ["cinematic", "film grain", "color grading", "composition"] }, "Renaissance": { "description": "Classical style with realistic proportions, perspective and religious themes", "icon": "๐Ÿ›๏ธ", "examples": "Leonardo da Vinci, Michelangelo, Raphael", "technical_terms": ["renaissance", "classical", "sfumato", "perspective"] }, "Folk Art": { "description": "Traditional decorative style with cultural motifs and simplified forms", "icon": "๐Ÿงถ", "examples": "Various cultural folk art traditions, primitive art", "technical_terms": ["folk art", "naive art", "traditional", "decorative"] }, "Pointillism": { "description": "Style using small distinct dots of color to form images", "icon": "๐Ÿ‘†", "examples": "Georges Seurat, Paul Signac", "technical_terms": ["pointillism", "stippling", "dot technique", "optical mixing"] }, "Bauhaus": { "description": "Modernist style with geometric shapes, primary colors and functional design", "icon": "๐Ÿ”ท", "examples": "Wassily Kandinsky's Bauhaus works, Josef Albers, Lรกszlรณ Moholy-Nagy", "technical_terms": ["bauhaus", "modernist", "functional", "geometric"] } } # 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", "lighting": "Bright, open lighting with minimal shadows" }, "Sad": { "description": "Melancholic atmosphere with muted colors", "icon": "๐Ÿ˜ข", "color_palette": "Muted blues, grays, desaturated colors, cool tones", "lighting": "Soft, subdued lighting with long shadows" }, "Mysterious": { "description": "Enigmatic atmosphere with shadows and hidden elements", "icon": "๐Ÿ”ฎ", "color_palette": "Deep purples, dark blues, hints of teal, selective lighting", "lighting": "Dramatic, directional lighting with strong shadows" }, "Peaceful": { "description": "Serene, calm atmosphere with gentle lighting", "icon": "๐Ÿ•Š๏ธ", "color_palette": "Soft blues, gentle greens, pastel colors, balanced light", "lighting": "Soft, diffused lighting with minimal contrast" }, "Tense": { "description": "Suspenseful atmosphere with dramatic lighting", "icon": "๐Ÿ˜ฐ", "color_palette": "High contrast, dark shadows, selective reds, strong highlights", "lighting": "Harsh, directional lighting with strong shadows" }, "Whimsical": { "description": "Playful, imaginative atmosphere with fanciful elements", "icon": "๐Ÿฆ„", "color_palette": "Pastels, candy colors, unexpected color combinations", "lighting": "Magical, glowing lighting with soft sparkles" }, "Dark": { "description": "Gloomy atmosphere with deep shadows and low lighting", "icon": "๐ŸŒ‘", "color_palette": "Dark blues, blacks, deep greens, minimal highlights", "lighting": "Low-key lighting with strong shadows and minimal highlights" }, "Energetic": { "description": "Dynamic, vibrant atmosphere with strong colors and movement", "icon": "โšก", "color_palette": "Saturated primary colors, bold contrasts, vibrant hues", "lighting": "Bold, dynamic lighting with sharp contrasts" }, "Romantic": { "description": "Soft, dreamy atmosphere with warm, gentle lighting", "icon": "โค๏ธ", "color_palette": "Soft pinks, gentle reds, golden highlights, warm tones", "lighting": "Warm, soft lighting with a gentle glow" }, "Epic": { "description": "Grand, impressive atmosphere with dramatic scale and lighting", "icon": "๐Ÿ”๏ธ", "color_palette": "Bold colors, dramatic contrast, atmospheric lighting, expansive scale", "lighting": "Dramatic, cinematic lighting with god rays and atmosphere" }, "Ethereal": { "description": "Delicate, otherworldly atmosphere with a sense of transcendence", "icon": "โœจ", "color_palette": "Soft whites, pale blues, gentle pastels, luminous tones", "lighting": "Glowing, diffused lighting with light particles" }, "Nostalgic": { "description": "Warm, reminiscent atmosphere evoking memories and sentiment", "icon": "๐Ÿ•ฐ๏ธ", "color_palette": "Warm ambers, faded colors, slightly desaturated tones", "lighting": "Golden hour lighting or vintage film effects" }, "Dramatic": { "description": "Bold, emotionally charged atmosphere with strong contrasts", "icon": "๐ŸŽญ", "color_palette": "Strong contrasts, selective color highlights, bold tones", "lighting": "Strong directional lighting with pronounced shadows" }, "Serene": { "description": "Tranquil, meditative atmosphere with balanced elements", "icon": "๐Ÿง˜", "color_palette": "Balanced harmonious colors, natural tones, soft transitions", "lighting": "Even, gentle lighting with subtle gradients" }, "Chaotic": { "description": "Disorderly, energetic atmosphere with clashing elements", "icon": "๐Ÿ’ฅ", "color_palette": "Clashing colors, high contrast, unpredictable combinations", "lighting": "Uneven, conflicting lighting from multiple sources" }, "Futuristic": { "description": "Advanced technological atmosphere with sleek, modern elements", "icon": "๐Ÿš€", "color_palette": "Blues, cyans, whites, metallics, with accent neons", "lighting": "High-tech lighting, glows, volumetric beams" }, "Organic": { "description": "Natural, living atmosphere with biological elements and growth", "icon": "๐ŸŒฑ", "color_palette": "Natural greens, browns, living colors, earthy tones", "lighting": "Soft, natural lighting with dappled shadows and highlights" }, "Magical": { "description": "Enchanted atmosphere with mystical elements and wonder", "icon": "โœจ", "color_palette": "Glowing purples, blues, with golden accents and sparkles", "lighting": "Magical glow, light particles, soft radiance from magical elements" }, "Cozy": { "description": "Warm, comfortable atmosphere that evokes feelings of safety and comfort", "icon": "๐Ÿก", "color_palette": "Warm oranges, browns, reds, soft yellows, comforting tones", "lighting": "Warm, soft lighting like firelight or sunset glow" }, "Elegant": { "description": "Refined, sophisticated atmosphere with tasteful elements", "icon": "๐Ÿ‘‘", "color_palette": "Subdued luxurious colors, golds, deep blues, soft whites", "lighting": "Carefully balanced, flattering lighting with subtle highlights" } } # New aspect ratios with descriptions and use cases ASPECT_RATIOS = { "1:1 (Square)": { "dimensions": (512, 512), "description": "Perfect square format", "use_cases": "Social media posts, profile pictures, album covers", "icon": "โฌ›" }, "4:3 (Classic)": { "dimensions": (576, 432), "description": "Traditional TV and monitor ratio", "use_cases": "Desktop wallpapers, presentations, classic photo prints", "icon": "๐Ÿ“บ" }, "3:2 (Photo)": { "dimensions": (576, 384), "description": "Traditional photography ratio", "use_cases": "Professional photography, prints, postcards", "icon": "๐Ÿ“ท" }, "16:9 (Widescreen)": { "dimensions": (576, 324), "description": "Modern video and display format", "use_cases": "Widescreen wallpapers, video thumbnails, presentations", "icon": "๐Ÿ–ฅ๏ธ" }, "2:1 (Panoramic)": { "dimensions": (640, 320), "description": "Wide panoramic format", "use_cases": "Landscape photography, banner images, wide displays", "icon": "๐ŸŒ„" }, "9:16 (Portrait)": { "dimensions": (384, 680), "description": "Vertical mobile format", "use_cases": "Mobile wallpapers, stories, vertical videos", "icon": "๐Ÿ“ฑ" }, "3:4 (Portrait)": { "dimensions": (384, 512), "description": "Traditional portrait ratio", "use_cases": "Portraits, book covers, magazine covers", "icon": "๐Ÿ“”" }, "2:3 (Portrait Photo)": { "dimensions": (384, 576), "description": "Portrait photography ratio", "use_cases": "Portrait prints, phone wallpapers, book covers", "icon": "๐Ÿ“ฑ" }, "21:9 (Ultrawide)": { "dimensions": (640, 272), "description": "Ultra-widescreen cinematic format", "use_cases": "Cinematic scenes, movie stills, ultrawide displays", "icon": "๐ŸŽฌ" } } # Color palettes with descriptions and sample colors COLOR_PALETTES = { "Vibrant": { "description": "Bold, energetic colors with high saturation", "colors": ["#FF4500", "#FFD700", "#00FF7F", "#1E90FF", "#FF1493"], "icon": "๐ŸŒˆ", "mood_association": ["Happy", "Energetic", "Whimsical"] }, "Pastel": { "description": "Soft, light colors with low saturation", "colors": ["#FFB6C1", "#E6E6FA", "#B0E0E6", "#FFDAB9", "#98FB98"], "icon": "๐Ÿญ", "mood_association": ["Peaceful", "Whimsical", "Romantic"] }, "Monochrome": { "description": "Various shades and tones of a single color", "colors": ["#000000", "#333333", "#666666", "#999999", "#CCCCCC"], "icon": "โšซ", "mood_association": ["Elegant", "Mysterious", "Dramatic"] }, "Earthy": { "description": "Natural tones inspired by nature and earth", "colors": ["#8B4513", "#A0522D", "#556B2F", "#BDB76B", "#F5DEB3"], "icon": "๐Ÿ‚", "mood_association": ["Peaceful", "Organic", "Serene"] }, "Neon": { "description": "Bright, glowing colors with high intensity", "colors": ["#FF00FF", "#00FFFF", "#FF9900", "#39FF14", "#FE01B1"], "icon": "๐Ÿ’ซ", "mood_association": ["Energetic", "Futuristic", "Chaotic"] }, "Vintage": { "description": "Faded, nostalgic colors with a retro feel", "colors": ["#D3A588", "#C3B091", "#8F9E8B", "#535657", "#A87C6D"], "icon": "๐Ÿ•ฐ๏ธ", "mood_association": ["Nostalgic", "Romantic", "Cozy"] }, "Cool": { "description": "Blues, greens, and purples with a calm feel", "colors": ["#4682B4", "#5F9EA0", "#6495ED", "#483D8B", "#008080"], "icon": "โ„๏ธ", "mood_association": ["Peaceful", "Mysterious", "Serene"] }, "Warm": { "description": "Reds, oranges, and yellows with a warm feel", "colors": ["#CD5C5C", "#F08080", "#FA8072", "#FFA07A", "#FFDAB9"], "icon": "๐Ÿ”ฅ", "mood_association": ["Happy", "Energetic", "Romantic"] }, "Cyberpunk": { "description": "Neon colors against dark backgrounds with high contrast", "colors": ["#FF00FF", "#00FFFF", "#101010", "#FE9A00", "#121634"], "icon": "๐Ÿ‘พ", "mood_association": ["Futuristic", "Mysterious", "Dramatic"] }, "Minimal": { "description": "Limited color palette with blacks, whites, and accents", "colors": ["#FFFFFF", "#000000", "#DDDDDD", "#333333", "#FF3366"], "icon": "๐Ÿ”ฒ", "mood_association": ["Elegant", "Dramatic", "Serene"] } } # Special effects with descriptions and parameters SPECIAL_EFFECTS = { "None": { "description": "No special effects applied", "icon": "โญ•", "intensity_range": (0, 0), "default_intensity": 0 }, "Glow": { "description": "Adds a subtle luminous glow to bright areas", "icon": "โœจ", "intensity_range": (0.1, 1.0), "default_intensity": 0.5 }, "Film Grain": { "description": "Adds a textured grain similar to analog film", "icon": "๐ŸŽž๏ธ", "intensity_range": (0.1, 1.0), "default_intensity": 0.3 }, "Vignette": { "description": "Darkens the edges of the image for focus", "icon": "โšซ", "intensity_range": (0.1, 0.8), "default_intensity": 0.4 }, "Chromatic Aberration": { "description": "Creates subtle color fringing on edges", "icon": "๐ŸŒˆ", "intensity_range": (0.1, 0.5), "default_intensity": 0.2 }, "Retro Wave": { "description": "80s style grid and neon effects", "icon": "๐Ÿ“บ", "intensity_range": (0.2, 1.0), "default_intensity": 0.7 }, "Dream Blur": { "description": "Soft gaussian blur with glow for dreamy effect", "icon": "๐Ÿ’ญ", "intensity_range": (0.1, 0.6), "default_intensity": 0.3 }, "Duotone": { "description": "Two-color overlay effect", "icon": "๐Ÿ”„", "intensity_range": (0.3, 1.0), "default_intensity": 0.7 }, "Halftone": { "description": "Comic-style dots pattern effect", "icon": "๐Ÿ‘พ", "intensity_range": (0.2, 0.8), "default_intensity": 0.5 }, "Noir": { "description": "High contrast black and white with film noir look", "icon": "๐Ÿ•ต๏ธ", "intensity_range": (0.4, 1.0), "default_intensity": 0.7 } } # Example prompts with rich metadata and additional parameters 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", "aspect_ratio": "16:9 (Widescreen)", "color_palette": "Warm", "special_effect": "None", "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", "aspect_ratio": "16:9 (Widescreen)", "color_palette": "Cyberpunk", "special_effect": "Glow", "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", "aspect_ratio": "3:4 (Portrait)", "color_palette": "Earthy", "special_effect": "Vignette", "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", "aspect_ratio": "3:2 (Photo)", "color_palette": "Vibrant", "special_effect": "Glow", "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", "aspect_ratio": "2:3 (Portrait Photo)", "color_palette": "Cyberpunk", "special_effect": "Chromatic Aberration", "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", "aspect_ratio": "1:1 (Square)", "color_palette": "Vibrant", "special_effect": "None", "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", "aspect_ratio": "16:9 (Widescreen)", "color_palette": "Earthy", "special_effect": "Vignette", "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 coffee shop", "creation_type": "Digital Art", "art_style": "Impressionist", "mood": "Cozy", "aspect_ratio": "3:2 (Photo)", "color_palette": "Warm", "special_effect": "Dream Blur", "tags": ["interior", "rainy", "cozy", "urban"] }, { "text": "An astronaut standing on a distant planet with multiple ringed moons in the sky and alien vegetation around", "thumbnail_desc": "Astronaut on alien planet", "creation_type": "Cinematic Scene", "art_style": "Photorealistic", "mood": "Epic", "aspect_ratio": "21:9 (Ultrawide)", "color_palette": "Cool", "special_effect": "Film Grain", "tags": ["scifi", "space", "exploration", "alien"] }, { "text": "A stylish cyberpunk street fashion model with neon accessories and holographic clothing in a futuristic marketplace", "thumbnail_desc": "Cyberpunk street fashion", "creation_type": "Character Portrait", "art_style": "Cyberpunk", "mood": "Futuristic", "aspect_ratio": "2:3 (Portrait Photo)", "color_palette": "Neon", "special_effect": "Chromatic Aberration", "tags": ["fashion", "character", "cyberpunk", "future"] }, { "text": "An underwater city with bioluminescent buildings and mermaid-like inhabitants swimming between coral structures", "thumbnail_desc": "Bioluminescent underwater city", "creation_type": "Fantasy Illustration", "art_style": "Digital Painting", "mood": "Mysterious", "aspect_ratio": "16:9 (Widescreen)", "color_palette": "Cool", "special_effect": "Glow", "tags": ["underwater", "fantasy", "city", "merfolk"] }, { "text": "A tranquil Japanese zen garden with carefully raked sand, moss-covered stones, and maple trees in autumn colors", "thumbnail_desc": "Japanese zen garden in autumn", "creation_type": "Realistic Photo", "art_style": "Photorealistic", "mood": "Peaceful", "aspect_ratio": "3:2 (Photo)", "color_palette": "Earthy", "special_effect": "None", "tags": ["garden", "japanese", "zen", "autumn"] }, { "text": "A steampunk airship battle among the clouds with brass and copper vessels exchanging cannon fire", "thumbnail_desc": "Steampunk airship battle", "creation_type": "Concept Art", "art_style": "Steampunk", "mood": "Dramatic", "aspect_ratio": "16:9 (Widescreen)", "color_palette": "Vintage", "special_effect": "Film Grain", "tags": ["steampunk", "battle", "airship", "clouds"] } ] # =============== HELPER FUNCTIONS =============== # Format dropdown choices with icons for better UI def format_dropdown_choices(options_dict): """Format dropdown choices with icons for better UI""" return [f"{options_dict[key].get('icon', 'โ€ข')} {key}" for key in options_dict.keys()] # Extract the key from a formatted choice with icon def extract_key(formatted_choice): """Extract the key from a formatted choice with icon""" if not formatted_choice: return None # 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): """Load a pre-defined example prompt""" 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']}" aspect = f"{ASPECT_RATIOS[example['aspect_ratio']]['icon']} {example['aspect_ratio']}" color_palette = f"{COLOR_PALETTES[example['color_palette']]['icon']} {example['color_palette']}" special_effect = f"{SPECIAL_EFFECTS[example['special_effect']]['icon']} {example['special_effect']}" return example["text"], creation, art, mood, aspect, color_palette, special_effect # Get model key from formatted display name def get_model_key_from_display_name(formatted_name): """Get the model ID from its formatted display name""" if not formatted_name: return list(IMAGE_MODELS.keys())[0] # Default to first model # Extract display name without the icon display_name = extract_key(formatted_name) # Find the corresponding key by display name for key, info in IMAGE_MODELS.items(): if info['display_name'] == display_name: return key # Default to first model if not found return list(IMAGE_MODELS.keys())[0] # Helper function to update character count with color coding def update_char_count(text): """Update character count with color coding based on length""" count = len(text) if text else 0 if count == 0: color_class = "" advice = "Start typing to create your prompt" elif count < 20: color_class = "warning" advice = "Your prompt is too short. Add more details for better results" elif count > 300: color_class = "info" advice = "Great level of detail! You can still add more if needed" elif count > 500: color_class = "warning" advice = "Your prompt is getting very long. Consider focusing on key details" elif count > 700: color_class = "error" advice = "Very long prompts may be truncated. Try to be more concise" else: color_class = "success" advice = "Good prompt length with useful details" return f"""
{count} characters {advice}
""" # Helper function to update creation type info def update_creation_info(choice): """Update creation type info display based on selection""" key = extract_key(choice) if not key or key not in CREATION_TYPES: return "" info = CREATION_TYPES[key] examples = ", ".join([f"{ex}" for ex in info.get('examples', [])]) recommended_models = "" if 'recommended_models' in info: model_list = [f"{model}" for model in info['recommended_models']] recommended_models = f""" """ return f"""

{info['icon']} {key}

{info['description']}

๐Ÿ’ก {info['prompt_hint']}

Examples: {examples}

{recommended_models}
""" # Helper function to update art style info def update_art_style_info(choice): """Update art style info display based on selection""" key = extract_key(choice) if not key or key not in ART_STYLES: return "" info = ART_STYLES[key] technical_terms = "" if 'technical_terms' in info: terms = ", ".join([f"{term}" for term in info['technical_terms']]) technical_terms = f"""

Keywords: {terms}

""" return f"""

{info['icon']} {key}

{info['description']}

Inspired by: {info['examples']}

{technical_terms}
""" # Helper function to update model info def update_model_info(formatted_choice): """Update model info display based on selection""" if not formatted_choice: return "" # Extract display name without the icon display_name = extract_key(formatted_choice) # 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') == 'very fast': speed_badge = 'Ultra Fast' elif info.get('speed') == 'fast': speed_badge = 'Fast' elif info.get('speed') == 'medium': speed_badge = 'Medium' elif info.get('speed') == 'slow': speed_badge = 'Slower' # Create quality badge quality_badge = "" if info.get('quality') == 'premium': quality_badge = 'Premium Quality' elif info.get('quality') == 'excellent': quality_badge = 'Excellent Quality' elif info.get('quality') == 'very good': quality_badge = 'Very Good Quality' elif info.get('quality') == 'good': quality_badge = 'Good Quality' elif info.get('quality') == 'specialized': quality_badge = 'Specialized' elif info.get('quality') == 'artistic': quality_badge = 'Artistic' # Create recommended for badges recommended_badges = "" if 'recommended_for' in info: badges = " ".join([f'{item}' for item in info['recommended_for'][:3]]) recommended_badges = f"""""" # Create strengths and weaknesses section strengths_weaknesses = "" if 'strengths' in info and 'weaknesses' in info: strengths_weaknesses = f"""

โœ“ Strengths: {info['strengths']}

โœ— Limitations: {info['weaknesses']}

""" return f"""

{info['icon']} {info['display_name']} {speed_badge} {quality_badge}

{info['description']}

{strengths_weaknesses} {recommended_badges}
{key}
""" return "" # Helper function to update mood info def update_mood_info(choice): """Update mood info display based on selection""" key = extract_key(choice) if not key or key not in MOODS: return "" info = MOODS[key] return f"""

{info['icon']} {key}

{info['description']}

๐ŸŽจ {info['color_palette']}

๐Ÿ’ก {info['lighting']}

""" # Helper function to update status message with styling def update_status(message, is_error=False, is_warning=False, is_info=False): """Update status message with appropriate styling""" 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"""
{icon} {message}
""" # Helper function to format parameters display as pills def format_parameters(creation_type_val, art_style_val, mood_val, aspect_ratio_val, color_palette_val, special_effect_val, model_name): """Format generation parameters as readable badges/pills""" creation_key = extract_key(creation_type_val) art_key = extract_key(art_style_val) mood_key = extract_key(mood_val) aspect_key = extract_key(aspect_ratio_val) palette_key = extract_key(color_palette_val) effect_key = extract_key(special_effect_val) # Get model info model_display_name = "Unknown Model" model_id = "" model_icon = "๐Ÿค–" for key, info in IMAGE_MODELS.items(): if info['display_name'] == extract_key(model_name): model_display_name = info['display_name'] model_id = key model_icon = info['icon'] break html = """
Generated with these parameters:
""" # Add creation type pill if creation_key and creation_key in CREATION_TYPES: html += f"""
{CREATION_TYPES[creation_key]['icon']} {creation_key}
""" # Add art style pill if art_key and art_key in ART_STYLES: html += f"""
{ART_STYLES[art_key]['icon']} {art_key}
""" # Add mood pill if mood_key and mood_key in MOODS: html += f"""
{MOODS[mood_key]['icon']} {mood_key}
""" # Add aspect ratio pill if aspect_key and aspect_key in ASPECT_RATIOS: html += f"""
{ASPECT_RATIOS[aspect_key]['icon']} {aspect_key}
""" # Add color palette pill if palette_key and palette_key in COLOR_PALETTES: html += f"""
{COLOR_PALETTES[palette_key]['icon']} {palette_key}
""" # Add special effect pill if effect_key and effect_key in SPECIAL_EFFECTS and effect_key != "None": html += f"""
{SPECIAL_EFFECTS[effect_key]['icon']} {effect_key}
""" # Add model pill html += f"""
{model_icon} {model_display_name}
""" # Close container html += """
Generated on {timestamp}
""".replace("{timestamp}", datetime.now().strftime("%Y-%m-%d at %H:%M:%S")) return html # Helper function to cache generation results # Helper function to cache generation results def get_cache_key(description, model_key, creation_type, art_style, mood, aspect_ratio, color_palette, special_effect): """Generate a unique cache key for generation parameters""" # Create a string representation of all parameters param_string = f"{description}|{model_key}|{creation_type}|{art_style}|{mood}|{aspect_ratio}|{color_palette}|{special_effect}" # Create a hash of the parameters for a shorter key return hashlib.md5(param_string.encode('utf-8')).hexdigest() # Create a simple cache for generated images IMAGE_CACHE = {} def cache_image(key, image, enhanced_prompt, parameters_html, seed=None): """Cache an image with its metadata""" if not APP_CONFIG["cache_enabled"]: return # Limit cache size if len(IMAGE_CACHE) > 50: # Limit to last 50 images # Remove oldest entry oldest_key = next(iter(IMAGE_CACHE)) IMAGE_CACHE.pop(oldest_key) # Save to cache IMAGE_CACHE[key] = { "image": image, "enhanced_prompt": enhanced_prompt, "parameters_html": parameters_html, "timestamp": datetime.now().isoformat(), "seed": seed } def get_cached_image(key): """Get an image from cache if it exists""" if not APP_CONFIG["cache_enabled"] or key not in IMAGE_CACHE: return None return IMAGE_CACHE[key] # =============== PROMPT ENHANCEMENT LOGIC =============== # Function to enhance prompt with AI model def enhance_prompt_with_ai(user_input, creation_type, art_style, mood, color_palette=None, special_effect=None): """ Enhance user input with AI 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") color_palette (str): Selected color palette (e.g., "Vibrant") special_effect (str): Selected special effect (e.g., "Glow") Returns: str: Enhanced prompt optimized for image generation """ try: if not use_ai_enhancer or enhancer_client is None: logger.warning("AI enhancer not available, using fallback") return enhance_prompt_fallback(user_input, creation_type, art_style, mood, color_palette, special_effect) logger.info(f"Enhancing prompt with AI for: {creation_type}, {art_style}, {mood}") # Enhanced 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 description into a comprehensive, detailed image generation prompt that will create stunning visuals. Consider all the provided elements 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 - 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-175 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"] style_technical_terms = ", ".join(style_info.get("technical_terms", [])) # Get mood description mood_info = MOODS.get(mood, {"description": "atmospheric", "icon": "โœจ"}) mood_description = mood_info["description"] mood_lighting = mood_info.get("lighting", "") # Get color palette description if provided color_palette_description = "" if color_palette and color_palette in COLOR_PALETTES: palette_info = COLOR_PALETTES[color_palette] color_palette_description = f"Color Palette: {color_palette} - {palette_info['description']}" # Get special effect description if provided special_effect_description = "" if special_effect and special_effect in SPECIAL_EFFECTS and special_effect != "None": effect_info = SPECIAL_EFFECTS[special_effect] special_effect_description = f"Special Effect: {special_effect} - {effect_info['description']}" # Prepare the user prompt for AI enhancer user_prompt = f"""Description: {user_input} Creation Type: {creation_type} - {creation_description} Art Style: {art_style} - {style_description} Technical Style Terms: {style_technical_terms} Mood: {mood} - {mood_description} Lighting: {mood_lighting} {color_palette_description} {special_effect_description} Please create a comprehensive, detailed image generation prompt that combines all these elements.""" try: # Request enhancement from AI model response = enhancer_client.text_generation( prompt=f"\n{system_prompt}\n\n\n\n{user_prompt}\n\n\n", max_new_tokens=500, temperature=0.7, # Slight creativity while maintaining coherence top_p=0.95, repetition_penalty=1.1 ) # Extract enhanced prompt enhanced = response.strip() if enhanced.startswith(""): enhanced = enhanced[len(""):].strip() if enhanced.endswith(""): enhanced = enhanced[:-len("")].strip() logger.info(f"AI enhanced prompt: {enhanced[:100]}...") return enhanced if enhanced else user_input except Exception as e: logger.error(f"Error during AI enhancement: {str(e)}") return enhance_prompt_fallback(user_input, creation_type, art_style, mood, color_palette, special_effect) except Exception as e: logger.error(f"Error in AI enhancement: {str(e)}") return enhance_prompt_fallback(user_input, creation_type, art_style, mood, color_palette, special_effect) # Fallback prompt enhancement without AI def enhance_prompt_fallback(user_input, creation_type, art_style, mood, color_palette=None, special_effect=None): """ Enhance user input without requiring AI 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") color_palette (str): Selected color palette (e.g., "Vibrant") special_effect (str): Selected special effect (e.g., "Glow") 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", "high-definition" ], "Digital Art": [ "vibrant colors", "clean lines", "digital illustration", "polished", "professional digital art", "detailed rendering", "digital painting", "colorful", "vector-like precision", "crisp" ], "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" ], "Character Portrait": [ "character portrait", "detailed features", "expressive pose", "personality captured", "dynamic lighting", "professional portrait", "character design", "emotive", "high-quality portrait" ], "Landscape": [ "scenic vista", "atmospheric lighting", "panoramic view", "environmental details", "natural beauty", "grand landscape", "scenic composition", "depth of field", "natural environment" ], "Abstract Composition": [ "abstract composition", "non-representational", "artistic expression", "color theory", "visual rhythm", "compositional balance", "abstract forms", "artistic creativity", "non-figurative" ], "Product Visualization": [ "product showcase", "studio lighting", "professional product shot", "commercial quality", "advertising aesthetic", "product details", "pristine rendering", "marketing visualization", "product photography" ] } # Get art style technical terms style_terms = [] if art_style in ART_STYLES and "technical_terms" in ART_STYLES[art_style]: style_terms = ART_STYLES[art_style]["technical_terms"] # Get mood lighting and color palette mood_lighting = "" if mood in MOODS: mood_lighting = MOODS[mood].get("lighting", "") # Get color palette terms palette_terms = [] if color_palette and color_palette in COLOR_PALETTES: palette_info = COLOR_PALETTES[color_palette] palette_terms = [color_palette.lower(), palette_info["description"].lower()] # Special effect terms effect_terms = [] if special_effect and special_effect in SPECIAL_EFFECTS and special_effect != "None": effect_info = SPECIAL_EFFECTS[special_effect] effect_terms = [special_effect.lower(), effect_info["description"].lower()] # 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", "ultra realistic" ] # Get style modifier style_modifier = f"{art_style} style, {', '.join(style_terms[:3])}" if style_terms else f"{art_style} style" # Get mood modifier mood_modifier = f"{mood} mood, {mood_lighting}" if mood_lighting else f"{mood} mood" # Color palette modifier palette_modifier = f"{', '.join(palette_terms[:2])}" if palette_terms else "" # Effect modifier effect_modifier = f"{', '.join(effect_terms[:1])}" if effect_terms else "" # Basic prompt structure - core subject and style elements prompt_parts = [ user_input, style_modifier, mood_modifier ] if palette_modifier: prompt_parts.append(palette_modifier) if effect_modifier: prompt_parts.append(effect_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 =============== # Apply special effects to an image def apply_special_effects(image, special_effect, intensity=None): """Apply special visual effects to an image""" if not special_effect or special_effect == "None" or image is None: return image if special_effect not in SPECIAL_EFFECTS: return image effect_info = SPECIAL_EFFECTS[special_effect] # Use default intensity if not specified if intensity is None: intensity = effect_info["default_intensity"] # Ensure intensity is within range min_intensity, max_intensity = effect_info["intensity_range"] intensity = max(min_intensity, min(max_intensity, intensity)) try: # Apply the selected effect if special_effect == "Glow": # Create a blurred version for the glow effect glow_image = image.copy() glow_image = glow_image.filter(ImageFilter.GaussianBlur(radius=10 * intensity)) # Blend the original with the blurred version return Image.blend(image, glow_image, intensity * 0.5) elif special_effect == "Film Grain": # Create a noise layer width, height = image.size noise = Image.new('L', (width, height)) noise_data = np.random.randint(0, 255, (height, width), dtype=np.uint8) # Adjust noise intensity noise_data = np.clip(noise_data * intensity, 0, 255).astype(np.uint8) noise.putdata([x for x in noise_data.flatten()]) # Convert image to RGBA if it isn't already if image.mode != 'RGBA': image = image.convert('RGBA') # Create an alpha mask for the noise noise_mask = Image.new('L', (width, height), 255) # Apply noise with screen blending mode noise_overlay = Image.new('RGBA', (width, height)) for x in range(width): for y in range(height): r, g, b, a = image.getpixel((x, y)) noise_val = noise_data[y, x] # Screen blend mode nr = min(255, r + (noise_val * intensity * 0.1)) ng = min(255, g + (noise_val * intensity * 0.1)) nb = min(255, b + (noise_val * intensity * 0.1)) noise_overlay.putpixel((x, y), (int(nr), int(ng), int(nb), a)) # Blend the original with the noise overlay result = Image.alpha_composite(image, noise_overlay) return result.convert('RGB') elif special_effect == "Vignette": # Create a radial gradient for vignette width, height = image.size vignette = Image.new('L', (width, height), 255) # Calculate the dimensions of the ellipse ellipse_w = width * 1.5 ellipse_h = height * 1.5 ellipse_x = (width - ellipse_w) / 2 ellipse_y = (height - ellipse_h) / 2 # Create a draw object from PIL import ImageDraw draw = ImageDraw.Draw(vignette) # Draw the gradient for i in range(min(width, height) // 2): # Scale the ellipse size factor = 1 - (i / (min(width, height) / 2)) e_w = ellipse_w * factor e_h = ellipse_h * factor e_x = (width - e_w) / 2 e_y = (height - e_h) / 2 # Calculate the brightness (darker toward edges) brightness = int(255 * (1 - i / (min(width, height) / 2) * intensity)) # Draw an ellipse with the current brightness draw.ellipse((e_x, e_y, e_x + e_w, e_y + e_h), fill=brightness) # Apply the vignette result = image.copy() result.putalpha(vignette) # Convert back to RGB result = result.convert('RGB') return result elif special_effect == "Chromatic Aberration": # Split into RGB channels r, g, b = image.split() # Shift red channel to the right and blue channel to the left shift_amount = int(5 * intensity) r = ImageChops.offset(r, shift_amount, 0) b = ImageChops.offset(b, -shift_amount, 0) # Merge channels back return Image.merge("RGB", (r, g, b)) elif special_effect == "Dream Blur": # Apply a soft Gaussian blur blurred = image.filter(ImageFilter.GaussianBlur(radius=intensity * 3)) # Increase brightness slightly enhancer = ImageEnhance.Brightness(blurred) brightened = enhancer.enhance(1 + intensity * 0.2) # Increase contrast slightly enhancer = ImageEnhance.Contrast(brightened) contrasted = enhancer.enhance(1 + intensity * 0.1) return contrasted elif special_effect == "Duotone": # Convert to grayscale grayscale = image.convert('L') # Define two colors for duotone effect highlight_color = (52, 143, 235) # Blue shadow_color = (145, 39, 143) # Purple # Create duotone image duotone = Image.new('RGB', image.size) # For each pixel, blend between the shadow and highlight colors # based on the grayscale value for x in range(image.width): for y in range(image.height): gray_value = grayscale.getpixel((x, y)) / 255.0 r = int(shadow_color[0] * (1 - gray_value) + highlight_color[0] * gray_value) g = int(shadow_color[1] * (1 - gray_value) + highlight_color[1] * gray_value) b = int(shadow_color[2] * (1 - gray_value) + highlight_color[2] * gray_value) duotone.putpixel((x, y), (r, g, b)) # Blend with original based on intensity return Image.blend(image, duotone, intensity) elif special_effect == "Halftone": # This is a simplified halftone effect # Convert to grayscale grayscale = image.convert('L') # Resize down and then back up to create the dot pattern dot_size = max(1, int(10 * intensity)) small = grayscale.resize((image.width // dot_size, image.height // dot_size), Image.NEAREST) halftone = small.resize(image.size, Image.NEAREST) # Convert back to RGB halftone = halftone.convert('RGB') # Blend with original based on intensity return Image.blend(image, halftone, intensity * 0.7) elif special_effect == "Noir": # Convert to high contrast black and white grayscale = image.convert('L') # Increase contrast enhancer = ImageEnhance.Contrast(grayscale) noir = enhancer.enhance(1.5 + intensity) # Convert back to RGB noir = noir.convert('RGB') return noir elif special_effect == "Retro Wave": # This is a simplified retro wave effect with purple/pink gradient width, height = image.size # Create base gradient gradient = Image.new('RGB', (width, height)) for y in range(height): # Calculate color gradient from pink to purple to blue r = int(255 - (y/height) * 150) g = int(50 + (y/height) * 50) b = int(150 + (y/height) * 105) for x in range(width): gradient.putpixel((x, y), (r, g, b)) # Blend gradient with original image result = Image.blend(image, gradient, intensity * 0.4) # Add scanlines for retro effect scanlines = Image.new('L', (width, height), 255) draw = ImageDraw.Draw(scanlines) # Draw horizontal lines line_spacing = max(2, int(4 * (1/intensity))) for y in range(0, height, line_spacing): draw.line([(0, y), (width, y)], fill=150) # Apply scanlines with opacity based on intensity result.putalpha(scanlines) result = result.convert('RGB') return result # Default case - return original image return image except Exception as e: logger.error(f"Error applying special effect {special_effect}: {str(e)}") return image # Generate image function with loading state handling and retry mechanism def generate_image(description, model_key, creation_type=None, art_style=None, mood=None, aspect_ratio=None, color_palette=None, special_effect=None, seed=None, retries=1): """ Generate image based on user inputs by enhancing prompt and calling image model API Args: description (str): User's original description model_key (str): Model identifier creation_type (str, optional): Creation type art_style (str, optional): Art style mood (str, optional): Mood aspect_ratio (str, optional): Aspect ratio color_palette (str, optional): Color palette special_effect (str, optional): Special effect seed (int, optional): Random seed for reproducibility retries (int): Number of retries if generation fails Returns: tuple: (image, status_message, enhanced_prompt, parameters_html, seed) """ try: # Validate input if not description or not description.strip(): return None, "Please enter a description for your image", "", "", None logger.info(f"Generating image with model: {model_key}") # Check if we have a cached result cache_key = get_cache_key(description, model_key, creation_type, art_style, mood, aspect_ratio, color_palette, special_effect) cached = get_cached_image(cache_key) if cached: logger.info(f"Using cached image for: {description[:50]}...") return cached["image"], "Image retrieved from cache", cached["enhanced_prompt"], cached["parameters_html"], cached["seed"] # Extract aspect ratio dimensions width, height = (512, 512) # Default if aspect_ratio in ASPECT_RATIOS: width, height = ASPECT_RATIOS[aspect_ratio]["dimensions"] # Enhance prompt with AI or fallback enhanced_prompt = enhance_prompt_with_ai( description, creation_type, art_style, mood, color_palette, special_effect ) # 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, "", None # 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_key} with prompt: {enhanced_prompt[:100]}...") # Log start time for performance tracking start_time = time.time() # Set generation parameters params = { "negative_prompt": negative_prompt, "width": width, "height": height } # Add seed if provided if seed is not None: params["seed"] = seed else: # Generate random seed seed = random.randint(0, 2147483647) params["seed"] = seed # Generate the image image = hf_client.text_to_image( prompt=enhanced_prompt, model=model_key, **params ) # Apply special effects if requested if special_effect and special_effect != "None": image = apply_special_effects(image, special_effect) # Calculate generation time generation_time = time.time() - start_time logger.info(f"Image generated successfully in {generation_time:.2f} seconds") # Format parameters for display model_info = "" for key, info in IMAGE_MODELS.items(): if key == model_key: model_info = f"{info['icon']} {info['display_name']}" break # Create parameters display parameters_html = format_parameters( f"{CREATION_TYPES.get(creation_type, {}).get('icon', 'โ€ข')} {creation_type}" if creation_type else "", f"{ART_STYLES.get(art_style, {}).get('icon', 'โ€ข')} {art_style}" if art_style else "", f"{MOODS.get(mood, {}).get('icon', 'โ€ข')} {mood}" if mood else "", f"{ASPECT_RATIOS.get(aspect_ratio, {}).get('icon', 'โ€ข')} {aspect_ratio}" if aspect_ratio else "", f"{COLOR_PALETTES.get(color_palette, {}).get('icon', 'โ€ข')} {color_palette}" if color_palette else "", f"{SPECIAL_EFFECTS.get(special_effect, {}).get('icon', 'โ€ข')} {special_effect}" if special_effect else "", model_info ) # Cache the result cache_image(cache_key, image, enhanced_prompt, parameters_html, seed) # Success message with generation details if use_ai_enhancer: enhancement_method = "AI-enhanced prompt" else: enhancement_method = "rule-based prompt enhancement" model_display_name = "Unknown Model" for key, info in IMAGE_MODELS.items(): if key == model_key: model_display_name = info['display_name'] break success_message = f"Image created successfully in {generation_time:.1f}s using {model_display_name} with {enhancement_method} (seed: {seed})" return image, success_message, enhanced_prompt, parameters_html, seed 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, model_key, creation_type, art_style, mood, aspect_ratio, color_palette, special_effect, seed, 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, "", None except Exception as e: logger.error(f"Unexpected error in generate_image: {str(e)}") return None, f"Unexpected error: {str(e)}", "", "", None # Wrapper function for generate_image with status updates # Wrapper function for generate_image with status updates (continued) def generate_with_status(description, creation_type_val, art_style_val, mood_val, aspect_ratio_val, color_palette_val, special_effect_val, model_name, seed=None): """ Wrapper for generate_image that handles UI status updates and parameter formatting Returns: tuple: (image, status_html, enhanced_prompt, parameters_html, seed) """ # Check if description is empty if not description or not description.strip(): return None, update_status("Please enter a description", is_error=True), "", "", None # 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) aspect_key = extract_key(aspect_ratio_val) palette_key = extract_key(color_palette_val) effect_key = extract_key(special_effect_val) # Get model key from formatted name model_key = get_model_key_from_display_name(model_name) if not model_key: return None, update_status("Invalid model selection", is_error=True), "", "", None try: # Generate the image image, message, enhanced_prompt, parameters_html, used_seed = generate_image( description, model_key, creation_key, art_key, mood_key, aspect_key, palette_key, effect_key, seed ) if image is None: return None, update_status(message, is_error=True), "", "", None # Success message success_message = update_status(message) return image, success_message, enhanced_prompt, parameters_html, used_seed 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), "", "", None # Batch generation function def generate_variations(description, model_key, creation_type=None, art_style=None, mood=None, aspect_ratio=None, color_palette=None, special_effect=None, num_images=4): """ Generate multiple variations of an image with different seeds Args: description (str): User's original description model_key (str): Model identifier creation_type (str, optional): Creation type art_style (str, optional): Art style mood (str, optional): Mood aspect_ratio (str, optional): Aspect ratio color_palette (str, optional): Color palette special_effect (str, optional): Special effect num_images (int): Number of variations to generate Returns: list: List of tuples (image, seed) for each variation """ results = [] num_images = min(num_images, APP_CONFIG["max_batch_size"]) # Limit to max batch size # Generate varied seeds import time base_seed = int(time.time()) % 10000 seeds = [base_seed + i * 1000 for i in range(num_images)] # Generate images in sequence for i, seed in enumerate(seeds): try: image, _, _, _, used_seed = generate_image( description, model_key, creation_type, art_style, mood, aspect_ratio, color_palette, special_effect, seed, retries=0 ) if image: results.append((image, used_seed)) except Exception as e: logger.error(f"Error generating variation {i+1}: {str(e)}") continue return results # =============== USER PROFILE AND HISTORY MANAGEMENT =============== # User profile management class UserProfile: """User profile management with preferences and history""" def __init__(self, user_id=None): """Initialize user profile""" self.user_id = user_id or str(uuid.uuid4()) self.preferences = { "theme": APP_CONFIG["default_theme"], "default_model": "stabilityai/stable-diffusion-xl-base-1.0", "default_creation_type": "Digital Art", "default_aspect_ratio": "1:1 (Square)", "show_tips": True, "advanced_mode": False } self.history = [] self.favorites = [] self.load() def save(self): """Save user profile to disk""" try: data_dir = os.path.join(APP_CONFIG["data_dir"], "users") os.makedirs(data_dir, exist_ok=True) filename = os.path.join(data_dir, f"{self.user_id}.json") with open(filename, 'w') as f: # Create serializable history (convert PIL images to base64) serializable_history = [] for entry in self.history: if 'image' in entry and entry['image'] is not None: # Convert PIL image to base64 img_buffer = io.BytesIO() entry['image'].save(img_buffer, format="PNG") img_base64 = base64.b64encode(img_buffer.getvalue()).decode('utf-8') # Create copy of entry with base64 image entry_copy = entry.copy() entry_copy['image_data'] = img_base64 entry_copy.pop('image', None) # Remove PIL image serializable_history.append(entry_copy) else: entry_copy = entry.copy() entry_copy.pop('image', None) # Remove PIL image if any serializable_history.append(entry_copy) # Create serializable favorites serializable_favorites = [] for entry in self.favorites: if 'image' in entry and entry['image'] is not None: # Convert PIL image to base64 img_buffer = io.BytesIO() entry['image'].save(img_buffer, format="PNG") img_base64 = base64.b64encode(img_buffer.getvalue()).decode('utf-8') # Create copy of entry with base64 image entry_copy = entry.copy() entry_copy['image_data'] = img_base64 entry_copy.pop('image', None) # Remove PIL image serializable_favorites.append(entry_copy) else: entry_copy = entry.copy() entry_copy.pop('image', None) # Remove PIL image if any serializable_favorites.append(entry_copy) # Create serializable profile profile_data = { 'user_id': self.user_id, 'preferences': self.preferences, 'history': serializable_history, 'favorites': serializable_favorites } json.dump(profile_data, f, indent=2) logger.info(f"Saved user profile: {self.user_id}") return True except Exception as e: logger.error(f"Error saving user profile: {str(e)}") return False def load(self): """Load user profile from disk""" try: filename = os.path.join(APP_CONFIG["data_dir"], "users", f"{self.user_id}.json") if not os.path.exists(filename): logger.info(f"User profile doesn't exist: {self.user_id}") return False with open(filename, 'r') as f: data = json.load(f) # Load profile data self.preferences = data.get('preferences', self.preferences) # Load history and convert base64 back to PIL images self.history = [] for entry in data.get('history', []): if 'image_data' in entry: # Convert base64 back to PIL image img_data = base64.b64decode(entry['image_data']) img = Image.open(io.BytesIO(img_data)) # Create entry with PIL image entry_copy = entry.copy() entry_copy['image'] = img entry_copy.pop('image_data', None) # Remove base64 data self.history.append(entry_copy) else: self.history.append(entry) # Load favorites self.favorites = [] for entry in data.get('favorites', []): if 'image_data' in entry: # Convert base64 back to PIL image img_data = base64.b64decode(entry['image_data']) img = Image.open(io.BytesIO(img_data)) # Create entry with PIL image entry_copy = entry.copy() entry_copy['image'] = img entry_copy.pop('image_data', None) # Remove base64 data self.favorites.append(entry_copy) else: self.favorites.append(entry) logger.info(f"Loaded user profile: {self.user_id}") return True except Exception as e: logger.error(f"Error loading user profile: {str(e)}") return False def add_to_history(self, image, description, enhanced_prompt, parameters, seed=None): """Add an image to user history""" if image is None: return False # Create history entry entry = { 'id': str(uuid.uuid4()), 'timestamp': datetime.now().isoformat(), 'image': image, 'description': description, 'enhanced_prompt': enhanced_prompt, 'parameters': parameters, 'seed': seed } # Add to history self.history.insert(0, entry) # Limit history size if len(self.history) > APP_CONFIG["max_history"]: self.history = self.history[:APP_CONFIG["max_history"]] # Save profile self.save() return True def add_to_favorites(self, image_id): """Add an image from history to favorites""" # Find image in history for entry in self.history: if entry.get('id') == image_id: # Check if already in favorites if any(fav.get('id') == image_id for fav in self.favorites): return False # Add to favorites self.favorites.insert(0, entry) # Save profile self.save() return True return False def remove_from_favorites(self, image_id): """Remove an image from favorites""" for i, entry in enumerate(self.favorites): if entry.get('id') == image_id: self.favorites.pop(i) self.save() return True return False def get_history(self): """Get user history""" return self.history def get_favorites(self): """Get user favorites""" return self.favorites def clear_history(self): """Clear user history""" self.history = [] self.save() return True def update_preferences(self, preferences): """Update user preferences""" self.preferences.update(preferences) self.save() return True # Initialize user profile current_user = UserProfile() # =============== UI CREATION FUNCTIONS =============== # Create modern UI with improved UX def create_ui(): """Create the application UI""" # Set page title and favicon gr.Blocks(analytics_enabled=APP_CONFIG["enable_analytics"]) # Define CSS for enhanced UI css = """ /* Variables for light/dark theme customization */ :root { /* Light Theme (Default) */ --primary-color: #6A24FE; --primary-hover: #5615ED; --secondary-color: #FF4593; --secondary-hover: #E32D7B; --tertiary-color: #2ECADE; --tertiary-hover: #22A8BC; --accent-color: #FFA03C; --accent-hover: #E98321; --background-color: #F9FAFF; --card-color: #FFFFFF; --card-hover: #F5F7FF; --text-color: #1A1A2E; --text-muted: #64748B; --text-light: #94A3B8; --border-color: #E2E8F0; --border-hover: #CBD5E1; --error-color: #E11D48; --warning-color: #F59E0B; --success-color: #10B981; --info-color: #3B82F6; --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-md: 0 6px 10px -2px rgba(0, 0, 0, 0.12), 0 3px 6px -2px rgba(0, 0, 0, 0.08); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); --radius-sm: 0.375rem; --radius: 0.5rem; --radius-md: 0.625rem; --radius-lg: 0.75rem; --radius-xl: 1rem; --radius-2xl: 1.5rem; --radius-3xl: 2rem; --radius-full: 9999px; --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; --font-display: 'Plus Jakarta Sans', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; --font-mono: 'JetBrains Mono', 'SF Mono', 'Roboto Mono', Menlo, Consolas, monospace; --header-height: 4rem; /* Theme transition */ --transition-normal: 0.2s ease; --transition-slow: 0.35s ease; } /* Dark Theme */ .dark-theme { --primary-color: #8B5CF6; --primary-hover: #7C3AED; --secondary-color: #EC4899; --secondary-hover: #DB2777; --tertiary-color: #06B6D4; --tertiary-hover: #0891B2; --accent-color: #F97316; --accent-hover: #EA580C; --background-color: #0F172A; --card-color: #1E293B; --card-hover: #263449; --text-color: #F8FAFC; --text-muted: #94A3B8; --text-light: #CBD5E1; --border-color: #334155; --border-hover: #475569; --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.2); --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2); --shadow-md: 0 6px 10px -2px rgba(0, 0, 0, 0.4), 0 3px 6px -2px rgba(0, 0, 0, 0.25); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.2); --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 10px 10px -5px rgba(0, 0, 0, 0.2); } /* 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; transition: background-color var(--transition-normal), color var(--transition-normal); } /* Container with responsive padding */ .container { max-width: 1500px; margin: 0 auto; padding: 1rem; } @media (max-width: 768px) { .container { padding: 0.75rem; } } @media (max-width: 640px) { .container { padding: 0.5rem; } } /* Add custom fonts */ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap'); /* Card styling with elevation and hover effects */ .gr-panel, div.gradio-box { border-radius: var(--radius-lg) !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(--transition-normal), border-color var(--transition-normal); background-color: var(--card-color) !important; } .gr-panel:hover, div.gradio-box:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg) !important; border-color: var(--border-hover) !important; } /* Primary 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; position: relative; overflow: hidden; z-index: 1; } button.primary::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, var(--secondary-color), var(--primary-color)); z-index: -1; opacity: 0; transition: opacity 0.3s ease; } button.primary:hover { transform: translateY(-1px); box-shadow: var(--shadow) !important; } button.primary:hover::before { opacity: 1; } button.primary:active { transform: translateY(0); } 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(106, 36, 254, 0.08) !important; border-color: var(--primary-hover) !important; transform: translateY(-1px); } /* Ghost button styling */ button.ghost { background-color: transparent !important; color: var(--text-color) !important; border: 1px solid var(--border-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.ghost:hover { background-color: rgba(0, 0, 0, 0.04) !important; border-color: var(--border-hover) !important; transform: translateY(-1px); } .dark-theme button.ghost:hover { background-color: rgba(255, 255, 255, 0.04) !important; } /* Style for the example buttons */ .example-button { font-size: 0.875rem !important; padding: 0.75rem 1rem !important; background-color: var(--card-color) !important; border: 1px solid var(--border-color) !important; border-radius: var(--radius-lg) !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; box-shadow: var(--shadow-sm) !important; } .example-button:hover { background-color: var(--card-hover) !important; border-color: var(--primary-color) !important; transform: translateY(-2px); box-shadow: var(--shadow) !important; } /* 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, background-color var(--transition-normal), color var(--transition-normal) !important; font-family: var(--font-sans) !important; color: var(--text-color) !important; background-color: var(--card-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(106, 36, 254, 0.2) !important; outline: none !important; } .dark-theme .gr-input:focus, .dark-theme .gr-textarea:focus, .dark-theme .gr-dropdown:focus-within { box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.3) !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; transition: color var(--transition-normal); } /* 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"], input[type="number"], input[type="email"], input[type="password"] { 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, background-color var(--transition-normal), color var(--transition-normal) !important; font-family: var(--font-sans) !important; background-color: var(--card-color) !important; color: var(--text-color) !important; } textarea:focus, input[type="text"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="password"]:focus { border-color: var(--primary-color) !important; box-shadow: 0 0 0 3px rgba(106, 36, 254, 0.2) !important; outline: none !important; } .dark-theme textarea:focus, .dark-theme input[type="text"]:focus, .dark-theme input[type="number"]:focus, .dark-theme input[type="email"]:focus, .dark-theme input[type="password"]:focus { box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.3) !important; } /* Dropdown styling */ .gr-dropdown { border-radius: var(--radius) !important; border: 1px solid var(--border-color) !important; background-color: var(--card-color) !important; color: var(--text-color) !important; transition: border-color 0.2s, box-shadow 0.2s, background-color var(--transition-normal), color var(--transition-normal) !important; } .gr-dropdown > div { border-radius: var(--radius) !important; min-height: 38px !important; } .gr-dropdown > div > span { font-size: 0.9375rem !important; color: var(--text-color) !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; transition: background-color var(--transition-normal), border-color var(--transition-normal) !important; } .gr-dropdown ul li { padding: 0.5rem 0.75rem !important; color: var(--text-color) !important; transition: background-color var(--transition-normal), color var(--transition-normal) !important; } .gr-dropdown ul li:hover { background-color: rgba(106, 36, 254, 0.08) !important; } .dark-theme .gr-dropdown ul li:hover { background-color: rgba(139, 92, 246, 0.15) !important; } /* App header with animation and brand styling */ .app-header { text-align: center; padding: 2.5rem 1.5rem 2rem; margin-bottom: 2rem; background: linear-gradient(135deg, rgba(106, 36, 254, 0.08), rgba(255, 69, 147, 0.08)); border-radius: var(--radius-xl); position: relative; overflow: hidden; transition: background var(--transition-normal); } .dark-theme .app-header { background: linear-gradient(135deg, rgba(139, 92, 246, 0.12), rgba(236, 72, 153, 0.12)); } .app-header::before { content: ''; position: absolute; top: -50px; left: -50px; right: -50px; height: 100px; background: linear-gradient(135deg, rgba(106, 36, 254, 0.2), rgba(255, 69, 147, 0.2)); transform: rotate(-5deg); z-index: 0; transition: background var(--transition-normal); } .dark-theme .app-header::before { background: linear-gradient(135deg, rgba(139, 92, 246, 0.25), rgba(236, 72, 153, 0.25)); } .app-header::after { content: ''; position: absolute; bottom: -50px; left: -50px; right: -50px; height: 70px; background: linear-gradient(135deg, rgba(255, 69, 147, 0.1), rgba(106, 36, 254, 0.1)); transform: rotate(3deg); z-index: 0; transition: background var(--transition-normal); } .dark-theme .app-header::after { background: linear-gradient(135deg, rgba(236, 72, 153, 0.15), rgba(139, 92, 246, 0.15)); } .app-header h1 { font-family: var(--font-display) !important; font-size: 3.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; letter-spacing: -0.03em; transition: background var(--transition-normal); } .dark-theme .app-header h1 { background: linear-gradient(135deg, #A78BFA, #F472B6); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .app-header p { font-size: 1.25rem !important; color: var(--text-color); opacity: 0.9; max-width: 42rem; margin: 0 auto; position: relative; z-index: 1; transition: color var(--transition-normal); } .app-tagline { font-family: var(--font-display) !important; font-weight: 600; font-size: 1.5rem !important; background: linear-gradient(135deg, var(--secondary-color), var(--primary-color)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 1rem !important; transition: background var(--transition-normal); } .dark-theme .app-tagline { background: linear-gradient(135deg, #F472B6, #A78BFA); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } /* Responsive header */ @media (max-width: 768px) { .app-header h1 { font-size: 2.5rem !important; } .app-tagline { font-size: 1.25rem !important; } .app-header p { font-size: 1rem !important; } } @media (max-width: 640px) { .app-header h1 { font-size: 2rem !important; } .app-header p { font-size: 0.875rem !important; } } /* Gallery with grid layout and responsive design */ .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 1rem; margin: 1.5rem 0; } @media (max-width: 768px) { .gallery { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.75rem; } } @media (max-width: 480px) { .gallery { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 0.5rem; } } .gallery-item { border-radius: var(--radius-lg); overflow: hidden; cursor: pointer; border: 2px solid transparent; transition: all 0.3s; display: flex; flex-direction: column; background-color: var(--card-color); box-shadow: var(--shadow-sm); position: relative; } .gallery-item:hover { transform: translateY(-3px) scale(1.02); border-color: var(--primary-color); box-shadow: var(--shadow-md); } .dark-theme .gallery-item:hover { border-color: var(--primary-color); } .gallery-item:active { transform: translateY(-1px) scale(1.01); } .gallery-item-image { width: 100%; aspect-ratio: 1; background-color: rgba(0, 0, 0, 0.04); display: flex; align-items: center; justify-content: center; color: var(--text-muted); font-size: 1.5rem; border-bottom: 1px solid var(--border-color); transition: background-color var(--transition-normal), border-color var(--transition-normal); } .dark-theme .gallery-item-image { background-color: rgba(255, 255, 255, 0.04); } .gallery-item-caption { padding: 0.75rem; 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; transition: color var(--transition-normal); } .gallery-item-labels { display: flex; gap: 0.25rem; padding: 0 0.5rem 0.5rem; } .gallery-item-label { font-size: 0.625rem; padding: 0.125rem 0.375rem; border-radius: var(--radius-full); background-color: rgba(106, 36, 254, 0.1); color: var(--primary-color); white-space: nowrap; transition: background-color var(--transition-normal), color var(--transition-normal); } .dark-theme .gallery-item-label { background-color: rgba(139, 92, 246, 0.2); color: #A78BFA; } /* 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.85); z-index: 1000; backdrop-filter: blur(3px); border-radius: var(--radius-lg); transition: background-color var(--transition-normal); } .dark-theme .loading-indicator { background-color: rgba(15, 23, 42, 0.85); } .spinner { width: 40px; height: 40px; border: 3px solid rgba(106, 36, 254, 0.2); border-radius: 50%; border-top-color: var(--primary-color); animation: spin 1s linear infinite; transition: border-color var(--transition-normal); } .dark-theme .spinner { border: 3px solid rgba(139, 92, 246, 0.3); border-top-color: var(--primary-color); } @keyframes spin { to { transform: rotate(360deg); } } /* Progress bars with animations */ .progress-container { width: 100%; height: 8px; background-color: rgba(106, 36, 254, 0.1); border-radius: var(--radius-full); overflow: hidden; margin: 0.75rem 0; transition: background-color var(--transition-normal); } .dark-theme .progress-container { background-color: rgba(139, 92, 246, 0.15); } .progress-bar { height: 100%; background: linear-gradient(to right, var(--primary-color), var(--secondary-color)); width: 0%; transition: width 0.3s ease, background var(--transition-normal); border-radius: var(--radius-full); position: relative; overflow: hidden; } .dark-theme .progress-bar { background: linear-gradient(to right, #8B5CF6, #EC4899); } .progress-bar::after { content: ""; position: absolute; top: 0; left: 0; bottom: 0; right: 0; background-image: linear-gradient( -45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent ); background-size: 50px 50px; animation: move 2s linear infinite; border-radius: var(--radius-full); overflow: hidden; z-index: 1; } @keyframes move { 0% { background-position: 0 0; } 100% { background-position: 50px 50px; } } /* Status message with icons */ .status-message { padding: 1rem 1.25rem; border-radius: var(--radius-lg); margin: 1rem 0; font-size: 0.875rem; display: flex; align-items: center; position: relative; transition: background-color var(--transition-normal), color var(--transition-normal); } .status-message .icon { margin-right: 0.75rem; font-size: 1.25rem; flex-shrink: 0; } .status-success { background-color: rgba(16, 185, 129, 0.1); color: var(--success-color); border-left: 3px solid var(--success-color); } .dark-theme .status-success { background-color: rgba(16, 185, 129, 0.15); } .status-error { background-color: rgba(225, 29, 72, 0.1); color: var(--error-color); border-left: 3px solid var(--error-color); } .dark-theme .status-error { background-color: rgba(225, 29, 72, 0.15); } .status-warning { background-color: rgba(245, 158, 11, 0.1); color: var(--warning-color); border-left: 3px solid var(--warning-color); } .dark-theme .status-warning { background-color: rgba(245, 158, 11, 0.15); } .status-info { background-color: rgba(59, 130, 246, 0.1); color: var(--info-color); border-left: 3px solid var(--info-color); } .dark-theme .status-info { background-color: rgba(59, 130, 246, 0.15); } /* Tabs styling with active indicators */ .tabs { display: flex; border-bottom: 2px solid var(--border-color); margin-bottom: 1.5rem; transition: border-color var(--transition-normal); } .tab { padding: 0.875rem 1.25rem; cursor: pointer; border-bottom: 2px solid transparent; font-weight: 600; font-size: 0.9375rem; color: var(--text-muted); transition: all 0.2s; margin-bottom: -2px; position: relative; z-index: 1; } .tab:hover { color: var(--primary-color); } .tab.active { color: var(--primary-color); border-bottom-color: var(--primary-color); } /* Badges for status indicators */ .badge { display: inline-flex; align-items: center; justify-content: center; border-radius: 9999px; padding: 0.25rem 0.625rem; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.025em; } .badge-success { background-color: rgba(16, 185, 129, 0.1); color: var(--success-color); } .dark-theme .badge-success { background-color: rgba(16, 185, 129, 0.2); } .badge-warning { background-color: rgba(245, 158, 11, 0.1); color: var(--warning-color); } .dark-theme .badge-warning { background-color: rgba(245, 158, 11, 0.2); } .badge-error { background-color: rgba(225, 29, 72, 0.1); color: var(--error-color); } .dark-theme .badge-error { background-color: rgba(225, 29, 72, 0.2); } .badge-info { background-color: rgba(59, 130, 246, 0.1); color: var(--info-color); } .dark-theme .badge-info { background-color: rgba(59, 130, 246, 0.2); } .badge-primary { background-color: rgba(106, 36, 254, 0.1); color: var(--primary-color); } .dark-theme .badge-primary { background-color: rgba(139, 92, 246, 0.2); color: #A78BFA; } /* Character counter with advice */ .character-counter { display: flex; flex-direction: column; font-size: 0.75rem; color: var(--text-muted); margin-top: 0.25rem; transition: color 0.2s; } .character-counter .count { font-weight: 500; } .character-counter .advice { font-size: 0.7rem; opacity: 0.9; margin-top: 0.25rem; } .character-counter.warning { color: var(--warning-color); } .character-counter.error { color: var(--error-color); } .character-counter.success { color: var(--success-color); } .character-counter.info { color: var(--info-color); } /* Creativity slider */ .creativity-slider-container { padding: 1rem; background: linear-gradient(to right, rgba(16, 185, 129, 0.1), rgba(59, 130, 246, 0.1), rgba(139, 92, 246, 0.1)); border-radius: var(--radius-lg); margin: 1rem 0; } .creativity-slider-container .label { display: flex; justify-content: space-between; font-size: 0.875rem; font-weight: 500; margin-bottom: 0.5rem; } .creativity-slider-container .label .value { font-weight: 600; color: var(--primary-color); } /* Model info card */ .model-info { background-color: rgba(106, 36, 254, 0.05); border-left: 3px solid var(--primary-color); padding: 1rem 1.25rem; border-radius: 0 var(--radius) var(--radius) 0; margin: 1rem 0; transition: background-color var(--transition-normal); } .dark-theme .model-info { background-color: rgba(139, 92, 246, 0.1); } .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.75rem 0; font-size: 0.875rem; color: var(--text-color); } .model-info .model-id { font-size: 0.75rem; color: var(--text-muted); font-family: var(--font-mono); background-color: rgba(0, 0, 0, 0.03); padding: 0.25rem 0.5rem; border-radius: 4px; margin-top: 0.5rem; word-break: break-all; } .dark-theme .model-info .model-id { background-color: rgba(255, 255, 255, 0.05); } .model-info .strengths-weaknesses { margin-top: 0.5rem; font-size: 0.8125rem; } .model-info .highlight { font-weight: 600; } .model-info .highlight.positive { color: var(--success-color); } .model-info .highlight.negative { color: var(--warning-color); } .model-info .recommended-for { margin-top: 0.75rem; display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; } .model-info .recommended-for p { margin: 0; font-size: 0.8125rem; display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; } /* Parameter pills */ .parameters-container { background-color: var(--card-color); border-radius: var(--radius-lg); padding: 1rem; margin: 1rem 0; border: 1px solid var(--border-color); transition: background-color var(--transition-normal), border-color var(--transition-normal); } .parameters-title { font-weight: 600; margin-bottom: 0.75rem; font-size: 0.9375rem; color: var(--text-color); } .parameters-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.75rem; } .parameter-pill { display: inline-flex; align-items: center; background-color: rgba(106, 36, 254, 0.08); color: var(--primary-color); border-radius: var(--radius-full); padding: 0.25rem 0.75rem; font-size: 0.75rem; font-weight: 500; user-select: none; transition: background-color var(--transition-normal), color var(--transition-normal); } .dark-theme .parameter-pill { background-color: rgba(139, 92, 246, 0.12); color: #A78BFA; } .parameter-pill .icon { margin-right: 0.25rem; } .parameter-pill.model-pill { background-color: rgba(59, 130, 246, 0.08); color: var(--info-color); } .dark-theme .parameter-pill.model-pill { background-color: rgba(59, 130, 246, 0.12); color: #60A5FA; } .generation-time { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.5rem; } /* Tips card */ .tips-card { background-color: rgba(59, 130, 246, 0.05); border-radius: var(--radius-lg); padding: 1rem 1.25rem; margin: 1rem 0; border-left: 3px solid var(--info-color); transition: background-color var(--transition-normal); } .dark-theme .tips-card { background-color: rgba(59, 130, 246, 0.1); } .tips-card h4 { display: flex; align-items: center; gap: 0.5rem; margin-top: 0; margin-bottom: 0.75rem; font-size: 1rem; color: var(--info-color); } .tips-card ul { margin: 0; padding-left: 1.5rem; } .tips-card li { margin-bottom: 0.5rem; font-size: 0.875rem; } .tips-card li:last-child { margin-bottom: 0; } /* Theme toggle switch */ .theme-toggle { position: fixed; bottom: 1.5rem; right: 1.5rem; background-color: var(--card-color); border-radius: var(--radius-full); box-shadow: var(--shadow-lg); padding: 0.625rem; display: flex; align-items: center; justify-content: center; z-index: 1000; cursor: pointer; border: 1px solid var(--border-color); transition: background-color var(--transition-normal), border-color var(--transition-normal); } .theme-toggle:hover { transform: translateY(-2px); box-shadow: var(--shadow-xl); } .theme-toggle-icon { font-size: 1.25rem; color: var(--text-color); transition: color var(--transition-normal); } /* Tooltip */ .tooltip { position: relative; display: inline-block; } .tooltip .tooltip-text { visibility: hidden; background-color: var(--text-color); color: white; text-align: center; border-radius: var(--radius); padding: 0.5rem 0.75rem; position: absolute; z-index: 1; bottom: 125%; left: 50%; margin-left: -60px; opacity: 0; transition: opacity 0.3s; font-size: 0.75rem; width: 120px; pointer-events: none; } .tooltip .tooltip-text::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 .tooltip-text { visibility: visible; opacity: 1; } /* Image grid for gallery view */ .image-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; margin: 1.5rem 0; } @media (max-width: 768px) { .image-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 0.75rem; } } @media (max-width: 480px) { .image-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 0.5rem; } } /* Empty state illustrations */ .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 3rem 1.5rem; text-align: center; background-color: var(--card-color); border-radius: var(--radius-lg); border: 1px dashed var(--border-color); margin: 1.5rem 0; transition: background-color var(--transition-normal), border-color var(--transition-normal); } .empty-state .icon { font-size: 3rem; margin-bottom: 1.5rem; color: var(--text-muted); } .empty-state h3 { margin: 0 0 0.75rem 0; font-size: 1.25rem; color: var(--text-color); } .empty-state p { margin: 0 0 1.5rem 0; font-size: 0.9375rem; color: var(--text-muted); max-width: 500px; } /* Feature cards */ .feature-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.5rem; margin: 2rem 0; } @media (max-width: 768px) { .feature-grid { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1rem; } } .feature-card { background-color: var(--card-color); border-radius: var(--radius-lg); padding: 1.5rem; box-shadow: var(--shadow); transition: transform 0.2s, box-shadow 0.2s, background-color var(--transition-normal); display: flex; flex-direction: column; border: 1px solid var(--border-color); } .feature-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); } .feature-icon { font-size: 2.5rem; margin-bottom: 1rem; color: var(--primary-color); } .feature-title { font-size: 1.125rem; font-weight: 700; margin: 0 0 0.75rem 0; color: var(--text-color); } .feature-description { font-size: 0.875rem; color: var(--text-muted); margin: 0; flex-grow: 1; } /* Responsive layout adjustments */ @media (max-width: 1200px) { h1 { font-size: 2.25rem !important; } h2 { font-size: 1.75rem !important; } h3 { font-size: 1.375rem !important; } } @media (max-width: 768px) { button.primary, button.secondary { padding: 0.625rem 1.25rem !important; font-size: 0.9375rem !important; } .app-header { padding: 2rem 1rem 1.5rem; } .gallery-item-image { aspect-ratio: 1; } } @media (max-width: 640px) { .tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; white-space: nowrap; padding-bottom: 0.25rem; } .tab { padding: 0.75rem 1rem; } } """ # Create new interface with gr.Blocks(title=APP_CONFIG["name"], css=css) as interface: # Header with branding with gr.Row(elem_classes="app-header"): with gr.Column(): gr.HTML(f"""

{APP_CONFIG["name"]}

{APP_CONFIG["tagline"]}

{APP_CONFIG["description"]}

""") # Main content area - tabs for different sections with gr.Tabs() as tabs: # Create tab with gr.TabItem("Create", id="create-tab") as create_tab: with gr.Row(equal_height=False): # Left column - Input controls with gr.Column(scale=1): # Description input with character counter with gr.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=update_char_count(""), elem_classes="char-counter-container" ) # Settings accordion with gr.Accordion("Image Settings", open=True): # 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" ) # Advanced options with gr.Accordion("Advanced Options", open=False): with gr.Row(): # Aspect ratio dropdown aspect_ratio = gr.Dropdown( choices=format_dropdown_choices(ASPECT_RATIOS), value=f"{ASPECT_RATIOS['1:1 (Square)']['icon']} 1:1 (Square)", label="Aspect Ratio", elem_classes="enhanced-dropdown" ) # Seed input seed_input = gr.Number( label="Seed (optional)", value=None, precision=0, elem_id="seed-input" ) with gr.Row(): # Color palette dropdown color_palette = gr.Dropdown( choices=format_dropdown_choices(COLOR_PALETTES), value=None, label="Color Palette (optional)", elem_classes="enhanced-dropdown" ) # Special effects dropdown special_effect = gr.Dropdown( choices=format_dropdown_choices(SPECIAL_EFFECTS), value=f"{SPECIAL_EFFECTS['None']['icon']} None", label="Special Effect (optional)", elem_classes="enhanced-dropdown" ) # Examples gallery with clear visual structure with gr.Accordion("Try an Example", open=True): # Gallery of examples with gr.Row(elem_classes="gallery"): for i, example in enumerate(EXAMPLE_PROMPTS[:8]): # Show first 8 examples with gr.Column(elem_classes="gallery-item"): # Example card with visual element and caption example_btn = gr.Button( example["thumbnail_desc"], elem_classes="example-button" ) # Event handler for example selection example_btn.click( fn=lambda idx=i: load_example(idx), outputs=[description_input, creation_type, art_style, mood_dropdown, aspect_ratio, color_palette, special_effect] ) # Generate buttons with batch option with gr.Row(): # Single image generation generate_btn = gr.Button("โœจ Generate Image", variant="primary", elem_classes="primary", elem_id="generate-btn") # Generate multiple variations variations_btn = gr.Button("๐Ÿ”„ Generate 4 Variations", elem_classes="secondary", elem_id="variations-btn") # Generation status message generation_status = gr.HTML(value="", elem_classes="generation-status") # Right column - Output display with gr.Column(scale=1): # Tabs for single image and variations with gr.Tabs() as image_tabs: # Single image tab with gr.TabItem("Image", id="single-tab"): # Image display area with placeholder with gr.Group(elem_classes="output-container"): image_output = gr.Image( label="Generated Image", elem_id="image-output", type="pil", height=512, interactive=False ) # Action buttons for generated image with gr.Row(): # Download button download_btn = gr.Button("๐Ÿ’พ Save Image", elem_classes="secondary") # Add to favorites favorite_btn = gr.Button("โค๏ธ Add to Favorites", elem_classes="secondary") # Generate variations of this image more_variations_btn = gr.Button("๐Ÿ”„ More Like This", elem_classes="secondary") # Image generation details with gr.Accordion("Image Details", open=True): parameters_display = gr.HTML(value="") # Enhanced prompt display with gr.Accordion("AI-Enhanced Prompt", open=False): prompt_output = gr.Textbox( label="AI-Enhanced Prompt Used", lines=5, elem_id="prompt-output", elem_classes="prompt-display" ) # Variations tab with gr.TabItem("Variations", id="variations-tab"): # Variations gallery with gr.Group(elem_classes="variations-gallery"): variations_gallery = gr.Gallery( label="Image Variations", elem_id="variations-gallery", columns=2, rows=2, height=512, object_fit="contain" ) # Variations info variations_info = gr.HTML(value="") # Information panels for selected options with gr.Group(elem_classes="info-panels"): # Creation type info creation_info = gr.HTML(value="", elem_classes="creation-info") # Art style info art_info = gr.HTML(value="", elem_classes="art-info") # Model info panel model_info = gr.HTML(value="", elem_classes="model-info") # Mood info mood_info = gr.HTML(value="", elem_classes="mood-info") # Gallery tab with history and favorites with gr.TabItem("My Creations", id="gallery-tab") as gallery_tab: with gr.Tabs() as gallery_tabs: # History tab with gr.TabItem("History", id="history-tab"): # History toolbar with gr.Row(): refresh_history_btn = gr.Button("๐Ÿ”„ Refresh", elem_classes="secondary") clear_history_btn = gr.Button("๐Ÿ—‘๏ธ Clear History", elem_classes="secondary") # History gallery history_gallery = gr.Gallery( label="Your Generated Images", elem_id="history-gallery", columns=4, rows=3, height=600, object_fit="contain" ) # History info history_info = gr.HTML(value="") # Favorites tab with gr.TabItem("Favorites", id="favorites-tab"): # Favorites toolbar with gr.Row(): refresh_favorites_btn = gr.Button("๐Ÿ”„ Refresh", elem_classes="secondary") # Favorites gallery favorites_gallery = gr.Gallery( label="Your Favorite Images", elem_id="favorites-gallery", columns=4, rows=3, height=600, object_fit="contain" ) # Favorites info favorites_info = gr.HTML(value="") # Explore tab with creative examples and guided mode with gr.TabItem("Explore", id="explore-tab") as explore_tab: with gr.Tabs() as explore_tabs: # Creative prompts tab with gr.TabItem("Inspiration", id="inspiration-tab"): gr.HTML("""
๐Ÿง™

Fantasy Worlds

Explore magical realms, mythical creatures, and enchanted landscapes from your imagination.

๐Ÿš€

Sci-Fi Visions

Create futuristic technology, alien worlds, and space adventures in stunning detail.

๐ŸŒŒ

Cosmic Dreams

Visualize galaxies, nebulae, and celestial phenomena beyond human imagination.

๐Ÿ‘ค

Character Design

Bring unique characters to life for stories, games, or personal projects.

๐Ÿ™๏ธ

Cityscape Concepts

Design futuristic cities, cyberpunk streets, or nostalgic urban environments.

๐ŸŽจ

Artistic Styles

Experiment with different art styles from renaissance to modern abstract expressions.

""") # Creative prompts gallery creative_prompts = gr.Gallery( label="Trending Creations", elem_id="creative-prompts", columns=3, rows=2, height=500, object_fit="contain" ) # Guided creation tab with gr.TabItem("Guided Creation", id="guided-tab"): gr.HTML("""

โœจ Guided Creation Mode

Answer the questions below to create a detailed prompt. Our AI will help you transform your ideas into amazing images.

""") # Step-by-step guided prompt creation with gr.Group(): # Subject guided_subject = gr.Textbox( label="What is the main subject?", placeholder="Examples: a majestic dragon, a cybernetic samurai, a cozy cottage...", elem_id="guided-subject" ) # Setting guided_setting = gr.Textbox( label="Where is it located? (Setting/Environment)", placeholder="Examples: in a misty forest, on a distant planet, in a futuristic city...", elem_id="guided-setting" ) # Lighting and atmosphere guided_lighting = gr.Textbox( label="Describe the lighting and atmosphere", placeholder="Examples: sunset with golden rays, blue moonlight, neon lights...", elem_id="guided-lighting" ) # Additional details guided_details = gr.Textbox( label="Additional details (optional)", placeholder="Examples: wearing a red cloak, with glowing eyes, surrounded by flowers...", elem_id="guided-details" ) # Style preferences with gr.Row(): guided_art_style = gr.Dropdown( choices=format_dropdown_choices(ART_STYLES), value=f"{ART_STYLES['Photorealistic']['icon']} Photorealistic", label="Art Style", elem_classes="enhanced-dropdown" ) guided_mood = gr.Dropdown( choices=format_dropdown_choices(MOODS), value=f"{MOODS['Peaceful']['icon']} Peaceful", label="Mood", elem_classes="enhanced-dropdown" ) # Build prompt button build_prompt_btn = gr.Button("๐Ÿช„ Build My Prompt", variant="primary", elem_classes="primary") # Generated prompt preview guided_preview = gr.Textbox( label="Your Generated Prompt", lines=4, elem_id="guided-preview" ) # Use this prompt button use_prompt_btn = gr.Button("โœ… Use This Prompt", elem_classes="secondary") # Settings tab with gr.TabItem("Settings", id="settings-tab") as settings_tab: with gr.Tabs() as settings_tabs: # Appearance settings with gr.TabItem("Appearance", id="appearance-tab"): # Theme selector theme_selector = gr.Radio( choices=["Light", "Dark", "Auto"], value=current_user.preferences["theme"], label="Theme", elem_id="theme-selector" ) # Apply button apply_theme_btn = gr.Button("Apply Theme", elem_classes="secondary") # Defaults settings with gr.TabItem("Defaults", id="defaults-tab"): # Default model default_model = gr.Dropdown( choices=formatted_models, value=f"{IMAGE_MODELS[current_user.preferences['default_model']]['icon']} {IMAGE_MODELS[current_user.preferences['default_model']]['display_name']}", label="Default Model", elem_classes="enhanced-dropdown" ) # Default creation type default_creation_type = gr.Dropdown( choices=format_dropdown_choices(CREATION_TYPES), value=f"{CREATION_TYPES[current_user.preferences['default_creation_type']]['icon']} {current_user.preferences['default_creation_type']}", label="Default Creation Type", elem_classes="enhanced-dropdown" ) # Default aspect ratio default_aspect_ratio = gr.Dropdown( choices=format_dropdown_choices(ASPECT_RATIOS), value=f"{ASPECT_RATIOS[current_user.preferences['default_aspect_ratio']]['icon']} {current_user.preferences['default_aspect_ratio']}", label="Default Aspect Ratio", elem_classes="enhanced-dropdown" ) # Show tips show_tips = gr.Checkbox( value=current_user.preferences["show_tips"], label="Show Tips and Suggestions", elem_id="show-tips" ) # Advanced mode advanced_mode = gr.Checkbox( value=current_user.preferences["advanced_mode"], label="Advanced Mode (Show all options by default)", elem_id="advanced-mode" ) # Save defaults button save_defaults_btn = gr.Button("Save Defaults", elem_classes="secondary") # About tab with gr.TabItem("About", id="about-tab"): gr.HTML(f"""

{APP_CONFIG["name"]} v{APP_CONFIG["version"]}

{APP_CONFIG["tagline"]}

About This Application

Imaginova is a powerful AI image generation platform that helps you bring your creative visions to life. Built with advanced diffusion models, Imaginova transforms your text descriptions into stunning, high-quality images across various styles and artistic mediums.

Features

  • Multiple AI Models: Access to several state-of-the-art image generation models
  • Creative Control: Customize your images with different styles, moods, and special effects
  • Prompt Enhancement: AI-powered prompt improvement for better results
  • Guided Creation: Step-by-step assistance to build detailed prompts
  • Image History: Save and organize your creations
  • Batch Generation: Create multiple variations of your ideas

Credits

Powered by Hugging Face's Diffusion Models and built with Gradio.

Created with โค๏ธ for the creative community.

""") # Hidden elements for state management current_seed = gr.Number(value=None, visible=False) current_image_id = gr.Textbox(value="", visible=False) # Event handlers # Character counter update description_input.change( fn=update_char_count, inputs=description_input, outputs=char_counter ) # Info panels updates 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 ) mood_dropdown.change( fn=update_mood_info, inputs=mood_dropdown, outputs=mood_info ) # Generate image button generate_btn.click( fn=generate_with_status, inputs=[ description_input, creation_type, art_style, mood_dropdown, aspect_ratio, color_palette, special_effect, model_selector, seed_input ], outputs=[ image_output, generation_status, prompt_output, parameters_display, current_seed ] ) # Add generated image to history def add_to_history_handler(image, description, prompt, parameters, seed): """Add the generated image to user history""" if image is None: return gr.HTML.update(value="No image to save") # Add to history image_id = str(uuid.uuid4()) success = current_user.add_to_history(image, description, prompt, parameters, seed) if success: return gr.Textbox.update(value=image_id) else: return gr.Textbox.update(value="") # After successful generation, add to history image_output.change( fn=add_to_history_handler, inputs=[ image_output, description_input, prompt_output, parameters_display, current_seed ], outputs=[current_image_id] ) # Generate variations def generate_variations_handler(description, creation_type_val, art_style_val, mood_val, aspect_ratio_val, color_palette_val, special_effect_val, model_name): """Generate multiple variations of an image""" try: # 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) aspect_key = extract_key(aspect_ratio_val) palette_key = extract_key(color_palette_val) effect_key = extract_key(special_effect_val) # Get model key model_key = get_model_key_from_display_name(model_name) # Generate variations (4 by default) results = generate_variations( description, model_key, creation_key, art_key, mood_key, aspect_key, palette_key, effect_key, num_images=4 ) # Extract images and seeds images = [img for img, _ in results] seeds = [seed for _, seed in results] # Create info text if images: seeds_text = ", ".join([str(s) for s in seeds]) info_html = f"""
โœ… Generated {len(images)} variations successfully. Seeds: {seeds_text}
""" else: info_html = """
โŒ Failed to generate variations. Please try again.
""" # Switch to variations tab image_tabs.select("variations-tab") return images, info_html except Exception as e: error_html = f"""
โŒ Error generating variations: {str(e)}
""" return [], error_html # Variations button click variations_btn.click( fn=generate_variations_handler, inputs=[ description_input, creation_type, art_style, mood_dropdown, aspect_ratio, color_palette, special_effect, model_selector ], outputs=[ variations_gallery, variations_info ] ) # Guided creation handlers def build_guided_prompt(subject, setting, lighting, details, art_style_val, mood_val): """Build a detailed prompt from guided inputs""" if not subject: return "Please describe the main subject first" # Extract keys art_key = extract_key(art_style_val) mood_key = extract_key(mood_val) # Get art style info art_style_desc = "" if art_key and art_key in ART_STYLES: art_info = ART_STYLES[art_key] style_terms = ", ".join(art_info.get("technical_terms", [])[:2]) art_style_desc = f"in {art_key} style, {style_terms}" # Get mood info mood_desc = "" if mood_key and mood_key in MOODS: mood_info = MOODS[mood_key] mood_desc = f"with {mood_key.lower()} mood, {mood_info.get('lighting', '')}" # Build prompt parts prompt_parts = [] # Main subject prompt_parts.append(subject.strip()) # Setting/environment if setting: prompt_parts.append(setting.strip()) # Lighting and atmosphere if lighting: prompt_parts.append(lighting.strip()) # Additional details if details: prompt_parts.append(details.strip()) # Style and mood if art_style_desc: prompt_parts.append(art_style_desc) if mood_desc: prompt_parts.append(mood_desc) # Quality terms quality_terms = "highly detailed, masterful, 8K resolution, professional, sharp focus, high quality" prompt_parts.append(quality_terms) # Build final prompt prompt = ", ".join(prompt_parts) return prompt # Build prompt button build_prompt_btn.click( fn=build_guided_prompt, inputs=[ guided_subject, guided_setting, guided_lighting, guided_details, guided_art_style, guided_mood ], outputs=[guided_preview] ) # Use guided prompt def use_guided_prompt(prompt): """Use the guided prompt in the main create tab""" # Switch to create tab tabs.select("create-tab") return prompt # Use prompt button use_prompt_btn.click( fn=use_guided_prompt, inputs=[guided_preview], outputs=[description_input] ) # History and favorites handlers def load_history(): """Load user history for gallery display""" history = current_user.get_history() if not history: info_html = """
๐Ÿ–ผ๏ธ

No Images Yet

Your created images will appear here. Start generating to build your collection!

""" return [], info_html # Extract images images = [entry.get("image") for entry in history if "image" in entry] info_html = f"""

Showing {len(images)} images from your history

""" return images, info_html # Load history on tab click gallery_tab.select( fn=load_history, inputs=[], outputs=[history_gallery, history_info] ) # Refresh history button refresh_history_btn.click( fn=load_history, inputs=[], outputs=[history_gallery, history_info] ) # Clear history button def clear_history(): """Clear user history""" success = current_user.clear_history() if success: info_html = """
โœ… History cleared successfully
""" else: info_html = """
โŒ Failed to clear history
""" return [], info_html # Clear history button clear_history_btn.click( fn=clear_history, inputs=[], outputs=[history_gallery, history_info] ) # Load favorites def load_favorites(): """Load user favorites for gallery display""" favorites = current_user.get_favorites() if not favorites: info_html = """
โค๏ธ

No Favorites Yet

Your favorite images will appear here. Add images to favorites to build your collection!

""" return [], info_html # Extract images images = [entry.get("image") for entry in favorites if "image" in entry] info_html = f"""

Showing {len(images)} favorite images

""" return images, info_html # Refresh favorites button refresh_favorites_btn.click( fn=load_favorites, inputs=[], outputs=[favorites_gallery, favorites_info] ) # Add to favorites def add_to_favorites(image_id): """Add an image to favorites""" if not image_id: return """
โŒ No image to add to favorites
""" success = current_user.add_to_favorites(image_id) if success: return """
โœ… Image added to favorites
""" else: return """
โš ๏ธ Image already in favorites or not found
""" # Add to favorites button favorite_btn.click( fn=add_to_favorites, inputs=[current_image_id], outputs=[generation_status] ) # Update theme def update_theme(theme): """Update user theme preference""" if theme not in ["Light", "Dark", "Auto"]: theme = "Light" current_user.update_preferences({"theme": theme}) # Return HTML with embedded JavaScript if theme == "Dark": return gr.HTML(""" """) elif theme == "Light": return gr.HTML(""" """) else: # Auto return gr.HTML(""" """) # Update default settings def update_defaults(model, creation_type, aspect_ratio, show_tips, advanced_mode): """Update user default settings""" # Extract values model_key = get_model_key_from_display_name(model) creation_key = extract_key(creation_type) aspect_key = extract_key(aspect_ratio) # Update preferences preferences = { "default_model": model_key, "default_creation_type": creation_key, "default_aspect_ratio": aspect_key, "show_tips": show_tips, "advanced_mode": advanced_mode } success = current_user.update_preferences(preferences) if success: return """
โœ… Default settings saved successfully
""" else: return """
โŒ Failed to save default settings
""" # Save defaults button save_defaults_btn.click( fn=update_defaults, inputs=[ default_model, default_creation_type, default_aspect_ratio, show_tips, advanced_mode ], outputs=[gr.HTML()] ) # Load default values on page load # 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']}"), update_mood_info(f"{MOODS['Peaceful']['icon']} Peaceful"), # Initial theme setting based on user preference update_theme(current_user.preferences["theme"]) ), outputs=[creation_info, art_info, model_info, mood_info, gr.Javascript()] ) return interface # =============== MAIN APPLICATION FLOW =============== def main(): """Main application entry point - creates UI and sets up event handlers""" logger.info(f"Starting {APP_CONFIG['name']} v{APP_CONFIG['version']}") # Create the UI components interface = create_ui() # Launch the interface launch_kwargs = {} # If running in Hugging Face Spaces if APP_CONFIG["huggingface_space"]: launch_kwargs.update({ "share": False, "server_name": "0.0.0.0", "server_port": 7860 }) else: # For local development launch_kwargs.update({ "share": False, "server_name": "127.0.0.1", "server_port": 7860 }) try: interface.launch(**launch_kwargs) except Exception as e: logger.error(f"Error launching interface: {str(e)}") interface.launch() # Fallback to default launch # Entry point if __name__ == "__main__": main()