Update app.py
Browse files
app.py
CHANGED
@@ -595,6 +595,11 @@ class ProfessionalCartoonFilmGenerator:
|
|
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
|
@@ -721,7 +726,12 @@ class ProfessionalCartoonFilmGenerator:
|
|
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()
|
726 |
progress = i / total_frames
|
727 |
|
@@ -729,6 +739,8 @@ class ProfessionalCartoonFilmGenerator:
|
|
729 |
frame = self._apply_cinematic_effects(frame, scene, progress)
|
730 |
out.write(frame)
|
731 |
|
|
|
|
|
732 |
out.release()
|
733 |
|
734 |
if os.path.exists(video_path):
|
@@ -747,48 +759,128 @@ class ProfessionalCartoonFilmGenerator:
|
|
747 |
|
748 |
def _apply_cinematic_effects(self, frame, scene, progress):
|
749 |
"""Apply professional cinematic effects"""
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
755 |
|
756 |
-
if
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
frame = cv2.warpAffine(frame, M, (w, h))
|
762 |
-
|
763 |
-
elif 'close-up' in shot_type:
|
764 |
-
# Gentle zoom in for emotional moments
|
765 |
-
scale = 1.0 + progress * 0.08
|
766 |
-
center_x, center_y = w // 2, h // 2
|
767 |
-
M = cv2.getRotationMatrix2D((center_x, center_y), 0, scale)
|
768 |
-
frame = cv2.warpAffine(frame, M, (w, h))
|
769 |
-
|
770 |
-
elif mood == 'exciting':
|
771 |
-
# Dynamic camera movement
|
772 |
-
shift_x = int(np.sin(progress * 4 * np.pi) * 8)
|
773 |
-
shift_y = int(np.cos(progress * 2 * np.pi) * 4)
|
774 |
-
M = np.float32([[1, 0, shift_x], [0, 1, shift_y]])
|
775 |
-
frame = cv2.warpAffine(frame, M, (w, h))
|
776 |
-
|
777 |
-
elif mood == 'peaceful':
|
778 |
-
# Gentle floating motion
|
779 |
-
shift_y = int(np.sin(progress * 2 * np.pi) * 6)
|
780 |
-
M = np.float32([[1, 0, 0], [0, 1, shift_y]])
|
781 |
-
frame = cv2.warpAffine(frame, M, (w, h))
|
782 |
-
|
783 |
-
elif mood == 'mysterious':
|
784 |
-
# Subtle rotation and zoom
|
785 |
-
angle = np.sin(progress * np.pi) * 2
|
786 |
-
scale = 1.0 + np.sin(progress * np.pi) * 0.05
|
787 |
-
center_x, center_y = w // 2, h // 2
|
788 |
-
M = cv2.getRotationMatrix2D((center_x, center_y), angle, scale)
|
789 |
-
frame = cv2.warpAffine(frame, M, (w, h))
|
790 |
|
791 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
792 |
|
793 |
def _create_emergency_fallback_video(self, script_data: Dict) -> str:
|
794 |
"""Create a simple emergency fallback video when everything else fails"""
|
|
|
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 |
+
|
599 |
+
# If professional video fails, try simple video
|
600 |
+
if not video_path:
|
601 |
+
print(f"π Professional video failed, trying simple video for scene {scene_num}...")
|
602 |
+
video_path = self._create_simple_static_video(scene, background_images)
|
603 |
else:
|
604 |
print(f"π¬ Using static video fallback for scene {scene_num}...")
|
605 |
# Fallback to enhanced static video
|
|
|
726 |
return None
|
727 |
|
728 |
# Advanced animation effects based on scene mood and type
|
729 |
+
print(f"π¬ Generating {total_frames} frames...")
|
730 |
+
|
731 |
for i in range(total_frames):
|
732 |
+
if i % 100 == 0: # Progress update every 100 frames
|
733 |
+
print(f" Frame {i}/{total_frames} ({i/total_frames*100:.1f}%)")
|
734 |
+
|
735 |
frame = img_array.copy()
|
736 |
progress = i / total_frames
|
737 |
|
|
|
739 |
frame = self._apply_cinematic_effects(frame, scene, progress)
|
740 |
out.write(frame)
|
741 |
|
742 |
+
print(f"β
All {total_frames} frames generated")
|
743 |
+
|
744 |
out.release()
|
745 |
|
746 |
if os.path.exists(video_path):
|
|
|
759 |
|
760 |
def _apply_cinematic_effects(self, frame, scene, progress):
|
761 |
"""Apply professional cinematic effects"""
|
762 |
+
try:
|
763 |
+
h, w = frame.shape[:2]
|
764 |
+
|
765 |
+
# Choose effect based on scene mood and type
|
766 |
+
mood = scene.get('mood', 'heartwarming')
|
767 |
+
shot_type = scene.get('shot_type', 'medium shot')
|
768 |
+
|
769 |
+
if 'establishing' in shot_type:
|
770 |
+
# Slow zoom out for establishing shots
|
771 |
+
scale = 1.15 - progress * 0.1
|
772 |
+
center_x, center_y = w // 2, h // 2
|
773 |
+
M = cv2.getRotationMatrix2D((center_x, center_y), 0, scale)
|
774 |
+
frame = cv2.warpAffine(frame, M, (w, h))
|
775 |
+
|
776 |
+
elif 'close-up' in shot_type:
|
777 |
+
# Gentle zoom in for emotional moments
|
778 |
+
scale = 1.0 + progress * 0.08
|
779 |
+
center_x, center_y = w // 2, h // 2
|
780 |
+
M = cv2.getRotationMatrix2D((center_x, center_y), 0, scale)
|
781 |
+
frame = cv2.warpAffine(frame, M, (w, h))
|
782 |
+
|
783 |
+
elif mood == 'exciting':
|
784 |
+
# Dynamic camera movement
|
785 |
+
shift_x = int(np.sin(progress * 4 * np.pi) * 8)
|
786 |
+
shift_y = int(np.cos(progress * 2 * np.pi) * 4)
|
787 |
+
M = np.float32([[1, 0, shift_x], [0, 1, shift_y]])
|
788 |
+
frame = cv2.warpAffine(frame, M, (w, h))
|
789 |
+
|
790 |
+
elif mood == 'peaceful':
|
791 |
+
# Gentle floating motion
|
792 |
+
shift_y = int(np.sin(progress * 2 * np.pi) * 6)
|
793 |
+
M = np.float32([[1, 0, 0], [0, 1, shift_y]])
|
794 |
+
frame = cv2.warpAffine(frame, M, (w, h))
|
795 |
+
|
796 |
+
elif mood == 'mysterious':
|
797 |
+
# Subtle rotation and zoom
|
798 |
+
angle = np.sin(progress * np.pi) * 2
|
799 |
+
scale = 1.0 + np.sin(progress * np.pi) * 0.05
|
800 |
+
center_x, center_y = w // 2, h // 2
|
801 |
+
M = cv2.getRotationMatrix2D((center_x, center_y), angle, scale)
|
802 |
+
frame = cv2.warpAffine(frame, M, (w, h))
|
803 |
+
else:
|
804 |
+
# Default: gentle zoom for heartwarming scenes
|
805 |
+
scale = 1.0 + progress * 0.03
|
806 |
+
center_x, center_y = w // 2, h // 2
|
807 |
+
M = cv2.getRotationMatrix2D((center_x, center_y), 0, scale)
|
808 |
+
frame = cv2.warpAffine(frame, M, (w, h))
|
809 |
+
|
810 |
+
return frame
|
811 |
+
|
812 |
+
except Exception as e:
|
813 |
+
print(f"β οΈ Cinematic effect failed: {e}, using original frame")
|
814 |
+
return frame
|
815 |
+
|
816 |
+
def _create_simple_static_video(self, scene: Dict, background_images: Dict) -> str:
|
817 |
+
"""Create a simple static video without complex effects"""
|
818 |
+
scene_num = scene['scene_number']
|
819 |
|
820 |
+
if scene_num not in background_images:
|
821 |
+
print(f"β No background image for scene {scene_num}")
|
822 |
+
return None
|
823 |
+
|
824 |
+
video_path = f"{self.temp_dir}/simple_scene_{scene_num}.mp4"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
825 |
|
826 |
+
try:
|
827 |
+
print(f"π¬ Creating simple video for scene {scene_num}...")
|
828 |
+
|
829 |
+
# Load background image
|
830 |
+
bg_path = background_images[scene_num]
|
831 |
+
print(f"π Loading background from: {bg_path}")
|
832 |
+
|
833 |
+
if not os.path.exists(bg_path):
|
834 |
+
print(f"β Background file not found: {bg_path}")
|
835 |
+
return None
|
836 |
+
|
837 |
+
image = Image.open(bg_path)
|
838 |
+
img_array = np.array(image.resize((1024, 768))) # 4:3 aspect ratio
|
839 |
+
img_array = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
|
840 |
+
|
841 |
+
print(f"π Image size: {img_array.shape}")
|
842 |
+
|
843 |
+
# Simple video settings
|
844 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
845 |
+
fps = 24
|
846 |
+
duration = 10 # Shorter duration for simple video
|
847 |
+
total_frames = duration * fps
|
848 |
+
|
849 |
+
print(f"π¬ Simple video settings: {fps}fps, {duration}s duration, {total_frames} frames")
|
850 |
+
|
851 |
+
out = cv2.VideoWriter(video_path, fourcc, fps, (1024, 768))
|
852 |
+
|
853 |
+
if not out.isOpened():
|
854 |
+
print(f"β Failed to open simple video writer for {video_path}")
|
855 |
+
return None
|
856 |
+
|
857 |
+
# Simple static video - just repeat the same frame
|
858 |
+
print(f"π¬ Generating {total_frames} simple frames...")
|
859 |
+
|
860 |
+
for i in range(total_frames):
|
861 |
+
if i % 50 == 0: # Progress update every 50 frames
|
862 |
+
print(f" Frame {i}/{total_frames} ({i/total_frames*100:.1f}%)")
|
863 |
+
|
864 |
+
# Just use the same frame without effects
|
865 |
+
out.write(img_array)
|
866 |
+
|
867 |
+
print(f"β
All {total_frames} simple frames generated")
|
868 |
+
|
869 |
+
out.release()
|
870 |
+
|
871 |
+
if os.path.exists(video_path):
|
872 |
+
file_size = os.path.getsize(video_path)
|
873 |
+
print(f"β
Simple video created: {video_path} ({file_size / (1024*1024):.1f} MB)")
|
874 |
+
return video_path
|
875 |
+
else:
|
876 |
+
print(f"β Simple video file not created: {video_path}")
|
877 |
+
return None
|
878 |
+
|
879 |
+
except Exception as e:
|
880 |
+
print(f"β Simple video creation failed for scene {scene_num}: {e}")
|
881 |
+
import traceback
|
882 |
+
traceback.print_exc()
|
883 |
+
return None
|
884 |
|
885 |
def _create_emergency_fallback_video(self, script_data: Dict) -> str:
|
886 |
"""Create a simple emergency fallback video when everything else fails"""
|