Munaf1987 commited on
Commit
83090e4
·
verified ·
1 Parent(s): 81cccef

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -209
app.py CHANGED
@@ -14,143 +14,92 @@ import gc
14
  from huggingface_hub import hf_hub_download
15
  import threading
16
 
17
- # Latest and best open-source models
18
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
19
  from diffusers import (
20
- FluxPipeline,
21
  DDIMScheduler,
22
  DPMSolverMultistepScheduler
23
  )
24
  import soundfile as sf
25
  import requests
26
 
27
- # Optional imports for enhanced performance
28
- try:
29
- import flash_attn
30
- FLASH_ATTN_AVAILABLE = True
31
- except ImportError:
32
- FLASH_ATTN_AVAILABLE = False
33
- print("⚠️ Flash Attention not available - using standard attention")
34
-
35
- try:
36
- import triton
37
- TRITON_AVAILABLE = True
38
- except ImportError:
39
- TRITON_AVAILABLE = False
40
- print("⚠️ Triton not available - using standard operations")
41
 
42
  # Global lock to prevent concurrent generations
43
  generation_lock = threading.Lock()
44
 
45
  class ProfessionalCartoonFilmGenerator:
46
  def __init__(self):
47
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
 
 
48
 
49
  # Use /tmp directory for Hugging Face Spaces storage
50
- # Note: HF Spaces only allows storage in /tmp, no subdirectories allowed
51
  self.output_dir = "/tmp"
52
  print(f"📁 Using Hugging Face temp directory: {self.output_dir}")
53
 
54
- # Note: Cannot create subdirectories in /tmp on HF Spaces
55
- # Will use file prefixes instead (char_, bg_, video_, etc.)
56
-
57
  # Model configurations for ZeroGPU optimization
58
  self.models_loaded = False
59
- self.using_flux = False
60
  self.flux_pipe = None
61
- self.script_enhancer = None
62
- self.cartoon_lora = None
63
- self.character_lora = None
64
- self.sketch_lora = None
65
 
66
- @spaces.GPU
67
  def load_models(self):
68
- """Load all required AI models for professional generation"""
69
  try:
70
- print("🚀 Loading professional-grade models...")
71
-
72
- # Clear GPU memory first
73
- self.clear_gpu_memory()
74
 
75
- # Detect device and set appropriate dtype
76
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
77
- self.dtype = torch.float16 if self.device == "cuda" else torch.float32
78
 
79
  print(f"🎮 Using device: {self.device} with dtype: {self.dtype}")
80
 
81
- # Try to load FLUX first
82
- try:
83
- print("🎨 Loading FLUX pipeline...")
84
- from diffusers import FluxPipeline
85
-
86
- self.flux_pipe = FluxPipeline.from_pretrained(
87
- "black-forest-labs/FLUX.1-dev",
88
- torch_dtype=self.dtype,
89
- device_map="auto" if self.device == "cuda" else None
90
- )
91
-
92
- if self.device == "cuda":
93
- self.flux_pipe = self.flux_pipe.to("cuda")
94
-
95
- print("✅ FLUX pipeline loaded successfully")
96
- self.flux_available = True
97
-
98
- except Exception as e:
99
- print("🔐 FLUX authentication failed - model requires Hugging Face token")
100
- print("💡 To use FLUX, you need to:")
101
- print(" 1. Get a Hugging Face token from https://huggingface.co/settings/tokens")
102
- print(" 2. Accept the FLUX model license at https://huggingface.co/black-forest-labs/FLUX.1-dev")
103
- print(" 3. Set your token: huggingface-cli login")
104
- print("🔄 Falling back to Stable Diffusion...")
105
- self.flux_available = False
106
-
107
- # Load Stable Diffusion fallback
108
- if not self.flux_available:
109
- print("🔄 Loading Stable Diffusion fallback model...")
110
- from diffusers import StableDiffusionPipeline, DDIMScheduler
111
-
112
- self.sd_pipe = StableDiffusionPipeline.from_pretrained(
113
- "CompVis/stable-diffusion-v1-4",
114
- torch_dtype=self.dtype,
115
- safety_checker=None,
116
- requires_safety_checker=False
117
- )
118
-
119
- # Configure scheduler for better quality
120
- self.sd_pipe.scheduler = DDIMScheduler.from_config(self.sd_pipe.scheduler.config)
121
-
122
- if self.device == "cuda":
123
- self.sd_pipe = self.sd_pipe.to("cuda")
124
 
