shaheerawan3 commited on
Commit
3484cc4
·
verified ·
1 Parent(s): cd00544

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +160 -160
app.py CHANGED
@@ -833,180 +833,180 @@ class EnhancedVideoGenerator:
833
  return f"{hours:02d}:{minutes:02d}:{secs:02d},{msecs:03d}"
834
 
835
  def create_video(self, script: str, style: str, duration: int, output_path: str, selected_images: List[str]) -> str:
836
- """Create video with enhanced features and proper error handling"""
837
- try:
838
- # Initialize progress tracking
839
- progress_bar = st.progress(0)
840
- status_text = st.empty()
841
-
842
- # Create output directory if it doesn't exist
843
- os.makedirs(os.path.dirname(output_path), exist_ok=True)
844
-
845
- # Validate inputs and paths
846
- if not output_path:
847
- raise ValueError("Output path cannot be empty")
848
- if not selected_images:
849
- raise ValueError("No images selected")
850
-
851
- # Generate voice-over with progress tracking
852
- status_text.text("Creating voice-over...")
853
- audio = self.generate_voice_over(script)
854
- progress_bar.progress(20)
855
-
856
- # Process images with effects
857
- status_text.text("Processing images with effects...")
858
- processed_images = []
859
-
860
- for img_url in selected_images:
861
- try:
862
- response = requests.get(img_url, timeout=10)
863
- response.raise_for_status()
864
- img = Image.open(BytesIO(response.content))
865
- img = img.convert('RGB')
866
-
867
- # Apply image effects based on style
868
- if style == "Creative":
869
- # Add creative effects
870
- enhancer = ImageEnhance.Contrast(img)
871
- img = enhancer.enhance(1.2)
872
- enhancer = ImageEnhance.Brightness(img)
873
- img = enhancer.enhance(1.1)
874
- elif style == "Professional":
875
- # Add professional effects
876
- enhancer = ImageEnhance.Sharpness(img)
877
- img = enhancer.enhance(1.3)
878
-
879
- img = img.resize((1920, 1080), Image.Resampling.LANCZOS)
880
- processed_images.append(img)
881
 
882
- except Exception as e:
883
- print(f"Error processing image {img_url}: {e}")
884
- continue
885
-
886
- progress_bar.progress(40)
887
-
888
- # Generate frames with transitions
889
- status_text.text("Creating frames with transitions...")
890
- frames = []
891
- fps = 30
892
- total_frames = int(duration * fps)
893
- frames_per_image = total_frames // len(processed_images)
894
-
895
- # Convert images to numpy arrays
896
- image_arrays = [np.array(img) for img in processed_images]
897
-
898
- # Add transition effects
899
- frame_count = 0
900
- for idx, img_array in enumerate(image_arrays):
901
- # Calculate frames for this image
902
- if idx == len(image_arrays) - 1:
903
- n_frames = total_frames - frame_count
904
- else:
905
- n_frames = min(frames_per_image, total_frames - frame_count)
906
-
907
- # Add effects and transitions
908
- for frame_idx in range(n_frames):
909
- # Apply fade in/out effect
910
- alpha = 1.0
911
- if frame_idx < 15: # Fade in
912
- alpha = frame_idx / 15
913
- elif frame_idx > n_frames - 15: # Fade out
914
- alpha = (n_frames - frame_idx) / 15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
915
 
916
- frame = img_array * alpha
917
- frames.append(frame.astype(np.uint8))
918
- frame_count += 1
 
 
 
 
 
 
 
 
 
 
 
 
 
919
 
