Munaf1987 commited on
Commit
89c191e
Β·
verified Β·
1 Parent(s): 8848233

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +570 -42
app.py CHANGED
@@ -1,52 +1,580 @@
1
  import gradio as gr
2
- from scene_planner import plan_scenes
3
- from generate_image import generate_scene_image
4
- from tts import generate_audio
5
- from animate import animate_scene
6
- from compose import compose_video
7
  import os
8
- import shutil
 
 
 
9
  import spaces
10
- from moviepy.editor import ImageClip, AudioFileClip
11
 
12
- def test():
13
- return "moviepy successfully imported"
 
 
 
 
 
 
 
 
 
 
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
-
17
- LANGUAGES = ["Gujarati", "Hindi", "English"]
18
 
19
  @spaces.GPU
20
- def full_pipeline(script, language):
21
- scenes = plan_scenes(script)
22
-
23
- if os.path.exists("assets"):
24
- shutil.rmtree("assets")
25
- os.makedirs("assets/images")
26
- os.makedirs("assets/audio")
27
- os.makedirs("assets/video")
28
-
29
- video_segments = []
30
- for idx, scene in enumerate(scenes):
31
- prompt = scene['prompt']
32
- line = scene['dialogue']
33
-
34
- image_path = generate_scene_image(prompt, idx)
35
- audio_path = generate_audio(line, idx, language)
36
- video_path = animate_scene(image_path, audio_path, idx)
37
- video_segments.append(video_path)
38
-
39
- final_path = compose_video(video_segments)
40
- return final_path
41
 
42
- #with gr.Blocks() as demo:
43
- #gr.Markdown("# Script to Cartoon Video Generator (Gujarati | Hindi | English)")
44
- #with gr.Row():
45
- #script_input = gr.Textbox(label="Enter Story or Script", lines=10)
46
- # lang_input = gr.Dropdown(choices=LANGUAGES, label="Select Narration Language")
47
- #gen_btn = gr.Button("Generate Cartoon Video")
48
- #output_video = gr.Video(label="Final Video")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- #gen_btn.click(full_pipeline, inputs=[script_input, lang_input], outputs=output_video)
51
- demo = gr.Interface(fn=test, inputs=[], outputs="text")
52
- demo.launch()
 
1
  import gradio as gr
2
+ import torch
3
+ import numpy as np
4
+ import cv2
5
+ from PIL import Image
6
+ import json
7
  import os
8
+ from typing import List, Dict, Any
9
+ import tempfile
10
+ import subprocess
11
+ from pathlib import Path
12
  import spaces
13
+ import gc
14
 
15
+ # All open-source HuggingFace models
16
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
17
+ from diffusers import (
18
+ StableDiffusionPipeline,
19
+ StableVideoDiffusionPipeline,
20
+ AnimateDiffPipeline,
21
+ MotionAdapter,
22
+ DDIMScheduler
23
+ )
24
+ from diffusers.utils import export_to_video
25
+ import soundfile as sf
26
+ from TTS.api import TTS
27
 