125
- print("✅ Loaded Stable Diffusion v1.4")
126
- print("✅ Stable Diffusion fallback loaded successfully")
127
 
128
- # Load script enhancement model with correct device
129
  print("📝 Loading script enhancement model...")
130
  self.script_model = AutoModelForCausalLM.from_pretrained(
131
  "microsoft/DialoGPT-medium",
132
  torch_dtype=self.dtype,
133
- device_map="auto" if self.device == "cuda" else None
134
  )
135
  self.script_tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium")
136
 
137
  if self.script_tokenizer.pad_token is None:
138
  self.script_tokenizer.pad_token = self.script_tokenizer.eos_token
139
 
140
- if self.device == "cuda":
141
- self.script_model = self.script_model.to("cuda")
142
 
143
  print(f"Device set to use {self.device}")
144
- print("✅ Script enhancer loaded")
145
-
146
- # Set model states
147
- if self.device == "cuda":
148
- if self.flux_available:
149
- self.flux_pipe.enable_model_cpu_offload()
150
- else:
151
- self.sd_pipe.enable_model_cpu_offload()
152
 
153
- print("🎬 All professional models loaded!")
154
  return True
155
 
156
  except Exception as e:
@@ -160,10 +109,8 @@ class ProfessionalCartoonFilmGenerator:
160
  return False
161
 
162
  def clear_gpu_memory(self):
163
- """Clear GPU memory between operations"""
164
- if torch.cuda.is_available():
165
- torch.cuda.empty_cache()
166
- gc.collect()
167
 
168
  def optimize_prompt_for_clip(self, prompt: str, max_tokens: int = 70) -> str:
169
  """Optimize prompt to fit within CLIP token limit"""
@@ -201,8 +148,7 @@ class ProfessionalCartoonFilmGenerator:
201
  return download_info
202
 
203
  except Exception as e:
204
- print(f"⚠️ Failed to create download info: {e}")
205
- return f"📁 File generated: {file_path}"
206
 
207
  def generate_professional_script(self, user_input: str) -> Dict[str, Any]:
208
  """Generate a professional cartoon script with detailed character development"""
@@ -447,28 +393,19 @@ class ProfessionalCartoonFilmGenerator:
447
  }
448
  return palettes.get(mood, "balanced warm and cool tones")
449
 
450
- @spaces.GPU
451
  def generate_professional_character_images(self, characters: List[Dict]) -> Dict[str, str]:
452
- """Generate professional character images with consistency"""
453
  character_images = {}
454
 
455
  print(f"🎭 Generating {len(characters)} professional character designs...")
456
 
457
- # Check if we have any image generation pipeline available
458
- if not hasattr(self, 'flux_available'):
459
- print("❌ No image generation models loaded")
460
  return character_images
461
 
462
- pipeline = None
463
- if self.flux_available and hasattr(self, 'flux_pipe'):
464
- pipeline = self.flux_pipe
465
- model_name = "FLUX"
466
- elif hasattr(self, 'sd_pipe'):
467
- pipeline = self.sd_pipe
468
- model_name = "Stable Diffusion"
469
- else:
470
- print("❌ No image generation pipeline available")
471
- return character_images
472
 
473
  print(f"🎨 Using {model_name} for character generation")
474
 
@@ -477,44 +414,28 @@ class ProfessionalCartoonFilmGenerator:
477
  print(f"\n🎨 Generating character: {character_name}")