920
- # Update progress
921
- progress = int(40 + (frame_count / total_frames * 30))
922
- progress_bar.progress(progress)
923
-
924
- # Add transition to next image
925
- if idx < len(image_arrays) - 1:
926
- next_img_array = image_arrays[idx + 1]
927
- transition_frames = 15
928
- for t in range(transition_frames):
929
- if frame_count < total_frames:
930
- alpha = t / transition_frames
931
- transition_frame = cv2.addWeighted(
932
- img_array, 1 - alpha,
933
- next_img_array, alpha, 0
934
- )
935
- frames.append(transition_frame)
936
- frame_count += 1
937
-
938
- progress_bar.progress(70)
939
-
940
- # Create video with frames
941
- status_text.text("Compiling video...")
942
- clip = ImageSequenceClip(frames, fps=fps)
943
-
944
- # Add audio with proper synchronization
945
- audio_duration = audio.duration
946
- video_duration = len(frames) / fps
947
-
948
- if audio_duration > video_duration:
949
- audio = audio.subclip(0, video_duration)
950
- elif audio_duration < video_duration:
951
- clip = clip.subclip(0, audio_duration)
952
-
953
- final_clip = clip.set_audio(audio)
954
-
955
- # Write video with progress caching
956
- status_text.text("Saving video...")
957
- cache_dir = os.path.join(os.path.dirname(output_path), ".cache")
958
- os.makedirs(cache_dir, exist_ok=True)
959
-
960
- try:
961
- final_clip.write_videofile(
962
- output_path,
963
- fps=fps,
964
- codec='libx264',
965
- audio_codec='aac',
966
- ffmpeg_params=['-pix_fmt', 'yuv420p'],
967
- temp_audiofile=os.path.join(cache_dir, "temp-audio.m4a"),
968
- verbose=False,
969
- logger=None
970
- )
971
- except Exception as e:
972
- # Attempt error recovery
973
- status_text.text("Attempting error recovery...")
974
  try:
975
- # Try alternative codec settings
976
  final_clip.write_videofile(
977
  output_path,
978
  fps=fps,
979
  codec='libx264',
980
- audio_codec='mp3',
 
 
981
  verbose=False,
982
  logger=None
983
  )
984
- except Exception as recovery_e:
985
- raise RuntimeError(f"Video creation failed even with recovery attempt: {str(recovery_e)}")
986
-
987
- progress_bar.progress(100)
988
- status_text.text("Video generation complete!")
989
-
990
- return output_path
991
-
992
- except Exception as e:
993
- error_msg = f"Video creation failed: {str(e)}"
994
- print(error_msg)
995
- raise RuntimeError(error_msg)
996
- finally:
997
- # Cleanup
998
- try:
999
- if 'clip' in locals():
1000
- clip.close()
1001
- if 'final_clip' in locals():
1002
- final_clip.close()
1003
- if 'audio' in locals():
1004
- audio.close()
1005
  except Exception as e:
1006
- print(f"Cleanup error: {e}")
1007
-
 
 
 
 
 
 
 
 
 
 
 
 
1008
 
1009
 
 
1010
  def generate_visual_assets(self, script: str, style: str) -> List[Dict]:
1011
  """Generate relevant visual assets based on script content"""
1012
  try:
 
833
  return f"{hours:02d}:{minutes:02d}:{secs:02d},{msecs:03d}"
834
 
835
  def create_video(self, script: str, style: str, duration: int, output_path: str, selected_images: List[str]) -> str:
836
+ """Create video with enhanced features and proper error handling"""
837
+ try:
838
+ # Initialize progress tracking
839
+ progress_bar = st.progress(0)
840
+ status_text = st.empty()
841
+
842
+ # Create output directory if it doesn't exist
843
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
844
+
845
+ # Validate inputs and paths
846
+ if not output_path:
847
+ raise ValueError("Output path cannot be empty")
848
+ if not selected_images:
849
+ raise ValueError("No images selected")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
850
 
851
+ # Generate voice-over with progress tracking
852
+ status_text.text("Creating voice-over...")
853
+ audio = self.generate_voice_over(script)
854
+ progress_bar.progress(20)
855
+
856
+ # Process images with effects
857
+ status_text.text("Processing images with effects...")
858
+ processed_images = []
859
+
860
+ for img_url in selected_images:
861
+ try:
862
+ response = requests.get(img_url, timeout=10)
863
+ response.raise_for_status()
864
+ img = Image.open(BytesIO(response.content))
865
+ img = img.convert('RGB')
866
+
867
+ # Apply image effects based on style
868
+ if style == "Creative":
869
+ # Add creative effects
870
+ enhancer = ImageEnhance.Contrast(img)
871
+ img = enhancer.enhance(1.2)
872
+ enhancer = ImageEnhance.Brightness(img)
873
+ img = enhancer.enhance(1.1)
874
+ elif style == "Professional":
875
+ # Add professional effects
876
+ enhancer = ImageEnhance.Sharpness(img)
877
+ img = enhancer.enhance(1.3)
878
+
879
+ img = img.resize((1920, 1080), Image.Resampling.LANCZOS)
880
+ processed_images.append(img)
881
+
882
+ except Exception as e:
883
+ print(f"Error processing image {img_url}: {e}")
884
+ continue
885
+
886
+ progress_bar.progress(40)
887
+
888
+ # Generate frames with transitions
889
+ status_text.text("Creating frames with transitions...")
890
+ frames = []
891
+ fps = 30
892
+ total_frames = int(duration * fps)
893
+ frames_per_image = total_frames // len(processed_images)
894
+
895
+ # Convert images to numpy arrays
896
+ image_arrays = [np.array(img) for img in processed_images]
897
+
898
+ # Add transition effects
899
+ frame_count = 0
900
+ for idx, img_array in enumerate(image_arrays):
901
+ # Calculate frames for this image
902
+ if idx == len(image_arrays) - 1:
903
+ n_frames = total_frames - frame_count
904
+ else:
905
+ n_frames = min(frames_per_image, total_frames - frame_count)
906
 
