Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -575,28 +575,55 @@ class ProfessionalCartoonFilmGenerator:
|
|
| 575 |
"""Generate professional videos using Open-Sora 2.0"""
|
| 576 |
scene_videos = []
|
| 577 |
|
|
|
|
|
|
|
|
|
|
| 578 |
# Try to use Open-Sora for professional video generation
|
| 579 |
opensora_available = self.setup_opensora_for_video()
|
|
|
|
| 580 |
|
| 581 |
for scene in scenes:
|
|
|
|
|
|
|
|
|
|
| 582 |
try:
|
| 583 |
if opensora_available:
|
|
|
|
| 584 |
video_path = self._generate_opensora_video(scene, character_images, background_images)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 585 |
else:
|
|
|
|
| 586 |
# Fallback to enhanced static video
|
| 587 |
video_path = self._create_professional_static_video(scene, background_images)
|
| 588 |
|
| 589 |
-
if video_path:
|
| 590 |
scene_videos.append(video_path)
|
| 591 |
-
print(f"β
Generated professional video for scene {
|
|
|
|
|
|
|
|
|
|
| 592 |
|
| 593 |
except Exception as e:
|
| 594 |
-
print(f"β Error in scene {
|
| 595 |
# Create fallback video
|
| 596 |
-
if
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
|
| 601 |
return scene_videos
|
| 602 |
|
|
@@ -654,25 +681,45 @@ class ProfessionalCartoonFilmGenerator:
|
|
| 654 |
|
| 655 |
def _create_professional_static_video(self, scene: Dict, background_images: Dict) -> str:
|
| 656 |
"""Create professional static video with advanced effects"""
|
| 657 |
-
|
|
|
|
|
|
|
|
|
|
| 658 |
return None
|
| 659 |
|
| 660 |
-
video_path = f"{self.temp_dir}/scene_{
|
| 661 |
|
| 662 |
try:
|
|
|
|
|
|
|
| 663 |
# Load background image
|
| 664 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 665 |
img_array = np.array(image.resize((1024, 768))) # 4:3 aspect ratio
|
| 666 |
img_array = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
|
| 667 |
|
|
|
|
|
|
|
| 668 |
# Professional video settings
|
| 669 |
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
| 670 |
fps = 24 # Cinematic frame rate
|
| 671 |
duration = int(scene.get('duration', 35))
|
| 672 |
total_frames = duration * fps
|
| 673 |
|
|
|
|
|
|
|
| 674 |
out = cv2.VideoWriter(video_path, fourcc, fps, (1024, 768))
|
| 675 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 676 |
# Advanced animation effects based on scene mood and type
|
| 677 |
for i in range(total_frames):
|
| 678 |
frame = img_array.copy()
|
|
@@ -683,10 +730,19 @@ class ProfessionalCartoonFilmGenerator:
|
|
| 683 |
out.write(frame)
|
| 684 |
|
| 685 |
out.release()
|
| 686 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 687 |
|
| 688 |
except Exception as e:
|
| 689 |
-
print(f"β Professional static video creation failed: {e}")
|
|
|
|
|
|
|
| 690 |
return None
|
| 691 |
|
| 692 |
def _apply_cinematic_effects(self, frame, scene, progress):
|
|
@@ -734,6 +790,61 @@ class ProfessionalCartoonFilmGenerator:
|
|
| 734 |
|
| 735 |
return frame
|
| 736 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 737 |
def merge_professional_film(self, scene_videos: List[str], script_data: Dict) -> str:
|
| 738 |
"""Merge videos into professional cartoon film"""
|
| 739 |
if not scene_videos:
|
|
@@ -784,10 +895,12 @@ class ProfessionalCartoonFilmGenerator:
|
|
| 784 |
# Step 1: Generate professional script
|
| 785 |
print("π Creating professional script structure...")
|
| 786 |
script_data = self.generate_professional_script(script)
|
|
|
|
| 787 |
|
| 788 |
# Step 2: Generate high-quality characters
|
| 789 |
print("π Creating professional character designs...")
|
| 790 |
character_images = self.generate_professional_character_images(script_data['characters'])
|
|
|
|
| 791 |
|
| 792 |
# Step 3: Generate cinematic backgrounds
|
| 793 |
print("ποΈ Creating cinematic backgrounds...")
|
|
@@ -795,6 +908,7 @@ class ProfessionalCartoonFilmGenerator:
|
|
| 795 |
script_data['scenes'],
|
| 796 |
script_data['color_palette']
|
| 797 |
)
|
|
|
|
| 798 |
|
| 799 |
# Step 4: Generate professional videos
|
| 800 |
print("π₯ Creating professional animated scenes...")
|
|
@@ -803,20 +917,42 @@ class ProfessionalCartoonFilmGenerator:
|
|
| 803 |
character_images,
|
| 804 |
background_images
|
| 805 |
)
|
|
|
|
| 806 |
|
| 807 |
# Step 5: Merge into professional film
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 814 |
else:
|
| 815 |
-
print("
|
| 816 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 817 |
|
| 818 |
except Exception as e:
|
| 819 |
print(f"β Generation failed: {e}")
|
|
|
|
|
|
|
| 820 |
error_info = {
|
| 821 |
"error": True,
|
| 822 |
"message": str(e),
|
|
|
|
| 575 |
"""Generate professional videos using Open-Sora 2.0"""
|
| 576 |
scene_videos = []
|
| 577 |
|
| 578 |
+
print(f"π₯ Starting video generation for {len(scenes)} scenes...")
|
| 579 |
+
print(f"π Background images available: {list(background_images.keys())}")
|
| 580 |
+
|
| 581 |
# Try to use Open-Sora for professional video generation
|
| 582 |
opensora_available = self.setup_opensora_for_video()
|
| 583 |
+
print(f"π¬ Open-Sora available: {opensora_available}")
|
| 584 |
|
| 585 |
for scene in scenes:
|
| 586 |
+
scene_num = scene['scene_number']
|
| 587 |
+
print(f"\n㪠Processing scene {scene_num}...")
|
| 588 |
+
|
| 589 |
try:
|
| 590 |
if opensora_available:
|
| 591 |
+
print(f"π¬ Attempting Open-Sora generation for scene {scene_num}...")
|
| 592 |
video_path = self._generate_opensora_video(scene, character_images, background_images)
|
| 593 |
+
if video_path:
|
| 594 |
+
print(f"β
Open-Sora video generated for scene {scene_num}")
|
| 595 |
+
else:
|
| 596 |
+
print(f"β Open-Sora failed for scene {scene_num}, trying fallback...")
|
| 597 |
+
video_path = self._create_professional_static_video(scene, background_images)
|
| 598 |
else:
|
| 599 |
+
print(f"π¬ Using static video fallback for scene {scene_num}...")
|
| 600 |
# Fallback to enhanced static video
|
| 601 |
video_path = self._create_professional_static_video(scene, background_images)
|
| 602 |
|
| 603 |
+
if video_path and os.path.exists(video_path):
|
| 604 |
scene_videos.append(video_path)
|
| 605 |
+
print(f"β
Generated professional video for scene {scene_num}: {video_path}")
|
| 606 |
+
print(f"π Video size: {os.path.getsize(video_path) / (1024*1024):.1f} MB")
|
| 607 |
+
else:
|
| 608 |
+
print(f"β No video generated for scene {scene_num}")
|
| 609 |
|
| 610 |
except Exception as e:
|
| 611 |
+
print(f"β Error in scene {scene_num}: {e}")
|
| 612 |
# Create fallback video
|
| 613 |
+
if scene_num in background_images:
|
| 614 |
+
print(f"π Creating emergency fallback for scene {scene_num}...")
|
| 615 |
+
try:
|
| 616 |
+
video_path = self._create_professional_static_video(scene, background_images)
|
| 617 |
+
if video_path and os.path.exists(video_path):
|
| 618 |
+
scene_videos.append(video_path)
|
| 619 |
+
print(f"β
Emergency fallback video created for scene {scene_num}")
|
| 620 |
+
except Exception as e2:
|
| 621 |
+
print(f"β Emergency fallback also failed for scene {scene_num}: {e2}")
|
| 622 |
+
|
| 623 |
+
print(f"\nπ Video generation summary:")
|
| 624 |
+
print(f" - Scenes processed: {len(scenes)}")
|
| 625 |
+
print(f" - Videos generated: {len(scene_videos)}")
|
| 626 |
+
print(f" - Videos list: {scene_videos}")
|
| 627 |
|
| 628 |
return scene_videos
|
| 629 |
|
|
|
|
| 681 |
|
| 682 |
def _create_professional_static_video(self, scene: Dict, background_images: Dict) -> str:
|
| 683 |
"""Create professional static video with advanced effects"""
|
| 684 |
+
scene_num = scene['scene_number']
|
| 685 |
+
|
| 686 |
+
if scene_num not in background_images:
|
| 687 |
+
print(f"β No background image for scene {scene_num}")
|
| 688 |
return None
|
| 689 |
|
| 690 |
+
video_path = f"{self.temp_dir}/scene_{scene_num}.mp4"
|
| 691 |
|
| 692 |
try:
|
| 693 |
+
print(f"π¬ Creating static video for scene {scene_num}...")
|
| 694 |
+
|
| 695 |
# Load background image
|
| 696 |
+
bg_path = background_images[scene_num]
|
| 697 |
+
print(f"π Loading background from: {bg_path}")
|
| 698 |
+
|
| 699 |
+
if not os.path.exists(bg_path):
|
| 700 |
+
print(f"β Background file not found: {bg_path}")
|
| 701 |
+
return None
|
| 702 |
+
|
| 703 |
+
image = Image.open(bg_path)
|
| 704 |
img_array = np.array(image.resize((1024, 768))) # 4:3 aspect ratio
|
| 705 |
img_array = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
|
| 706 |
|
| 707 |
+
print(f"π Image size: {img_array.shape}")
|
| 708 |
+
|
| 709 |
# Professional video settings
|
| 710 |
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
| 711 |
fps = 24 # Cinematic frame rate
|
| 712 |
duration = int(scene.get('duration', 35))
|
| 713 |
total_frames = duration * fps
|
| 714 |
|
| 715 |
+
print(f"π¬ Video settings: {fps}fps, {duration}s duration, {total_frames} frames")
|
| 716 |
+
|
| 717 |
out = cv2.VideoWriter(video_path, fourcc, fps, (1024, 768))
|
| 718 |
|
| 719 |
+
if not out.isOpened():
|
| 720 |
+
print(f"β Failed to open video writer for {video_path}")
|
| 721 |
+
return None
|
| 722 |
+
|
| 723 |
# Advanced animation effects based on scene mood and type
|
| 724 |
for i in range(total_frames):
|
| 725 |
frame = img_array.copy()
|
|
|
|
| 730 |
out.write(frame)
|
| 731 |
|
| 732 |
out.release()
|
| 733 |
+
|
| 734 |
+
if os.path.exists(video_path):
|
| 735 |
+
file_size = os.path.getsize(video_path)
|
| 736 |
+
print(f"β
Static video created: {video_path} ({file_size / (1024*1024):.1f} MB)")
|
| 737 |
+
return video_path
|
| 738 |
+
else:
|
| 739 |
+
print(f"β Video file not created: {video_path}")
|
| 740 |
+
return None
|
| 741 |
|
| 742 |
except Exception as e:
|
| 743 |
+
print(f"β Professional static video creation failed for scene {scene_num}: {e}")
|
| 744 |
+
import traceback
|
| 745 |
+
traceback.print_exc()
|
| 746 |
return None
|
| 747 |
|
| 748 |
def _apply_cinematic_effects(self, frame, scene, progress):
|
|
|
|
| 790 |
|
| 791 |
return frame
|
| 792 |
|
| 793 |
+
def _create_emergency_fallback_video(self, script_data: Dict) -> str:
|
| 794 |
+
"""Create a simple emergency fallback video when everything else fails"""
|
| 795 |
+
try:
|
| 796 |
+
print("π Creating emergency fallback video...")
|
| 797 |
+
|
| 798 |
+
# Create a simple colored background
|
| 799 |
+
width, height = 1024, 768
|
| 800 |
+
background_color = (100, 150, 200) # Blue-ish color
|
| 801 |
+
|
| 802 |
+
# Create video
|
| 803 |
+
video_path = f"{self.temp_dir}/emergency_fallback.mp4"
|
| 804 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
| 805 |
+
fps = 24
|
| 806 |
+
duration = 30 # 30 seconds
|
| 807 |
+
total_frames = duration * fps
|
| 808 |
+
|
| 809 |
+
out = cv2.VideoWriter(video_path, fourcc, fps, (width, height))
|
| 810 |
+
|
| 811 |
+
if not out.isOpened():
|
| 812 |
+
print("β Failed to open emergency video writer")
|
| 813 |
+
return None
|
| 814 |
+
|
| 815 |
+
# Create simple animated background
|
| 816 |
+
for i in range(total_frames):
|
| 817 |
+
frame = np.full((height, width, 3), background_color, dtype=np.uint8)
|
| 818 |
+
|
| 819 |
+
# Add simple animation (color shift)
|
| 820 |
+
progress = i / total_frames
|
| 821 |
+
color_shift = int(50 * np.sin(progress * 2 * np.pi))
|
| 822 |
+
frame[:, :, 0] = np.clip(frame[:, :, 0] + color_shift, 0, 255)
|
| 823 |
+
|
| 824 |
+
# Add text
|
| 825 |
+
font = cv2.FONT_HERSHEY_SIMPLEX
|
| 826 |
+
text = f"Cartoon Film: {script_data.get('title', 'Adventure')}"
|
| 827 |
+
text_size = cv2.getTextSize(text, font, 1, 2)[0]
|
| 828 |
+
text_x = (width - text_size[0]) // 2
|
| 829 |
+
text_y = height // 2
|
| 830 |
+
|
| 831 |
+
cv2.putText(frame, text, (text_x, text_y), font, 1, (255, 255, 255), 2)
|
| 832 |
+
|
| 833 |
+
out.write(frame)
|
| 834 |
+
|
| 835 |
+
out.release()
|
| 836 |
+
|
| 837 |
+
if os.path.exists(video_path):
|
| 838 |
+
print(f"β
Emergency fallback video created: {video_path}")
|
| 839 |
+
return video_path
|
| 840 |
+
else:
|
| 841 |
+
print("β Emergency fallback video file not created")
|
| 842 |
+
return None
|
| 843 |
+
|
| 844 |
+
except Exception as e:
|
| 845 |
+
print(f"β Emergency fallback video creation failed: {e}")
|
| 846 |
+
return None
|
| 847 |
+
|
| 848 |
def merge_professional_film(self, scene_videos: List[str], script_data: Dict) -> str:
|
| 849 |
"""Merge videos into professional cartoon film"""
|
| 850 |
if not scene_videos:
|
|
|
|
| 895 |
# Step 1: Generate professional script
|
| 896 |
print("π Creating professional script structure...")
|
| 897 |
script_data = self.generate_professional_script(script)
|
| 898 |
+
print(f"β
Script generated with {len(script_data['scenes'])} scenes")
|
| 899 |
|
| 900 |
# Step 2: Generate high-quality characters
|
| 901 |
print("π Creating professional character designs...")
|
| 902 |
character_images = self.generate_professional_character_images(script_data['characters'])
|
| 903 |
+
print(f"β
Characters generated: {list(character_images.keys())}")
|
| 904 |
|
| 905 |
# Step 3: Generate cinematic backgrounds
|
| 906 |
print("ποΈ Creating cinematic backgrounds...")
|
|
|
|
| 908 |
script_data['scenes'],
|
| 909 |
script_data['color_palette']
|
| 910 |
)
|
| 911 |
+
print(f"β
Backgrounds generated: {list(background_images.keys())}")
|
| 912 |
|
| 913 |
# Step 4: Generate professional videos
|
| 914 |
print("π₯ Creating professional animated scenes...")
|
|
|
|
| 917 |
character_images,
|
| 918 |
background_images
|
| 919 |
)
|
| 920 |
+
print(f"β
Videos generated: {len(scene_videos)} videos")
|
| 921 |
|
| 922 |
# Step 5: Merge into professional film
|
| 923 |
+
if scene_videos:
|
| 924 |
+
print("ποΈ Creating final professional cartoon film...")
|
| 925 |
+
final_video = self.merge_professional_film(scene_videos, script_data)
|
| 926 |
+
|
| 927 |
+
if final_video and os.path.exists(final_video):
|
| 928 |
+
file_size = os.path.getsize(final_video) / (1024*1024)
|
| 929 |
+
print(f"β
Professional cartoon film generation complete!")
|
| 930 |
+
print(f"π Final video: {final_video} ({file_size:.1f} MB)")
|
| 931 |
+
return final_video, script_data, f"β
Professional cartoon film generated successfully! ({file_size:.1f} MB)"
|
| 932 |
+
else:
|
| 933 |
+
print("β οΈ Video merging failed")
|
| 934 |
+
return None, script_data, "β οΈ Video merging failed"
|
| 935 |
else:
|
| 936 |
+
print("β No videos to merge - video generation failed")
|
| 937 |
+
print("π Creating emergency fallback video...")
|
| 938 |
+
|
| 939 |
+
# Create at least one simple video as fallback
|
| 940 |
+
try:
|
| 941 |
+
emergency_video = self._create_emergency_fallback_video(script_data)
|
| 942 |
+
if emergency_video and os.path.exists(emergency_video):
|
| 943 |
+
file_size = os.path.getsize(emergency_video) / (1024*1024)
|
| 944 |
+
print(f"β
Emergency fallback video created: {emergency_video} ({file_size:.1f} MB)")
|
| 945 |
+
return emergency_video, script_data, f"β οΈ Emergency fallback video created ({file_size:.1f} MB)"
|
| 946 |
+
else:
|
| 947 |
+
return None, script_data, "β No videos generated - all methods failed"
|
| 948 |
+
except Exception as e:
|
| 949 |
+
print(f"β Emergency fallback also failed: {e}")
|
| 950 |
+
return None, script_data, "β No videos generated - all methods failed"
|
| 951 |
|
| 952 |
except Exception as e:
|
| 953 |
print(f"β Generation failed: {e}")
|
| 954 |
+
import traceback
|
| 955 |
+
traceback.print_exc()
|
| 956 |
error_info = {
|
| 957 |
"error": True,
|
| 958 |
"message": str(e),
|