478
 
479
  try:
480
- # Build comprehensive character prompt
481
  base_prompt = f"Professional cartoon character design, {character['name']}, {character['description']}"
482
 
483
- # Add style and quality modifiers
484
- if self.flux_available:
485
- # FLUX-specific prompt
486
- prompt = f"{base_prompt}, Disney-Pixar animation style, highly detailed character sheet, clean white background, 2D animation model sheet, expressive face, vibrant colors, professional character design, perfect for animation"
487
- else:
488
- # Stable Diffusion prompt
489
- prompt = f"{base_prompt}, anime style, cartoon character, clean background, high quality, detailed, 2D animation style, character sheet"
490
 
491
  # Optimize prompt for CLIP
492
- prompt = self.optimize_prompt_for_clip(prompt, max_tokens=75)
493
  print(f"📝 Character prompt: {prompt}")
494
 
495
- # Generate with appropriate settings
496
- if self.flux_available:
497
- # FLUX generation settings
498
- image = pipeline(
499
- prompt=prompt,
500
- width=1024,
501
- height=1024,
502
- num_inference_steps=25,
503
- guidance_scale=7.5,
504
- generator=torch.Generator(device=self.device).manual_seed(42)
505
- ).images[0]
506
- else:
507
- # Stable Diffusion generation settings
508
- image = pipeline(
509
- prompt=prompt,
510
- width=512,
511
- height=512,
512
- num_inference_steps=30,
513
- guidance_scale=7.5,
514
- generator=torch.Generator(device=self.device).manual_seed(42)
515
- ).images[0]
516
- # Upscale for SD
517
- image = image.resize((1024, 1024), Image.Resampling.LANCZOS)
518
 
519
  # Save character image
520
  char_path = f"{self.output_dir}/char_{character['name'].replace(' ', '_')}.png"
@@ -532,10 +453,8 @@ class ProfessionalCartoonFilmGenerator:
532
  print(f" 📁 Internal path: {char_path}")
533
  print(download_info)
534
 
535
- # Clear GPU memory after each generation
536
- if self.device == "cuda":
537
- torch.cuda.empty_cache()
538
- gc.collect()
539
  else:
540
  print(f"❌ Failed to save character image: {char_path}")
541
 
@@ -553,28 +472,19 @@ class ProfessionalCartoonFilmGenerator:
553
 
554
  return character_images
555
 
556
- @spaces.GPU
557
  def generate_cinematic_backgrounds(self, scenes: List[Dict], color_palette: str) -> Dict[int, str]:
558
- """Generate professional cinematic backgrounds for each scene"""
559
  background_images = {}
560
 
561
  print(f"🎞️ Generating {len(scenes)} cinematic backgrounds...")
562
 
563
- # Check if we have any image generation pipeline available
564
- if not hasattr(self, 'flux_available'):
565
- print("❌ No image generation models loaded")
566
  return background_images
567
 
568
- pipeline = None
569
- if self.flux_available and hasattr(self, 'flux_pipe'):
570
- pipeline = self.flux_pipe
571
- model_name = "FLUX"
572
- elif hasattr(self, 'sd_pipe'):
573
- pipeline = self.sd_pipe
574
- model_name = "Stable Diffusion"
575
- else:
576
- print("❌ No image generation pipeline available")
577
- return background_images
578
 
579
  print(f"🎨 Using {model_name} for background generation")
580
 
@@ -583,7 +493,7 @@ class ProfessionalCartoonFilmGenerator:
583
  print(f"\n🌄 Generating background for scene {scene_num}")
584
 
585
  try:
586
- # Build cinematic background prompt
587
  background_desc = scene['background']
588
  mood = scene.get('mood', 'neutral')
589
  shot_type = scene.get('shot_type', 'medium shot')
@@ -591,39 +501,25 @@ class ProfessionalCartoonFilmGenerator:
591
 
