Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -862,7 +862,7 @@ class EnhancedVideoGenerator:
|
|
| 862 |
return f"{hours:02d}:{minutes:02d}:{secs:02d},{msecs:03d}"
|
| 863 |
|
| 864 |
def create_video(self, script: str, style: str, duration: int, output_path: str, selected_images: List[str],
|
| 865 |
-
video_effects: dict = None) -> str:
|
| 866 |
"""Create video with selected images and effects"""
|
| 867 |
try:
|
| 868 |
# Initialize default effects if none provided
|
|
@@ -876,7 +876,9 @@ class EnhancedVideoGenerator:
|
|
| 876 |
|
| 877 |
# Process images with error handling
|
| 878 |
processed_images = []
|
| 879 |
-
|
|
|
|
|
|
|
| 880 |
try:
|
| 881 |
response = requests.get(img_url, timeout=10)
|
| 882 |
response.raise_for_status()
|
|
@@ -884,6 +886,12 @@ class EnhancedVideoGenerator:
|
|
| 884 |
img = img.convert('RGB')
|
| 885 |
img = img.resize((1920, 1080), Image.LANCZOS)
|
| 886 |
processed_images.append(img)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 887 |
except Exception as e:
|
| 888 |
self.logger.error(f"Error processing image {img_url}: {e}")
|
| 889 |
continue
|
|
@@ -893,6 +901,8 @@ class EnhancedVideoGenerator:
|
|
| 893 |
|
| 894 |
# Generate voice-over
|
| 895 |
audio = self.generate_fallback_audio(script)
|
|
|
|
|
|
|
| 896 |
|
| 897 |
# Calculate frames
|
| 898 |
fps = 30
|
|
@@ -927,9 +937,14 @@ class EnhancedVideoGenerator:
|
|
| 927 |
frame = self.apply_video_effects(img_array.copy(), current_effects)
|
| 928 |
frames.append(frame)
|
| 929 |
frame_count += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 930 |
|
| 931 |
-
# Add transition to next image
|
| 932 |
-
if idx < len(processed_images) - 1:
|
| 933 |
next_img_array = np.array(processed_images[idx + 1])
|
| 934 |
transition_frames = 15
|
| 935 |
|
|
@@ -945,7 +960,9 @@ class EnhancedVideoGenerator:
|
|
| 945 |
|
| 946 |
# Create video clip
|
| 947 |
clip = ImageSequenceClip(frames, fps=fps)
|
| 948 |
-
|
|
|
|
|
|
|
| 949 |
# Adjust audio duration
|
| 950 |
if audio.duration > clip.duration:
|
| 951 |
audio = audio.subclip(0, clip.duration)
|
|
@@ -954,6 +971,8 @@ class EnhancedVideoGenerator:
|
|
| 954 |
|
| 955 |
# Combine video and audio
|
| 956 |
final_clip = clip.set_audio(audio)
|
|
|
|
|
|
|
| 957 |
|
| 958 |
# Ensure output directory exists
|
| 959 |
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
@@ -968,6 +987,9 @@ class EnhancedVideoGenerator:
|
|
| 968 |
verbose=False,
|
| 969 |
logger=None
|
| 970 |
)
|
|
|
|
|
|
|
|
|
|
| 971 |
|
| 972 |
return output_path
|
| 973 |
|
|
@@ -985,9 +1007,9 @@ class EnhancedVideoGenerator:
|
|
| 985 |
audio.close()
|
| 986 |
except Exception as e:
|
| 987 |
self.logger.error(f"Cleanup error: {e}")
|
| 988 |
-
|
| 989 |
-
|
| 990 |
|
|
|
|
|
|
|
| 991 |
def generate_visual_assets(self, script: str, style: str) -> List[Dict]:
|
| 992 |
"""Generate relevant visual assets based on script content"""
|
| 993 |
try:
|
|
|
|
| 862 |
return f"{hours:02d}:{minutes:02d}:{secs:02d},{msecs:03d}"
|
| 863 |
|
| 864 |
def create_video(self, script: str, style: str, duration: int, output_path: str, selected_images: List[str],
|
| 865 |
+
video_effects: dict = None, progress_callback: Callable[[float], None] = None) -> str:
|
| 866 |
"""Create video with selected images and effects"""
|
| 867 |
try:
|
| 868 |
# Initialize default effects if none provided
|
|
|
|
| 876 |
|
| 877 |
# Process images with error handling
|
| 878 |
processed_images = []
|
| 879 |
+
total_images = len(selected_images)
|
| 880 |
+
|
| 881 |
+
for idx, img_url in enumerate(selected_images):
|
| 882 |
try:
|
| 883 |
response = requests.get(img_url, timeout=10)
|
| 884 |
response.raise_for_status()
|
|
|
|
| 886 |
img = img.convert('RGB')
|
| 887 |
img = img.resize((1920, 1080), Image.LANCZOS)
|
| 888 |
processed_images.append(img)
|
| 889 |
+
|
| 890 |
+
# Update progress (20% of total progress is for image processing)
|
| 891 |
+
if progress_callback:
|
| 892 |
+
progress = (idx + 1) / total_images * 20
|
| 893 |
+
progress_callback(progress)
|
| 894 |
+
|
| 895 |
except Exception as e:
|
| 896 |
self.logger.error(f"Error processing image {img_url}: {e}")
|
| 897 |
continue
|
|
|
|
| 901 |
|
| 902 |
# Generate voice-over
|
| 903 |
audio = self.generate_fallback_audio(script)
|
| 904 |
+
if progress_callback:
|
| 905 |
+
progress_callback(30) # 30% progress after audio generation
|
| 906 |
|
| 907 |
# Calculate frames
|
| 908 |
fps = 30
|
|
|
|
| 937 |
frame = self.apply_video_effects(img_array.copy(), current_effects)
|
| 938 |
frames.append(frame)
|
| 939 |
frame_count += 1
|
| 940 |
+
|
| 941 |
+
# Update progress (30% to 70% is for frame generation)
|
| 942 |
+
if progress_callback and frame_count % 30 == 0:
|
| 943 |
+
progress = 30 + (frame_count / total_frames * 40)
|
| 944 |
+
progress_callback(progress)
|
| 945 |
|
| 946 |
+
# Add transition to next image if enabled
|
| 947 |
+
if idx < len(processed_images) - 1 and video_effects.get('transition_style') != 'None':
|
| 948 |
next_img_array = np.array(processed_images[idx + 1])
|
| 949 |
transition_frames = 15
|
| 950 |
|
|
|
|
| 960 |
|
| 961 |
# Create video clip
|
| 962 |
clip = ImageSequenceClip(frames, fps=fps)
|
| 963 |
+
if progress_callback:
|
| 964 |
+
progress_callback(80) # 80% progress after creating clip
|
| 965 |
+
|
| 966 |
# Adjust audio duration
|
| 967 |
if audio.duration > clip.duration:
|
| 968 |
audio = audio.subclip(0, clip.duration)
|
|
|
|
| 971 |
|
| 972 |
# Combine video and audio
|
| 973 |
final_clip = clip.set_audio(audio)
|
| 974 |
+
if progress_callback:
|
| 975 |
+
progress_callback(90) # 90% progress after combining audio
|
| 976 |
|
| 977 |
# Ensure output directory exists
|
| 978 |
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
|
|
| 987 |
verbose=False,
|
| 988 |
logger=None
|
| 989 |
)
|
| 990 |
+
|
| 991 |
+
if progress_callback:
|
| 992 |
+
progress_callback(100) # 100% progress after writing file
|
| 993 |
|
| 994 |
return output_path
|
| 995 |
|
|
|
|
| 1007 |
audio.close()
|
| 1008 |
except Exception as e:
|
| 1009 |
self.logger.error(f"Cleanup error: {e}")
|
|
|
|
|
|
|
| 1010 |
|
| 1011 |
+
|
| 1012 |
+
|
| 1013 |
def generate_visual_assets(self, script: str, style: str) -> List[Dict]:
|
| 1014 |
"""Generate relevant visual assets based on script content"""
|
| 1015 |
try:
|