File size: 19,578 Bytes
038cd8a 136b95f 038cd8a 878513c 038cd8a 878513c 038cd8a 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 038cd8a 136b95f 038cd8a 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 038cd8a 878513c 136b95f 038cd8a 136b95f 878513c 136b95f 878513c 136b95f 038cd8a 878513c 038cd8a 878513c 136b95f 038cd8a 136b95f 878513c b369c04 878513c b369c04 136b95f 878513c 136b95f 878513c 136b95f 878513c b369c04 136b95f 878513c b369c04 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f b369c04 136b95f 878513c 136b95f 878513c 136b95f b369c04 878513c 038cd8a 878513c 136b95f 038cd8a 136b95f 878513c 136b95f 038cd8a 878513c 038cd8a 878513c 038cd8a 878513c 136b95f 878513c 038cd8a 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 038cd8a 136b95f 878513c 038cd8a 136b95f 878513c 136b95f 878513c 038cd8a 136b95f 878513c 038cd8a 878513c 038cd8a 878513c 136b95f 038cd8a 136b95f 31e6321 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 878513c 136b95f 7f13b76 136b95f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
#!/usr/bin/env python3
"""
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
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Safe imports only
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}")
# Check PyTorch availability but don't import if problematic
try:
import torch
TORCH_AVAILABLE = True
logger.info("β
PyTorch available")
# Test for the specific custom_op issue
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}")
# NEVER attempt to import diffusers if we detect the custom_op issue
FORCE_GRADIENT_MODE = False
if TORCH_AVAILABLE:
try:
# First, check if torch.library.custom_op exists
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:
# Only try diffusers if custom_op exists
try:
# Quick test import to see if diffusers will work
import importlib.util
spec = importlib.util.find_spec("diffusers")
if spec is not None:
# Try a minimal import test
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")
# Override diffusers availability if we're forcing gradient mode
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"
# Comprehensive color themes for gradient fallbacks
self.color_themes = {
# Blues
'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)],
# Greens
'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/Business
'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 themes
'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 colors
'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)],
# Cool colors
'purple': [(147, 112, 219), (75, 0, 130)],
'violet': [(138, 43, 226), (75, 0, 130)],
'lavender': [(230, 230, 250), (147, 112, 219)],
# Others
'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)],
# Technology/Digital
'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
'default': [(100, 149, 237), (65, 105, 225)]
}
# Only try to initialize diffusers if it's actually available
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)"""
# This will only be called if we've verified diffusers works
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)
# Optimize for memory
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()
# Direct theme matches first
for theme in self.color_themes:
if theme in prompt_lower:
return theme
# Keyword analysis
keyword_map = {
# Water/Ocean
('water', 'sea', 'lake', 'river', 'stream'): 'ocean',
('sky', 'cloud', 'air'): 'sky',
# Nature
('tree', 'plant', 'garden', 'leaf', 'flower'): 'nature',
('grass', 'field', 'meadow'): 'grass',
# Business
('business', 'meeting', 'work', 'conference'): 'business',
('company', 'enterprise', 'corporate'): 'corporate',
# Time/Lighting
('evening', 'midnight', 'shadow', 'darkness'): 'night',
('fire', 'flame', 'autumn', 'fall'): 'fire',
('morning', 'sunrise', 'dawn'): 'warm',
# Technology
('technology', 'computer', 'digital', 'software'): 'tech',
('cyber', 'virtual', 'matrix'): 'cyber',
('neon', 'electric', 'bright'): 'neon',
# Emotions/Moods
('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")
# Get colors for the theme
colors = self.color_themes.get(theme, self.color_themes['default'])
color1, color2 = colors
# Create base gradient
image = Image.new('RGB', (width, height))
draw = ImageDraw.Draw(image)
# Create smooth vertical gradient
for y in range(height):
# Use smooth interpolation
factor = y / height
# Apply easing function for smoother gradients
factor = factor * factor * (3.0 - 2.0 * factor) # Smoothstep
# Interpolate between colors
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 horizontal line
draw.line([(0, y), (width, y)], fill=(r, g, b))
# Add subtle texture and depth
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
# Create texture overlay
texture = Image.new('RGBA', (width, height), (0, 0, 0, 0))
texture_draw = ImageDraw.Draw(texture)
# Add different textures based on theme
if theme in ['tech', 'digital', 'cyber']:
# Add subtle grid pattern
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']:
# Add organic noise
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:
# Add subtle noise for general texture
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))
# Apply texture
image.paste(texture, (0, 0), texture)
# Final smooth blur for professional look
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
# Check if AI generation is possible and working
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}")
# Use gradient generation (main path for compatibility)
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:
# Ensure directory exists
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
# Save image with high quality
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 ""
# Convenience functions
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 multiple themes
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
# Save test image
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
# Example usage and testing
if __name__ == "__main__":
# Run compatibility test
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") |