592
  base_prompt = f"Cinematic background scene, {background_desc}, {mood} atmosphere, {lighting}"
593
 
594
- # Add style and quality modifiers
595
- if self.flux_available:
596
- prompt = f"{base_prompt}, Disney-Pixar animation style, detailed landscape, professional background art, vibrant colors, high quality, cinematic composition, no characters"
597
- else:
598
- prompt = f"{base_prompt}, anime style background, detailed landscape, high quality, cinematic, {color_palette} color palette, no people"
599
 
600
  # Optimize for CLIP
601
- prompt = self.optimize_prompt_for_clip(prompt, max_tokens=75)
602
  print(f"📝 Background prompt: {prompt}")
603
 
604
- # Generate with appropriate settings
605
- if self.flux_available:
606
- # FLUX generation settings
607
- image = pipeline(
608
- prompt=prompt,
609
- width=1024,
610
- height=768, # 4:3 aspect ratio for video
611
- num_inference_steps=25,
612
- guidance_scale=7.5,
613
- generator=torch.Generator(device=self.device).manual_seed(scene_num * 10)
614
- ).images[0]
615
- else:
616
- # Stable Diffusion generation settings
617
- image = pipeline(
618
- prompt=prompt,
619
- width=512,
620
- height=384, # 4:3 aspect ratio
621
- num_inference_steps=30,
622
- guidance_scale=7.5,
623
- generator=torch.Generator(device=self.device).manual_seed(scene_num * 10)
624
- ).images[0]
625
- # Upscale for SD
626
- image = image.resize((1024, 768), Image.Resampling.LANCZOS)
627
 
628
  # Save background image
629
  bg_path = f"{self.output_dir}/bg_scene_{scene_num}.png"
@@ -641,10 +537,8 @@ class ProfessionalCartoonFilmGenerator:
641
  print(f" 📁 Internal path: {bg_path}")
642
  print(download_info)
643
 
644
- # Clear GPU memory after each generation
645
- if self.device == "cuda":
646
- torch.cuda.empty_cache()
647
- gc.collect()
648
  else:
649
  print(f"❌ Failed to save background image: {bg_path}")
650
 
@@ -667,6 +561,9 @@ class ProfessionalCartoonFilmGenerator:
667
  try:
668
  print("🎬 Setting up Open-Sora 2.0 for video generation...")
669
 
 
 
 
670
  # Check available GPU memory
671
  if torch.cuda.is_available():
672
  gpu_memory = torch.cuda.get_device_properties(0).total_memory / (1024**3)
@@ -774,7 +671,6 @@ class ProfessionalCartoonFilmGenerator:
774
  traceback.print_exc()
775
  return False
776
 
777
- @spaces.GPU
778
  def generate_professional_videos(self, scenes: List[Dict], character_images: Dict, background_images: Dict) -> List[str]:
779
  """Generate professional videos using Open-Sora 2.0"""
780
  scene_videos = []
@@ -1129,11 +1025,10 @@ class ProfessionalCartoonFilmGenerator:
1129
  return None
1130
 
1131
  def _create_emergency_fallback_video(self, script_data: Dict) -> str:
1132
- """Create a simple emergency fallback video when everything else fails"""
1133
  try:
1134
  print("🆘 Creating emergency fallback video...")
1135
 
1136
- # Create a simple colored background
1137
  width, height = 1024, 768
1138
  background_color = (100, 150, 200) # Blue-ish color
1139
 
@@ -1152,12 +1047,16 @@ class ProfessionalCartoonFilmGenerator:
1152
 
1153
  # Create simple animated background
1154
  for i in range(total_frames):
 
1155
  frame = np.full((height, width, 3), background_color, dtype=np.uint8)
1156
 
1157
- # Add simple animation (color shift)
1158
  progress = i / total_frames
1159
  color_shift = int(50 * np.sin(progress * 2 * np.pi))