28
+ class CartoonFilmGenerator:
29
+ def __init__(self):
30
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
31
+ self.temp_dir = tempfile.mkdtemp()
32
+
33
+ # Model configurations for ZeroGPU optimization
34
+ self.models_loaded = False
35
+
36
+ @spaces.GPU
37
+ def load_models(self):
38
+ """Load models on-demand for ZeroGPU efficiency"""
39
+ if self.models_loaded:
40
+ return
41
+
42
+ print("Loading open-source models...")
43
+
44
+ # 1. Text generation for script enhancement (Open source)
45
+ self.text_generator = pipeline(
46
+ "text-generation",
47
+ model="microsoft/DialoGPT-large",
48
+ tokenizer="microsoft/DialoGPT-large",
49
+ device=0 if self.device == "cuda" else -1,
50
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
51
+ )
52
+
53
+ # 2. Image generation - SDXL (fully open source)
54
+ self.image_generator = StableDiffusionPipeline.from_pretrained(
55
+ "stabilityai/stable-diffusion-xl-base-1.0",
56
+ torch_dtype=torch.float16,
57
+ use_safetensors=True,
58
+ variant="fp16"
59
+ ).to(self.device)
60
+
61
+ # Enable memory efficient attention
62
+ self.image_generator.enable_memory_efficient_attention()
63
+ self.image_generator.enable_vae_slicing()
64
+
65
+ # 3. Video generation - AnimateDiff (open source)
66
+ adapter = MotionAdapter.from_pretrained("guoyww/animatediff-motion-adapter-v1-5-2")
67
+ self.video_generator = AnimateDiffPipeline.from_pretrained(
68
+ "runwayml/stable-diffusion-v1-5",
69
+ motion_adapter=adapter,
70
+ torch_dtype=torch.float16
71
+ ).to(self.device)
72
+
73
+ self.video_generator.scheduler = DDIMScheduler.from_pretrained(
74
+ "runwayml/stable-diffusion-v1-5",
75
+ subfolder="scheduler",
76
+ clip_sample=False,
77
+ timestep_spacing="linspace",
78
+ beta_schedule="linear",
79
+ steps_offset=1,
80
+ )
81
+ self.video_generator.enable_vae_slicing()
82
+ self.video_generator.enable_memory_efficient_attention()
83
+
84
+ # 4. Text-to-Speech (Open source XTTS)
85
+ self.tts_model = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to(self.device)
86
+
87
+ self.models_loaded = True
88
+ print("All open-source models loaded successfully!")
89
+
90
+ def clear_gpu_memory(self):
91
+ """Clear GPU memory between operations"""
92
+ if torch.cuda.is_available():
93
+ torch.cuda.empty_cache()
94
+ gc.collect()
95
+
96
+ def enhance_script_with_llm(self, raw_script: str) -> Dict[str, Any]:
97
+ """Use open-source LLM to enhance the script"""
98
+
99
+ # Structured prompt for script enhancement
100
+ enhancement_prompt = f"""
101
+ Original script: {raw_script}
102
+
103
+ Transform this into a detailed 8-minute cartoon film with:
104
+ - 12 scenes (40 seconds each)
105
+ - Consistent characters
106
+ - Clear scene descriptions
107
+ - Simple dialogue
108
+ - Visual descriptions for animation
109
+
110
+ Create a story structure with beginning, middle, and end.
111
+ """
112
+
113
+ try:
114
+ # Use the text generation pipeline
115
+ response = self.text_generator(
116
+ enhancement_prompt,
117
+ max_length=1000,
118
+ num_return_sequences=1,
119
+ temperature=0.7,
120
+ do_sample=True,
121
+ pad_token_id=self.text_generator.tokenizer.eos_token_id
122
+ )
123
+
124
+ enhanced_script = response[0]['generated_text']
125
+
126
+ except Exception as e:
127
+ print(f"LLM enhancement failed: {e}")
128
+ enhanced_script = raw_script
129
+
130
+ # Create structured output (fallback method)
131
+ return self.create_structured_script(raw_script, enhanced_script)
132
+
133
+ def create_structured_script(self, original: str, enhanced: str) -> Dict[str, Any]:
134
+ """Create structured script data"""
135
+
136
+ # Extract key elements from the script
137
+ words = original.lower().split()
138
+
139
+ # Determine main character and setting
140
+ if any(word in words for word in ['boy', 'man', 'hero', 'prince']):
141
+ main_char = "brave young hero"
142
+ elif any(word in words for word in ['girl', 'woman', 'princess', 'heroine']):
143
+ main_char = "brave young heroine"
144
+ else:
145
+ main_char = "friendly protagonist"
146
+
147
+ # Determine setting
148
+ if any(word in words for word in ['forest', 'woods', 'trees']):
149
+ setting = "magical forest"
150
+ elif any(word in words for word in ['city', 'town', 'urban']):
151
+ setting = "bustling city"
152
+ elif any(word in words for word in ['space', 'stars', 'planet']):
153
+ setting = "cosmic space"
154
+ else:
155
+ setting = "colorful fantasy world"
156
+
157
+ # Create 12 scenes for 8-minute film
158
+ scenes = []
159
+ scene_templates = [
160
+ "Introduction of the main character",
161
+ "Character discovers the challenge",
162
+ "Meeting helpful friends",
163
+ "First obstacle appears",
164
+ "Character shows determination",
165
+ "Meeting the antagonist",
166
+ "Major challenge or conflict",
167
+ "Character feels doubt",
168
+ "Friends provide support",
169
+ "Final confrontation",
170
+ "Resolution and victory",
171
+ "Happy ending celebration"
172
+ ]
173
+
174
+ for i, template in enumerate(scene_templates):
175
+ scenes.append({
176
+ "scene_number": i + 1,
177
+ "description": f"{template} in the {setting}",
178
+ "characters_present": [main_char] if i % 3 != 0 else [main_char, "supporting character"],
179
+ "dialogue": [
180
+ {"character": main_char, "text": f"Scene {i+1} dialogue based on: {template}"}
181
+ ],
182
+ "background": f"{setting} with {['sunrise', 'daylight', 'sunset', 'moonlight'][i % 4]} lighting",
183
+ "mood": ["hopeful", "determined", "friendly", "tense", "brave", "worried", "dramatic", "uncertain", "supportive", "exciting", "triumphant", "joyful"][i],
184
+ "duration": "40"
185
+ })
186
+
187
+ return {
188
+ "characters": [
189
+ {
190
+ "name": main_char,
191
+ "description": f"Cartoon-style {main_char} with expressive eyes, friendly smile, colorful outfit, animated style",
192
+ "personality": "brave, kind, determined"
193
+ },
194
+ {
195
+ "name": "supporting character",
196
+ "description": "Helpful cartoon companion with warm colors, friendly appearance, supporting role",
197
+ "personality": "loyal, wise, encouraging"
198
+ }
199
+ ],
200
+ "scenes": scenes,
201
+ "style": "Modern 2D cartoon animation, bright colors, expressive characters, family-friendly"
202
+ }
203
+
204
+ @spaces.GPU
205
+ def generate_character_images(self, characters: List[Dict]) -> Dict[str, str]:
206
+ """Generate character images using SDXL"""
207
+ self.load_models()
208
+ character_images = {}
209
+
210
+ for character in characters:
211
+ prompt = f"cartoon character sheet, {character['description']}, multiple poses, clean white background, 2D animation style, colorful, expressive, high quality"
212
+ negative_prompt = "realistic, 3D, dark, scary, inappropriate, low quality, blurry"
213
+
214
+ try:
215
+ image = self.image_generator(
216
+ prompt=prompt,
217
+ negative_prompt=negative_prompt,
218
+ num_inference_steps=25,
219
+ guidance_scale=7.5,
220
+ height=1024,
221
+ width=1024
222
+ ).images[0]
223
+
224
+ char_path = f"{self.temp_dir}/character_{character['name'].replace(' ', '_')}.png"
225
+ image.save(char_path)
226
+ character_images[character['name']] = char_path
227
+
228
+ # Clear memory after each character
229
+ self.clear_gpu_memory()
230
+
231
+ except Exception as e:
232
+ print(f"Error generating character {character['name']}: {e}")
233
+
234
+ return character_images
235
+
236
+ @spaces.GPU
237
+ def generate_background_images(self, scenes: List[Dict]) -> Dict[int, str]:
238
+ """Generate background images for each scene"""
239
+ self.load_models()
240
+ background_images = {}
241
+
242
+ for scene in scenes:
243
+ prompt = f"cartoon background, {scene['background']}, {scene['mood']} atmosphere, animated style, no characters, detailed environment, bright colors, 2D animation"
244
+ negative_prompt = "characters, people, realistic, dark, scary, low quality"
245
+
246
+ try:
247
+ image = self.image_generator(
248
+ prompt=prompt,
249
+ negative_prompt=negative_prompt,
250
+ num_inference_steps=20,
251
+ guidance_scale=7.0,
252
+ height=576,
253
+ width=1024 # 16:9 aspect ratio
254
+ ).images[0]
255
+
256
+ bg_path = f"{self.temp_dir}/background_scene_{scene['scene_number']}.png"
257
+ image.save(bg_path)
258
+ background_images[scene['scene_number']] = bg_path
259
+
260
+ # Clear memory after each background
261
+ self.clear_gpu_memory()
262
+
263
+ except Exception as e:
264
+ print(f"Error generating background for scene {scene['scene_number']}: {e}")
265
+
266
+ return background_images
267
+
268
+ @spaces.GPU
269
+ def generate_scene_videos(self, scenes: List[Dict], character_images: Dict, background_images: Dict) -> List[str]:
270
+ """Generate animated videos for each scene using AnimateDiff"""
271
+ self.load_models()
272
+ scene_videos = []
273
+
274
+ for scene in scenes:
275
+ try:
276
+ # Create prompt for scene animation
277
+ characters_text = ", ".join(scene['characters_present'])
278
+ prompt = f"cartoon animation, {characters_text} in {scene['background']}, {scene['mood']} mood, 2D animated style, smooth motion, family friendly"
279
+ negative_prompt = "realistic, 3D, static, blurry, low quality, scary"
280
+
281
+ # Generate animated video using AnimateDiff
282
+ video_frames = self.video_generator(
283
+ prompt=prompt,
284
+ negative_prompt=negative_prompt,
285
+ num_frames=16, # 16 frames for smooth motion
286
+ guidance_scale=7.5,
287
+ num_inference_steps=20,
288
+ height=576,
289
+ width=1024
290
+ ).frames[0]
291
+
292
+ # Save video
293
+ video_path = f"{self.temp_dir}/scene_{scene['scene_number']}.mp4"
294
+ export_to_video(video_frames, video_path, fps=8)
295
+ scene_videos.append(video_path)
296
+
297
+ # Clear GPU memory
298
+ self.clear_gpu_memory()
299
+
300
+ except Exception as e:
301
+ print(f"Error generating video for scene {scene['scene_number']}: {e}")
302
+ # Fallback: create static video
303
+ if scene['scene_number'] in background_images:
304
+ video_path = self.create_static_video(
305
+ Image.open(background_images[scene['scene_number']]),
306
+ int(scene.get('duration', 40)),
307
+ scene['scene_number']
308
+ )
309
+ scene_videos.append(video_path)
310
+
311
+ return scene_videos
312
+
313
+ def create_static_video(self, image: Image.Image, duration: int, scene_num: int) -> str:
314
+ """Fallback: Create video from static image"""
315
+ video_path = f"{self.temp_dir}/scene_{scene_num}.mp4"
316
+
317
+ # Convert PIL to OpenCV
318
+ img_array = np.array(image.resize((1024, 576)))
319
+ img_array = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
320
+
321
+ # Create video writer
322
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
323
+ fps = 24
324
+ out = cv2.VideoWriter(video_path, fourcc, fps, (1024, 576))
325
+
326
+ # Add simple zoom effect
327
+ for i in range(duration * fps):
328
+ scale = 1.0 + (i / (duration * fps)) * 0.1 # Slight zoom
329
+ h, w = img_array.shape[:2]
330
+ center_x, center_y = w // 2, h // 2
331
+
332
+ # Create zoom matrix
333
+ M = cv2.getRotationMatrix2D((center_x, center_y), 0, scale)
334
+ zoomed = cv2.warpAffine(img_array, M, (w, h))
335
+
336
+ out.write(zoomed)
337
+
338
+ out.release()
339
+ return video_path
340
+
341
+ @spaces.GPU
342
+ def generate_audio(self, scenes: List[Dict]) -> str:
343
+ """Generate audio using open-source XTTS"""
344
+ self.load_models()
345
+
346
+ try:
347
+ audio_segments = []
348
+ sample_rate = 22050
349
+
350
+ for scene in scenes:
351
+ scene_audio = []
352
+
353
+ # Generate speech for dialogue
354
+ for dialogue in scene.get('dialogue', []):
355
+ text = dialogue['text']
356
+
357
+ # Generate audio using XTTS
358
+ audio = self.tts_model.tts(
359
+ text=text,
360
+ language="en"
361
+ )
362
+
363
+ scene_audio.extend(audio)
364
+
365
+ # Add pause between scenes
366
+ pause = np.zeros(int(sample_rate * 1.0)) # 1 second pause
367
+ scene_audio.extend(pause)
368
+ audio_segments.extend(scene_audio)
369
+
370
+ # Save combined audio
371
+ audio_path = f"{self.temp_dir}/film_audio.wav"
372
+ sf.write(audio_path, audio_segments, sample_rate)
373
+
374
+ self.clear_gpu_memory()
375
+ return audio_path
376
+
377
+ except Exception as e:
378
+ print(f"Audio generation failed: {e}")
379
+ return None
380
+
381
+ def merge_videos_with_ffmpeg(self, scene_videos: List[str], audio_path: str = None) -> str:
382
+ """Merge videos using ffmpeg"""
383
+ if not scene_videos:
384
+ return None
385
+
386
+ final_video_path = f"{self.temp_dir}/final_cartoon_film.mp4"
387
+
388
+ try:
389
+ # Create concat file
390
+ concat_file = f"{self.temp_dir}/concat_list.txt"
391
+ with open(concat_file, 'w') as f:
392
+ for video in scene_videos:
393
+ if os.path.exists(video):
394
+ f.write(f"file '{os.path.abspath(video)}'\n")
395
+
396
+ if audio_path and os.path.exists(audio_path):
397
+ # Merge videos with audio
398
+ cmd = [
399
+ 'ffmpeg', '-f', 'concat', '-safe', '0', '-i', concat_file,
400
+ '-i', audio_path,
401
+ '-c:v', 'libx264', '-c:a', 'aac',
402
+ '-shortest', '-y', final_video_path
403
+ ]
404
+ else:
405
+ # Merge videos without audio
406
+ cmd = [
407
+ 'ffmpeg', '-f', 'concat', '-safe', '0', '-i', concat_file,
408
+ '-c', 'copy', '-y', final_video_path
409
+ ]
410
+
411
+ result = subprocess.run(cmd, capture_output=True, text=True)
412
+ if result.returncode == 0:
413
+ return final_video_path
414
+ else:
415
+ print(f"FFmpeg error: {result.stderr}")
416
+ return None
417
+
418
+ except Exception as e:
419
+ print(f"Video merging failed: {e}")
420
+ return None
421
+
422
+ @spaces.GPU
423
+ def generate_cartoon_film(self, script: str, include_audio: bool = True) -> tuple:
424
+ """Main function to generate complete cartoon film"""
425
+ try:
426
+ progress_updates = []
427
+
428
+ # Step 1: Enhance script
429
+ progress_updates.append("🎬 Processing and enhancing script...")
430
+ processed_script = self.enhance_script_with_llm(script)
431
+
432
+ # Step 2: Generate characters
433
+ progress_updates.append("πŸ‘₯ Creating character designs...")
434
+ character_images = self.generate_character_images(processed_script['characters'])
435
+
436
+ # Step 3: Generate backgrounds
437
+ progress_updates.append("🏞️ Generating scene backgrounds...")
438
+ background_images = self.generate_background_images(processed_script['scenes'])
439
+
440
+ # Step 4: Generate scene videos
441
+ progress_updates.append("πŸŽ₯ Creating animated scenes...")
442
+ scene_videos = self.generate_scene_videos(
443
+ processed_script['scenes'],
444
+ character_images,
445
+ background_images
446
+ )
447
+
448
+ # Step 5: Generate audio
449
+ audio_path = None
450
+ if include_audio:
451
+ progress_updates.append("🎡 Generating audio and voices...")
452
+ audio_path = self.generate_audio(processed_script['scenes'])
453
+
454
+ # Step 6: Merge final video
455
+ progress_updates.append("🎞️ Merging final cartoon film...")
456
+ final_video = self.merge_videos_with_ffmpeg(scene_videos, audio_path)
457
+
458
+ if final_video and os.path.exists(final_video):
459
+ return final_video, json.dumps(processed_script, indent=2), "βœ… Cartoon film generated successfully!"
460
+ else:
461
+ return None, json.dumps(processed_script, indent=2), "❌ Error in final video generation"
462
+
463
+ except Exception as e:
464
+ return None, f"Error: {str(e)}", f"❌ Generation failed: {str(e)}"
465
 
