| | |
| | """ |
| | AI Background Generator Module - Gradient-Only Version |
| | Handles background generation with smart gradient fallbacks when AI libraries conflict. |
| | """ |
| |
|
| | import os |
| | import sys |
| | import tempfile |
| | import random |
| | import logging |
| | from pathlib import Path |
| | from typing import Optional, Tuple |
| | import io |
| | import base64 |
| |
|
| | |
| | logging.basicConfig(level=logging.INFO) |
| | logger = logging.getLogger(__name__) |
| |
|
| | |
| | PIL_AVAILABLE = False |
| | TORCH_AVAILABLE = False |
| | DIFFUSERS_AVAILABLE = False |
| |
|
| | try: |
| | from PIL import Image, ImageDraw, ImageFilter |
| | PIL_AVAILABLE = True |
| | logger.info("β
PIL imported successfully") |
| | except ImportError as e: |
| | logger.error(f"β PIL import failed: {e}") |
| |
|
| | |
| | try: |
| | import torch |
| | TORCH_AVAILABLE = True |
| | logger.info("β
PyTorch available") |
| | |
| | |
| | if hasattr(torch.library, 'custom_op'): |
| | logger.info("β
PyTorch custom_op available") |
| | else: |
| | logger.warning("β οΈ PyTorch custom_op not available - diffusers will likely fail") |
| | |
| | except ImportError: |
| | logger.warning("β οΈ PyTorch not available") |
| | except AttributeError: |
| | logger.warning("β οΈ PyTorch version incompatible (missing torch.library)") |
| | except Exception as e: |
| | logger.warning(f"β οΈ PyTorch check failed: {e}") |
| |
|
| | |
| | FORCE_GRADIENT_MODE = False |
| |
|
| | if TORCH_AVAILABLE: |
| | try: |
| | |
| | import torch |
| | if not hasattr(torch.library, 'custom_op'): |
| | logger.warning("π Force enabling gradient-only mode due to torch.library.custom_op missing") |
| | FORCE_GRADIENT_MODE = True |
| | else: |
| | |
| | try: |
| | |
| | import importlib.util |
| | spec = importlib.util.find_spec("diffusers") |
| | if spec is not None: |
| | |
| | from diffusers import __version__ |
| | logger.info(f"β
Diffusers {__version__} detected and compatible") |
| | DIFFUSERS_AVAILABLE = True |
| | else: |
| | logger.info("βΉοΈ Diffusers not installed") |
| | except Exception as e: |
| | if "custom_op" in str(e): |
| | logger.warning("π Detected custom_op compatibility issue - using gradient-only mode") |
| | FORCE_GRADIENT_MODE = True |
| | else: |
| | logger.warning(f"π Diffusers import issue: {e}") |
| | except Exception as e: |
| | logger.warning(f"π PyTorch/Diffusers compatibility check failed: {e}") |
| | FORCE_GRADIENT_MODE = True |
| | else: |
| | logger.info("βΉοΈ Skipping diffusers check - PyTorch not available") |
| |
|
| | |
| | if FORCE_GRADIENT_MODE: |
| | DIFFUSERS_AVAILABLE = False |
| |
|
| | class AIBackgroundGenerator: |
| | """ |
| | AI Background Generator with intelligent gradient fallbacks |
| | """ |
| | |
| | def __init__(self): |
| | self.pipeline = None |
| | self.device = "cpu" |
| | |
| | |
| | self.color_themes = { |
| | |
| | 'blue': [(64, 128, 255), (0, 64, 128)], |
| | 'ocean': [(0, 119, 190), (0, 64, 128)], |
| | 'sky': [(135, 206, 250), (25, 25, 112)], |
| | 'water': [(0, 191, 255), (0, 100, 200)], |
| | 'azure': [(240, 255, 255), (0, 127, 255)], |
| | |
| | |
| | 'green': [(34, 139, 34), (0, 100, 0)], |
| | 'nature': [(107, 142, 35), (34, 139, 34)], |
| | 'forest': [(34, 139, 34), (0, 50, 0)], |
| | 'grass': [(124, 252, 0), (34, 139, 34)], |
| | 'mint': [(152, 251, 152), (0, 128, 0)], |
| | |
| | |
| | 'professional': [(105, 105, 105), (169, 169, 169)], |
| | 'office': [(192, 192, 192), (105, 105, 105)], |
| | 'corporate': [(70, 130, 180), (25, 25, 112)], |
| | 'business': [(47, 79, 79), (112, 128, 144)], |
| | 'modern': [(95, 158, 160), (47, 79, 79)], |
| | |
| | |
| | 'dark': [(64, 64, 64), (0, 0, 0)], |
| | 'night': [(25, 25, 112), (0, 0, 0)], |
| | 'black': [(105, 105, 105), (0, 0, 0)], |
| | 'shadow': [(85, 85, 85), (0, 0, 0)], |
| | |
| | |
| | 'warm': [(255, 140, 0), (255, 69, 0)], |
| | 'sunset': [(255, 94, 77), (255, 154, 0)], |
| | 'orange': [(255, 165, 0), (255, 69, 0)], |
| | 'fire': [(255, 69, 0), (139, 0, 0)], |
| | |
| | |
| | 'purple': [(147, 112, 219), (75, 0, 130)], |
| | 'violet': [(138, 43, 226), (75, 0, 130)], |
| | 'lavender': [(230, 230, 250), (147, 112, 219)], |
| | |
| | |
| | 'red': [(220, 20, 60), (139, 0, 0)], |
| | 'pink': [(255, 182, 193), (255, 20, 147)], |
| | 'yellow': [(255, 255, 0), (255, 215, 0)], |
| | 'gold': [(255, 215, 0), (184, 134, 11)], |
| | |
| | |
| | 'tech': [(0, 255, 255), (0, 0, 139)], |
| | 'digital': [(138, 43, 226), (25, 25, 112)], |
| | 'cyber': [(0, 255, 127), (0, 100, 0)], |
| | 'neon': [(255, 20, 147), (138, 43, 226)], |
| | |
| | |
| | 'default': [(100, 149, 237), (65, 105, 225)] |
| | } |
| | |
| | |
| | if DIFFUSERS_AVAILABLE and not FORCE_GRADIENT_MODE: |
| | logger.info("π¨ Attempting to initialize AI pipeline...") |
| | self._init_diffusers() |
| | else: |
| | logger.info("π¨ Using gradient-only mode") |
| | |
| | def _init_diffusers(self): |
| | """Initialize the Stable Diffusion pipeline (only if safe)""" |
| | |
| | try: |
| | from diffusers import StableDiffusionPipeline |
| | |
| | model_id = "runwayml/stable-diffusion-v1-5" |
| | |
| | if torch.cuda.is_available(): |
| | self.device = "cuda" |
| | logger.info("π Using CUDA device") |
| | else: |
| | self.device = "cpu" |
| | logger.info("π₯οΈ Using CPU device") |
| | |
| | self.pipeline = StableDiffusionPipeline.from_pretrained( |
| | model_id, |
| | torch_dtype=torch.float16 if self.device == "cuda" else torch.float32, |
| | safety_checker=None, |
| | requires_safety_checker=False |
| | ).to(self.device) |
| | |
| | |
| | if self.device == "cuda": |
| | self.pipeline.enable_memory_efficient_attention() |
| | self.pipeline.enable_attention_slicing() |
| | |
| | logger.info("β
AI pipeline initialized successfully") |
| | |
| | except Exception as e: |
| | logger.error(f"β Failed to initialize AI pipeline: {e}") |
| | self.pipeline = None |
| | global DIFFUSERS_AVAILABLE |
| | DIFFUSERS_AVAILABLE = False |
| | |
| | def _analyze_prompt_theme(self, prompt: str) -> str: |
| | """Analyze prompt to determine appropriate color theme""" |
| | prompt_lower = prompt.lower() |
| | |
| | |
| | for theme in self.color_themes: |
| | if theme in prompt_lower: |
| | return theme |
| | |
| | |
| | keyword_map = { |
| | |
| | ('water', 'sea', 'lake', 'river', 'stream'): 'ocean', |
| | ('sky', 'cloud', 'air'): 'sky', |
| | |
| | |
| | ('tree', 'plant', 'garden', 'leaf', 'flower'): 'nature', |
| | ('grass', 'field', 'meadow'): 'grass', |
| | |
| | |
| | ('business', 'meeting', 'work', 'conference'): 'business', |
| | ('company', 'enterprise', 'corporate'): 'corporate', |
| | |
| | |
| | ('evening', 'midnight', 'shadow', 'darkness'): 'night', |
| | ('fire', 'flame', 'autumn', 'fall'): 'fire', |
| | ('morning', 'sunrise', 'dawn'): 'warm', |
| | |
| | |
| | ('technology', 'computer', 'digital', 'software'): 'tech', |
| | ('cyber', 'virtual', 'matrix'): 'cyber', |
| | ('neon', 'electric', 'bright'): 'neon', |
| | |
| | |
| | ('calm', 'peaceful', 'serene'): 'azure', |
| | ('energetic', 'vibrant', 'active'): 'orange', |
| | ('elegant', 'sophisticated', 'luxury'): 'purple', |
| | ('fresh', 'clean', 'pure'): 'mint', |
| | } |
| | |
| | for keywords, theme in keyword_map.items(): |
| | if any(keyword in prompt_lower for keyword in keywords): |
| | return theme |
| | |
| | return 'default' |
| | |
| | def _create_gradient_background(self, width: int = 1024, height: int = 768, |
| | theme: str = 'default') -> Image.Image: |
| | """Create a sophisticated gradient background""" |
| | if not PIL_AVAILABLE: |
| | raise RuntimeError("PIL is not available for gradient generation") |
| | |
| | |
| | colors = self.color_themes.get(theme, self.color_themes['default']) |
| | color1, color2 = colors |
| | |
| | |
| | image = Image.new('RGB', (width, height)) |
| | draw = ImageDraw.Draw(image) |
| | |
| | |
| | for y in range(height): |
| | |
| | factor = y / height |
| | |
| | factor = factor * factor * (3.0 - 2.0 * factor) |
| | |
| | |
| | r = int(color1[0] * (1 - factor) + color2[0] * factor) |
| | g = int(color1[1] * (1 - factor) + color2[1] * factor) |
| | b = int(color1[2] * (1 - factor) + color2[2] * factor) |
| | |
| | |
| | draw.line([(0, y), (width, y)], fill=(r, g, b)) |
| | |
| | |
| | self._add_texture(image, theme) |
| | |
| | return image |
| | |
| | def _add_texture(self, image: Image.Image, theme: str): |
| | """Add subtle texture to make gradients more interesting""" |
| | width, height = image.size |
| | |
| | |
| | texture = Image.new('RGBA', (width, height), (0, 0, 0, 0)) |
| | texture_draw = ImageDraw.Draw(texture) |
| | |
| | |
| | if theme in ['tech', 'digital', 'cyber']: |
| | |
| | grid_size = 50 |
| | for x in range(0, width, grid_size): |
| | texture_draw.line([(x, 0), (x, height)], fill=(255, 255, 255, 5)) |
| | for y in range(0, height, grid_size): |
| | texture_draw.line([(0, y), (width, y)], fill=(255, 255, 255, 5)) |
| | |
| | elif theme in ['nature', 'forest', 'grass']: |
| | |
| | for _ in range(width * height // 200): |
| | x = random.randint(0, width - 1) |
| | y = random.randint(0, height - 1) |
| | size = random.randint(1, 3) |
| | brightness = random.randint(10, 30) |
| | texture_draw.ellipse([(x, y), (x+size, y+size)], |
| | fill=(brightness, brightness, brightness, 20)) |
| | |
| | else: |
| | |
| | for _ in range(width * height // 300): |
| | x = random.randint(0, width - 1) |
| | y = random.randint(0, height - 1) |
| | brightness = random.randint(-15, 15) |
| | alpha = random.randint(5, 15) |
| | texture_draw.point((x, y), fill=(brightness, brightness, brightness, alpha)) |
| | |
| | |
| | image.paste(texture, (0, 0), texture) |
| | |
| | |
| | image = image.filter(ImageFilter.GaussianBlur(radius=0.8)) |
| | |
| | def generate_background(self, prompt: str, width: int = 1024, height: int = 768, |
| | guidance_scale: float = 7.5, num_inference_steps: int = 20) -> Optional[Image.Image]: |
| | """ |
| | Generate a background image from a text prompt. |
| | Uses gradients with intelligent theming. |
| | """ |
| | |
| | if not PIL_AVAILABLE: |
| | logger.error("β Cannot generate backgrounds - PIL not available") |
| | return None |
| | |
| | |
| | if DIFFUSERS_AVAILABLE and not FORCE_GRADIENT_MODE and self.pipeline is not None: |
| | try: |
| | logger.info(f"π¨ Attempting AI generation for: '{prompt}'") |
| | |
| | enhanced_prompt = f"{prompt}, high quality, detailed, professional background, 8k" |
| | |
| | with torch.no_grad(): |
| | result = self.pipeline( |
| | enhanced_prompt, |
| | width=width, |
| | height=height, |
| | guidance_scale=guidance_scale, |
| | num_inference_steps=num_inference_steps, |
| | negative_prompt="low quality, blurry, distorted, watermark, text" |
| | ) |
| | |
| | if result.images and len(result.images) > 0: |
| | logger.info("β
AI background generated successfully") |
| | return result.images[0] |
| | |
| | except Exception as e: |
| | logger.warning(f"β οΈ AI generation failed, using gradient: {e}") |
| | |
| | |
| | logger.info(f"π¨ Creating gradient background for: '{prompt}'") |
| | theme = self._analyze_prompt_theme(prompt) |
| | logger.info(f"π― Selected theme: '{theme}'") |
| | |
| | try: |
| | image = self._create_gradient_background(width, height, theme) |
| | if image: |
| | logger.info("β
Gradient background generated successfully") |
| | return image |
| | else: |
| | logger.error("β Gradient generation returned None") |
| | return None |
| | except Exception as e: |
| | logger.error(f"β Gradient generation failed: {e}") |
| | return None |
| | |
| | def save_background(self, image: Image.Image, output_path: str) -> bool: |
| | """Save the generated background image""" |
| | try: |
| | |
| | Path(output_path).parent.mkdir(parents=True, exist_ok=True) |
| | |
| | |
| | image.save(output_path, format='PNG', quality=95, optimize=True) |
| | logger.info(f"πΎ Background saved to: {output_path}") |
| | return True |
| | |
| | except Exception as e: |
| | logger.error(f"β Failed to save background: {e}") |
| | return False |
| | |
| | def get_background_base64(self, image: Image.Image) -> str: |
| | """Convert background image to base64 string""" |
| | try: |
| | buffer = io.BytesIO() |
| | image.save(buffer, format='PNG') |
| | img_str = base64.b64encode(buffer.getvalue()).decode() |
| | return img_str |
| | except Exception as e: |
| | logger.error(f"β Failed to convert to base64: {e}") |
| | return "" |
| |
|
| | |
| | def generate_ai_background(prompt: str, width: int = 1024, height: int = 768) -> Optional[Image.Image]: |
| | """ |
| | Quick function to generate a background. |
| | |
| | Args: |
| | prompt: Text description of the desired background |
| | width: Image width in pixels |
| | height: Image height in pixels |
| | |
| | Returns: |
| | PIL Image object or None if generation fails |
| | """ |
| | try: |
| | generator = AIBackgroundGenerator() |
| | return generator.generate_background(prompt, width, height) |
| | except Exception as e: |
| | logger.error(f"β Background generation failed: {e}") |
| | return None |
| |
|
| | def test_background_generation(): |
| | """Test function to verify the background generator is working""" |
| | print("\n" + "="*60) |
| | print("π§ͺ AI BACKGROUND GENERATOR COMPATIBILITY TEST") |
| | print("="*60) |
| | |
| | print(f"π¦ PIL Available: {'β
' if PIL_AVAILABLE else 'β'}") |
| | print(f"π₯ PyTorch Available: {'β
' if TORCH_AVAILABLE else 'β'}") |
| | print(f"π¨ Diffusers Available: {'β
' if DIFFUSERS_AVAILABLE else 'β'}") |
| | print(f"π Force Gradient Mode: {'β
' if FORCE_GRADIENT_MODE else 'β'}") |
| | |
| | if not PIL_AVAILABLE: |
| | print("\nβ CRITICAL: Cannot generate backgrounds - PIL not available") |
| | return False |
| | |
| | mode = "AI (Stable Diffusion)" if (DIFFUSERS_AVAILABLE and not FORCE_GRADIENT_MODE) else "Gradient Fallback" |
| | print(f"\nπ― Generation Mode: {mode}") |
| | |
| | |
| | test_cases = [ |
| | ("professional blue office", "Should produce blue professional gradient"), |
| | ("ocean sunset background", "Should produce ocean-themed gradient"), |
| | ("dark tech cyber background", "Should produce dark tech gradient"), |
| | ("green nature forest", "Should produce green nature gradient") |
| | ] |
| | |
| | print(f"\nπ Testing {len(test_cases)} different prompts...") |
| | |
| | success_count = 0 |
| | for i, (prompt, expected) in enumerate(test_cases, 1): |
| | print(f"\nπ Test {i}: '{prompt}'") |
| | print(f" Expected: {expected}") |
| | |
| | try: |
| | image = generate_ai_background(prompt, 400, 300) |
| | |
| | if image: |
| | print(f" β
Generated: {image.size} {image.mode} image") |
| | success_count += 1 |
| | |
| | |
| | test_path = f"test_bg_{i}.png" |
| | try: |
| | image.save(test_path) |
| | print(f" πΎ Saved: {test_path}") |
| | except Exception as save_error: |
| | print(f" β οΈ Save failed: {save_error}") |
| | else: |
| | print(" β Generation failed - returned None") |
| | |
| | except Exception as e: |
| | print(f" β Generation error: {e}") |
| | |
| | print(f"\n" + "="*60) |
| | print(f"π RESULTS: {success_count}/{len(test_cases)} tests passed") |
| | |
| | if success_count == len(test_cases): |
| | print("π ALL TESTS PASSED! Background generator is working perfectly.") |
| | return True |
| | elif success_count > 0: |
| | print("β οΈ PARTIAL SUCCESS: Some backgrounds generated successfully.") |
| | return True |
| | else: |
| | print("β ALL TESTS FAILED: Background generator is not working.") |
| | return False |
| |
|
| | |
| | if __name__ == "__main__": |
| | |
| | success = test_background_generation() |
| | |
| | if success: |
| | print(f"\nπ Ready to generate backgrounds!") |
| | print(f"π‘ Usage example:") |
| | print(f" from ai_background import generate_ai_background") |
| | print(f" image = generate_ai_background('your prompt here')") |
| | print(f" image.save('background.png')") |
| | else: |
| | print(f"\nβ οΈ Please check the error messages above.") |
| | print(f"π‘ Make sure PIL (Pillow) is installed: pip install Pillow") |