| |
| """ |
| 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") |