907
+ # Add effects and transitions
908
+ for frame_idx in range(n_frames):
909
+ # Apply fade in/out effect
910
+ alpha = 1.0
911
+ if frame_idx < 15: # Fade in
912
+ alpha = frame_idx / 15
913
+ elif frame_idx > n_frames - 15: # Fade out
914
+ alpha = (n_frames - frame_idx) / 15
915
+
916
+ frame = img_array * alpha
917
+ frames.append(frame.astype(np.uint8))
918
+ frame_count += 1
919
+
920
+ # Update progress
921
+ progress = int(40 + (frame_count / total_frames * 30))
922
+ progress_bar.progress(progress)
923
 
924
+ # Add transition to next image
925
+ if idx < len(image_arrays) - 1:
926
+ next_img_array = image_arrays[idx + 1]
927
+ transition_frames = 15
928
+ for t in range(transition_frames):
929
+ if frame_count < total_frames:
930
+ alpha = t / transition_frames
931
+ transition_frame = cv2.addWeighted(
932
+ img_array, 1 - alpha,
933
+ next_img_array, alpha, 0
934
+ )
935
+ frames.append(transition_frame)
936
+ frame_count += 1
937
+
938
+ progress_bar.progress(70)
939
+
940
+ # Create video with frames
941
+ status_text.text("Compiling video...")
942
+ clip = ImageSequenceClip(frames, fps=fps)
943
+
944
+ # Add audio with proper synchronization
945
+ audio_duration = audio.duration
946
+ video_duration = len(frames) / fps
947
+
948
+ if audio_duration > video_duration:
949
+ audio = audio.subclip(0, video_duration)
950
+ elif audio_duration < video_duration:
951
+ clip = clip.subclip(0, audio_duration)
952
+
953
+ final_clip = clip.set_audio(audio)
954
+
955
+ # Write video with progress caching
956
+ status_text.text("Saving video...")
957
+ cache_dir = os.path.join(os.path.dirname(output_path), ".cache")
958
+ os.makedirs(cache_dir, exist_ok=True)
959
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
960
  try:
 
961
  final_clip.write_videofile(
962
  output_path,
963
  fps=fps,
964
  codec='libx264',
965
+ audio_codec='aac',
966
+ ffmpeg_params=['-pix_fmt', 'yuv420p'],
967
+ temp_audiofile=os.path.join(cache_dir, "temp-audio.m4a"),
968
  verbose=False,
969
  logger=None
970
  )
971
+ except Exception as e:
972
+ # Attempt error recovery
973
+ status_text.text("Attempting error recovery...")
974
+ try:
975
+ # Try alternative codec settings
976
+ final_clip.write_videofile(
977
+ output_path,
978
+ fps=fps,
979
+ codec='libx264',
980
+ audio_codec='mp3',
981
+ verbose=False,
982
+ logger=None
983
+ )
984
+ except Exception as recovery_e:
985
+ raise RuntimeError(f"Video creation failed even with recovery attempt: {str(recovery_e)}")
986
+
987
+ progress_bar.progress(100)
988
+ status_text.text("Video generation complete!")
989
+
990
+ return output_path
991
+
992
  except Exception as e:
993
+ error_msg = f"Video creation failed: {str(e)}"
994
+ print(error_msg)
995
+ raise RuntimeError(error_msg)
996
+ finally:
997
+ # Cleanup
998
+ try:
999
+ if 'clip' in locals():
1000
+ clip.close()
1001
+ if 'final_clip' in locals():
1002
+ final_clip.close()
1003
+ if 'audio' in locals():
1004
+ audio.close()
1005
+ except Exception as e:
1006
+ print(f"Cleanup error: {e}")
1007
 
1008
 
1009
+
1010
  def generate_visual_assets(self, script: str, style: str) -> List[Dict]:
1011
  """Generate relevant visual assets based on script content"""
1012
  try: