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