1160
- frame[:, :, 0] = np.clip(frame[:, :, 0] + color_shift, 0, 255)
 
 
 
1161
 
1162
  # Add text
1163
  font = cv2.FONT_HERSHEY_SIMPLEX
@@ -1181,6 +1080,8 @@ class ProfessionalCartoonFilmGenerator:
1181
 
1182
  except Exception as e:
1183
  print(f"❌ Emergency fallback video creation failed: {e}")
 
 
1184
  return None
1185
 
1186
  def merge_professional_film(self, scene_videos: List[str], script_data: Dict) -> str:
@@ -1224,12 +1125,25 @@ class ProfessionalCartoonFilmGenerator:
1224
  print(f"❌ Video merging failed: {e}")
1225
  return None
1226
 
1227
- @spaces.GPU
1228
  def generate_professional_cartoon_film(self, script: str) -> tuple:
1229
- """Main function to generate professional-quality cartoon film"""
1230
  try:
1231
  print("🎬 Starting professional cartoon film generation...")
1232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1233
  # Step 1: Generate professional script
1234
  print("📝 Creating professional script structure...")
1235
  script_data = self.generate_professional_script(script)
@@ -1486,9 +1400,8 @@ class ProfessionalCartoonFilmGenerator:
1486
  # Initialize professional generator
1487
  generator = ProfessionalCartoonFilmGenerator()
1488
 
1489
- @spaces.GPU
1490
  def create_professional_cartoon_film(script):
1491
- """Gradio interface function for professional generation"""
1492
  if not script.strip():
1493
  empty_response = {
1494
  "error": True,
@@ -1508,7 +1421,7 @@ def create_professional_cartoon_film(script):
1508
  "scenes": [],
1509
  "style": "Please wait for current generation to complete"
1510
  }
1511
- return None, busy_response, "⏳ Another generation is in progress. Please wait and try again.", [], []
1512
 
1513
  try:
1514
  return generator.generate_professional_cartoon_film(script)
 
14
  from huggingface_hub import hf_hub_download
15
  import threading
16
 
17
+ # ZeroGPU-compatible imports
18
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
19
  from diffusers import (
20
+ StableDiffusionPipeline,
21
  DDIMScheduler,
22
  DPMSolverMultistepScheduler
23
  )
24
  import soundfile as sf
25
  import requests
26
 
27
+ # ZeroGPU compatibility - disable GPU-specific optimizations
28
+ FLASH_ATTN_AVAILABLE = False
29
+ TRITON_AVAILABLE = False
30
+ print("⚠️ ZeroGPU mode - using CPU-optimized operations")
 
 
 
 
 
 
 
 
 
 
31
 
32
  # Global lock to prevent concurrent generations
33
  generation_lock = threading.Lock()
34
 
35
  class ProfessionalCartoonFilmGenerator:
36
  def __init__(self):
37
+ # ZeroGPU compatibility - force CPU usage
38
+ self.device = "cpu"
39
+ self.dtype = torch.float32 # Use float32 for CPU compatibility
40
 
41
  # Use /tmp directory for Hugging Face Spaces storage
 
42
  self.output_dir = "/tmp"
43
  print(f"📁 Using Hugging Face temp directory: {self.output_dir}")
44
 
 
 
 
45
  # Model configurations for ZeroGPU optimization
46
  self.models_loaded = False
47
+ self.flux_available = False
48
  self.flux_pipe = None
49
+ self.sd_pipe = None
50
+ self.script_model = None
51
+ self.script_tokenizer = None
 
52
 
 
53
  def load_models(self):
54
+ """Load ZeroGPU-compatible models for professional generation"""
55
  try:
56
+ print("🚀 Loading ZeroGPU-compatible models...")
 
 
 
57
 
58
+ # Clear memory
59
+ gc.collect()
 
60
 
61
  print(f"🎮 Using device: {self.device} with dtype: {self.dtype}")
62
 