466
+ # Initialize generator
467
+ generator = CartoonFilmGenerator()
468
 
469
  @spaces.GPU
470
+ def create_cartoon_film(script, include_audio):
471
+ """Gradio interface function"""
472
+ if not script.strip():
473
+ return None, "", "❌ Please enter a script"
474
+
475
+ return generator.generate_cartoon_film(script, include_audio)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
 
477
+ # Gradio Interface optimized for ZeroGPU
478
+ with gr.Blocks(
479
+ title="🎬 AI Cartoon Film Generator",
480
+ theme=gr.themes.Soft(),
481
+ css="""
482
+ .gradio-container {
483
+ max-width: 1200px !important;
484
+ }
485
+ """
486
+ ) as demo:
487
+
488
+ gr.Markdown("""
489
+ # 🎬 AI Cartoon Film Generator (100% Open Source)
490
+
491
+ Transform your script into a complete 7-10 minute cartoon film using only open-source models!
492
+
493
+ **πŸ”₯ Features:**
494
+ - **Stable Diffusion XL** for high-quality character & background generation
495
+ - **AnimateDiff** for smooth video animation
496
+ - **XTTS** for multilingual voice synthesis
497
+ - **All models run on ZeroGPU** - completely free!
498
+ - **No API keys required** - everything is open source
499
+
500
+ **⚑ Optimized for Hugging Face ZeroGPU**
501
+ """)
502
+
503
+ with gr.Row():
504
+ with gr.Column(scale=1):
505
+ script_input = gr.Textbox(
506
+ label="πŸ“ Your Script",
507
+ placeholder="Enter your story idea here! Can be just a few sentences - the AI will expand it into a full cartoon film.\n\nExample: 'A young explorer discovers a magical forest where animals can talk and help find a lost treasure.'",
508
+ lines=8,
509
+ max_lines=15
510
+ )
511
+
512
+ with gr.Row():
513
+ include_audio = gr.Checkbox(
514
+ label="🎡 Include AI-Generated Voices",
515
+ value=True,
516
+ info="Generate speech for character dialogue"
517
+ )
518
+
519
+ generate_btn = gr.Button(
520
+ "🎬 Generate Cartoon Film",
521
+ variant="primary",
522
+ size="lg"
523
+ )
524
+
525
+ gr.Markdown("""
526
+ **⏱️ Processing Time:** 10-15 minutes
527
+ **πŸŽ₯ Output:** 7-10 minute MP4 film
528
+ **πŸ“± All models:** 100% open source & free
529
+ """)
530
+
531
+ with gr.Column(scale=1):
532
+ video_output = gr.Video(
533
+ label="🎬 Generated Cartoon Film",
534
+ height=400
535
+ )
536
+
537
+ status_output = gr.Textbox(
538
+ label="πŸ“Š Status",
539
+ lines=2
540
+ )
541
+
542
+ script_details = gr.JSON(
543
+ label="πŸ“‹ Generated Script Details",
544
+ visible=False
545
+ )
546
+
547
+ # Event handlers
548
+ generate_btn.click(
549
+ fn=create_cartoon_film,
550
+ inputs=[script_input, include_audio],
551
+ outputs=[video_output, script_details, status_output],
552
+ show_progress=True
553
+ )
554
+
555
+ # Example scripts
556
+ gr.Examples(
557
+ examples=[
558
+ ["A brave young explorer discovers a magical forest where talking animals help her find a lost treasure that will save her village.", True],
559
+ ["Two best friends embark on a space adventure to help a friendly alien return home while learning about friendship and courage.", True],
560
+ ["A small robot in a big city learns about emotions and friendship when it meets a lonely child who needs a companion.", False],
561
+ ["A young artist discovers their drawings come to life and must help the characters solve problems in both the real and drawn worlds.", True]
562
+ ],
563
+ inputs=[script_input, include_audio],
564
+ label="πŸ’‘ Try these example scripts:"
565
+ )
566
+
567
+ gr.Markdown("""
568
+ ---
569
+ **πŸ”§ Technical Details:**
570
+ - **Image Generation:** Stable Diffusion XL (open source)
571
+ - **Video Animation:** AnimateDiff (open source)
572
+ - **Voice Synthesis:** XTTS v2 (open source)
573
+ - **Script Enhancement:** DialoGPT (open source)
574
+ - **Infrastructure:** Hugging Face ZeroGPU (free)
575
+
576
+ **πŸ’ Completely free and open source!** No API keys or subscriptions required.
577
+ """)
578
 
579
+ if __name__ == "__main__":
580
+ demo.queue(max_size=3).launch()