63
+ # Load Stable Diffusion (CPU optimized)
64
+ print("🔄 Loading Stable Diffusion (CPU optimized)...")
65
+ from diffusers import StableDiffusionPipeline, DDIMScheduler
66
+
67
+ self.sd_pipe = StableDiffusionPipeline.from_pretrained(
68
+ "CompVis/stable-diffusion-v1-4",
69
+ torch_dtype=self.dtype,
70
+ safety_checker=None,
71
+ requires_safety_checker=False,
72
+ device_map=None # Force CPU usage
73
+ )
74
+
75
+ # Configure scheduler for better quality
76
+ self.sd_pipe.scheduler = DDIMScheduler.from_config(self.sd_pipe.scheduler.config)
77
+
78
+ # Force CPU usage for ZeroGPU
79
+ self.sd_pipe = self.sd_pipe.to("cpu")
80
+ self.sd_pipe.enable_sequential_cpu_offload() # Memory optimization
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
+ print("✅ Loaded Stable Diffusion v1.4 (CPU optimized)")
 
83
 
84
+ # Load script enhancement model (CPU optimized)
85
  print("📝 Loading script enhancement model...")
86
  self.script_model = AutoModelForCausalLM.from_pretrained(
87
  "microsoft/DialoGPT-medium",
88
  torch_dtype=self.dtype,
89
+ device_map=None # Force CPU usage
90
  )
91
  self.script_tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium")
92
 
93
  if self.script_tokenizer.pad_token is None:
94
  self.script_tokenizer.pad_token = self.script_tokenizer.eos_token
95
 
96
+ # Force CPU usage
97
+ self.script_model = self.script_model.to("cpu")
98
 
99
  print(f"Device set to use {self.device}")
100
+ print("✅ Script enhancer loaded (CPU optimized)")
 
 
 
 
 
 
 
101
 
102
+ print("🎬 All ZeroGPU-compatible models loaded!")
103
  return True
104
 
105
  except Exception as e:
 
109
  return False
110
 
111
  def clear_gpu_memory(self):
112
+ """Clear memory (CPU-focused for ZeroGPU)"""
113
+ gc.collect()
 
 
114
 
115
  def optimize_prompt_for_clip(self, prompt: str, max_tokens: int = 70) -> str:
116
  """Optimize prompt to fit within CLIP token limit"""
 
148
  return download_info
149
 
150
  except Exception as e:
151
+ return f"📥 Generated {file_type} (download info unavailable: {e})"
 
152
 
153
  def generate_professional_script(self, user_input: str) -> Dict[str, Any]:
154
  """Generate a professional cartoon script with detailed character development"""
 
393
  }
394
  return palettes.get(mood, "balanced warm and cool tones")
395
 
 
396
  def generate_professional_character_images(self, characters: List[Dict]) -> Dict[str, str]:
397
+ """Generate professional character images with consistency (ZeroGPU compatible)"""
398
  character_images = {}
399
 
400
  print(f"🎭 Generating {len(characters)} professional character designs...")
401
 
402
+ # Check if we have Stable Diffusion pipeline available
403
+ if not hasattr(self, 'sd_pipe') or self.sd_pipe is None:
404
+ print("❌ Stable Diffusion not loaded - please call load_models() first")
405
  return character_images
406
 
407
+ pipeline = self.sd_pipe
408
+ model_name = "Stable Diffusion (CPU)"
 
 
 
 
 
 
 
 
409
 
410
  print(f"🎨 Using {model_name} for character generation")
411
 
 
414
  print(f"\n🎨 Generating character: {character_name}")
415
 
416
  try:
417
+ # Build comprehensive character prompt for CPU generation
418
  base_prompt = f"Professional cartoon character design, {character['name']}, {character['description']}"
419
 
420
+ # CPU-optimized prompt
421
+ prompt = f"{base_prompt}, anime style, cartoon character, clean background, high quality, detailed, 2D animation style, character sheet, simple design"
 
 
 
 
 
422
 
423
  # Optimize prompt for CLIP
424
+ prompt = self.optimize_prompt_for_clip(prompt, max_tokens=60) # Shorter for CPU
425
  print(f"📝 Character prompt: {prompt}")
426
 
427
+ # CPU-optimized generation settings
428
+ image = pipeline(
429
+ prompt=prompt,
430
+ width=512, # Smaller for CPU
431
+ height=512,
432
+ num_inference_steps=20, # Fewer steps for CPU
433
+ guidance_scale=7.5,
434
+ generator=torch.Generator(device="cpu").manual_seed(42)
435
+ ).images[0]
436
+
437
+ # Upscale for better quality
438
+ image = image.resize((1024, 1024), Image.Resampling.LANCZOS)
 
 
 
 
 
 
 
 
 
 
 
439
 
440
  # Save character image
441
  char_path = f"{self.output_dir}/char_{character['name'].replace(' ', '_')}.png"
 
453
  print(f" 📁 Internal path: {char_path}")
454
  print(download_info)
455
 
456
+ # Clear memory after each generation
457
+ gc.collect()
 
 
458
  else:
459
  print(f"❌ Failed to save character image: {char_path}")
460
 
 
472
 
473
  return character_images
474
 
 
475
  def generate_cinematic_backgrounds(self, scenes: List[Dict], color_palette: str) -> Dict[int, str]:
476
+ """Generate professional cinematic backgrounds for each scene (ZeroGPU compatible)"""
477
  background_images = {}
478
 
479
  print(f"🎞️ Generating {len(scenes)} cinematic backgrounds...")
480
 
481
+ # Check if we have Stable Diffusion pipeline available
482
+ if not hasattr(self, 'sd_pipe') or self.sd_pipe is None:
483
+ print("❌ Stable Diffusion not loaded - please call load_models() first")
484
  return background_images
485
 
486
+ pipeline = self.sd_pipe
487
+ model_name = "Stable Diffusion (CPU)"
 
 
 
 
 
 
 
 
488
 
489
  print(f"🎨 Using {model_name} for background generation")
490
 
 
493
  print(f"\n🌄 Generating background for scene {scene_num}")
494
 
495
  try:
496
+ # Build cinematic background prompt for CPU generation
497
  background_desc = scene['background']
498
  mood = scene.get('mood', 'neutral')
499
  shot_type = scene.get('shot_type', 'medium shot')
 
501
 
502
  base_prompt = f"Cinematic background scene, {background_desc}, {mood} atmosphere, {lighting}"
503
 
504
+ # CPU-optimized prompt
505
+ prompt = f"{base_prompt}, anime style background, detailed landscape, high quality, cinematic, {color_palette} color palette, no people, simple design"
 
 
 
506
 
507
  # Optimize for CLIP
508
+ prompt = self.optimize_prompt_for_clip(prompt, max_tokens=60) # Shorter for CPU
509
  print(f"📝 Background prompt: {prompt}")
510
 
511
+ # CPU-optimized generation settings
512
+ image = pipeline(
513
+ prompt=prompt,
514
+ width=512, # Smaller for CPU
515
+ height=384, # 4:3 aspect ratio
516
+ num_inference_steps=20, # Fewer steps for CPU
517
+ guidance_scale=7.5,
518
+ generator=torch.Generator(device="cpu").manual_seed(scene_num * 10)
519
+ ).images[0]
520
+
521
+ # Upscale for better quality
522
+ image = image.resize((1024, 768), Image.Resampling.LANCZOS)
 
 
 
 
 
 
 
 
 
 
 
523
 
524
  # Save background image
525
  bg_path = f"{self.output_dir}/bg_scene_{scene_num}.png"
 
537
  print(f" 📁 Internal path: {bg_path}")
538
  print(download_info)
539
 
540
+ # Clear memory after each generation
541
+ gc.collect()
 
 
542
  else:
543
  print(f"❌ Failed to save background image: {bg_path}")
544
 
 
561
  try:
562
  print("🎬 Setting up Open-Sora 2.0 for video generation...")
563
 
564
+ # Import torch here to avoid the UnboundLocalError
565
+ import torch
566
+
567
  # Check available GPU memory
568
  if torch.cuda.is_available():
569
  gpu_memory = torch.cuda.get_device_properties(0).total_memory / (1024**3)
 
671
  traceback.print_exc()
672
  return False
673
 
 
674
  def generate_professional_videos(self, scenes: List[Dict], character_images: Dict, background_images: Dict) -> List[str]:
675
  """Generate professional videos using Open-Sora 2.0"""
676
  scene_videos = []
 
1025
  return None
1026
 
1027
  def _create_emergency_fallback_video(self, script_data: Dict) -> str:
1028
+ """Create emergency fallback video when all else fails"""
1029
  try:
1030
  print("🆘 Creating emergency fallback video...")
1031
 
 
1032
  width, height = 1024, 768
1033
  background_color = (100, 150, 200) # Blue-ish color
1034
 
 
1047
 
1048
  # Create simple animated background
1049
  for i in range(total_frames):
1050
+ # Create frame with proper uint8 type
1051
  frame = np.full((height, width, 3), background_color, dtype=np.uint8)
1052
 
1053
+ # Add simple animation (color shift) with proper clamping
1054
  progress = i / total_frames
1055
  color_shift = int(50 * np.sin(progress * 2 * np.pi))
1056
+
1057
+ # Ensure all values stay within uint8 bounds (0-255)
1058
+ new_blue = np.clip(frame[:, :, 0].astype(np.int16) + color_shift, 0, 255).astype(np.uint8)
1059
+ frame[:, :, 0] = new_blue
1060
 
1061
  # Add text
1062
  font = cv2.FONT_HERSHEY_SIMPLEX
 
1080
 
1081
  except Exception as e:
1082
  print(f"❌ Emergency fallback video creation failed: {e}")
1083
+ import traceback
1084
+ traceback.print_exc()
1085
  return None
1086
 
1087
  def merge_professional_film(self, scene_videos: List[str], script_data: Dict) -> str:
 
1125
  print(f"❌ Video merging failed: {e}")
1126
  return None
1127
 
 
1128
  def generate_professional_cartoon_film(self, script: str) -> tuple:
1129
+ """Main function to generate professional-quality cartoon film (ZeroGPU compatible)"""
1130
  try:
1131
  print("🎬 Starting professional cartoon film generation...")
1132
 
1133
+ # Step 0: Load models first (critical!)
1134
+ print("🚀 Loading AI models...")
1135
+ models_loaded = self.load_models()
1136
+ if not models_loaded:
1137
+ print("❌ Failed to load models - cannot generate content")
1138
+ error_info = {
1139
+ "error": True,
1140
+ "message": "Failed to load AI models",
1141
+ "characters": [],
1142
+ "scenes": [],
1143
+ "style": "Model loading failed"
1144
+ }
1145
+ return None, error_info, "❌ Failed to load AI models", [], []
1146
+
1147
  # Step 1: Generate professional script
1148
  print("📝 Creating professional script structure...")
1149
  script_data = self.generate_professional_script(script)
 
1400
  # Initialize professional generator
1401
  generator = ProfessionalCartoonFilmGenerator()
1402
 
 
1403
  def create_professional_cartoon_film(script):
1404
+ """Gradio interface function for professional generation (ZeroGPU compatible)"""
1405
  if not script.strip():
1406
  empty_response = {
1407
  "error": True,
 
1421
  "scenes": [],
1422
  "style": "Please wait for current generation to complete"
1423
  }
1424
+ return None, busy_response, "⏳ Generation already in progress - please wait", [], []
1425
 
1426
  try:
1427
  return generator.generate_professional_cartoon_film(script)