sam12345324 commited on
Commit
90475eb
·
verified ·
1 Parent(s): 5b69f87

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -33
app.py CHANGED
@@ -8,6 +8,7 @@ import logging
8
  import sys
9
  import traceback
10
  import socket
 
11
 
12
  # Set up logging to debug issues
13
  logging.basicConfig(level=logging.INFO, handlers=[logging.StreamHandler(sys.stdout)])
@@ -132,7 +133,7 @@ def trim_silence(audio_clip, threshold=0.005):
132
  logger.error(f"Error trimming silence: {str(e)}")
133
  return audio_clip
134
 
135
- def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, music_vol=0.5):
136
  """
137
  Merge multiple video clips and/or audio clips based on inputs provided.
138
  - If only video_files: Merge videos, retaining their original audio.
@@ -144,6 +145,7 @@ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, mu
144
  audio_files: List of audio file paths (optional)
145
  orig_vol: Volume for original video audio (0.0 to 1.0)
146
  music_vol: Volume for background audio (0.0 to 1.0)
 
147
  Returns:
148
  Path to the merged file (video or audio) or error message.
149
  """
@@ -168,13 +170,15 @@ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, mu
168
  logger.error(error_msg)
169
  return error_msg
170
 
171
- # Create a temporary output path
172
- temp_dir = tempfile.mkdtemp()
 
 
173
 
174
  # Case 1: Audio only
175
  if audio_count >= 2 and video_count == 0:
176
  output_filename = f"combined_audio_{audio_indices}.mp3"
177
- output_path = os.path.join(temp_dir, output_filename)
178
  logger.info("Merging audio files only")
179
 
180
  # Load, normalize, and trim audio clips
@@ -228,7 +232,7 @@ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, mu
228
  output_filename = f"combined_video_{video_indices}_with_audio_{audio_indices}.mp4"
229
  else:
230
  output_filename = f"combined_video_{video_indices}.mp4"
231
- output_path = os.path.join(temp_dir, output_filename)
232
 
233
  # Load and concatenate video clips
234
  video_clips = [VideoFileClip(video) for video in video_files]
@@ -319,43 +323,94 @@ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, mu
319
  error_msg = f"Error during merging: {str(e)}\n{traceback.format_exc()}"
320
  logger.error(error_msg)
321
  return error_msg
 
 
 
 
 
 
 
 
322
 
323
  # --- Gradio App Using Blocks ---
324
 
325
- def gradio_merge_files(all_files, orig_vol, music_vol):
326
  """
327
- Gradio endpoint to merge videos and/or audio.
328
  Args:
329
- all_files: List of file paths (mixed videos and audios, e.g., ['file1.mp4', 'audio1.mp3', 'file2.mp4'])
330
  orig_vol: Volume for original video audio (0.0 to 1.0)
331
  music_vol: Volume for background audio (0.0 to 1.0)
332
  Returns:
333
  Path to the merged file (video or audio) or error message
334
  """
335
- logger.info(f"Received {len(all_files) if all_files else 0} files: {all_files}")
336
-
337
- # Split files into videos and audios based on extensions
338
- video_files, audio_files = split_files_by_extension(all_files)
339
- logger.info(f"Identified {len(video_files)} video files: {video_files}")
340
- logger.info(f"Identified {len(audio_files)} audio files: {audio_files}")
341
-
342
- result = merge_videos_and_audios(
343
- video_files=video_files,
344
- audio_files=audio_files,
345
- orig_vol=orig_vol,
346
- music_vol=music_vol
347
- )
348
-
349
- if isinstance(result, str) and result.startswith("Error"):
350
- logger.error(result)
351
- return result, None
352
- else:
353
- logger.info(f"Merge successful. Output saved at: {result}")
354
- # Return appropriate output based on file type
355
- if result.endswith(".mp3"):
356
- return None, result # Audio output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  else:
358
- return result, None # Video output
 
 
 
 
 
 
 
 
 
 
 
 
359
 
360
  # --- Main Execution ---
361
 
@@ -386,10 +441,10 @@ if __name__ == "__main__":
386
  with gr.Blocks(title="Video and Audio Merger API") as app:
387
  gr.Markdown("## Video and Audio Merger API")
388
  gr.Markdown("Upload at least 2 files total (videos, audios, or a combination) to merge them.")
389
- gr.Markdown("For API usage, name videos as file1.mp4, file2.mp4, etc., and audios as audio1.mp3, audio2.mp3, etc. Files can be sent in a single list; the app will distinguish them by extension (.mp4 for videos, .mp3/.wav for audios).")
390
 
391
  with gr.Row():
392
- file_input = gr.File(label="Upload Files (Videos: .mp4, Audios: .mp3/.wav)", type="filepath", file_count="multiple")
393
 
394
  with gr.Row():
395
  orig_vol_input = gr.Slider(minimum=0.0, maximum=1.0, value=1.0, step=0.05, label="Original Video Audio Volume")
 
8
  import sys
9
  import traceback
10
  import socket
11
+ import shutil
12
 
13
  # Set up logging to debug issues
14
  logging.basicConfig(level=logging.INFO, handlers=[logging.StreamHandler(sys.stdout)])
 
133
  logger.error(f"Error trimming silence: {str(e)}")
134
  return audio_clip
135
 
136
+ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, music_vol=0.5, temp_dir=None):
137
  """
138
  Merge multiple video clips and/or audio clips based on inputs provided.
139
  - If only video_files: Merge videos, retaining their original audio.
 
145
  audio_files: List of audio file paths (optional)
146
  orig_vol: Volume for original video audio (0.0 to 1.0)
147
  music_vol: Volume for background audio (0.0 to 1.0)
148
+ temp_dir: Temporary directory to clean up (optional)
149
  Returns:
150
  Path to the merged file (video or audio) or error message.
151
  """
 
170
  logger.error(error_msg)
171
  return error_msg
172
 
173
+ # Create a temporary output path (use provided temp_dir if available)
174
+ if temp_dir is None:
175
+ temp_dir = tempfile.mkdtemp()
176
+ output_dir = temp_dir
177
 
178
  # Case 1: Audio only
179
  if audio_count >= 2 and video_count == 0:
180
  output_filename = f"combined_audio_{audio_indices}.mp3"
181
+ output_path = os.path.join(output_dir, output_filename)
182
  logger.info("Merging audio files only")
183
 
184
  # Load, normalize, and trim audio clips
 
232
  output_filename = f"combined_video_{video_indices}_with_audio_{audio_indices}.mp4"
233
  else:
234
  output_filename = f"combined_video_{video_indices}.mp4"
235
+ output_path = os.path.join(output_dir, output_filename)
236
 
237
  # Load and concatenate video clips
238
  video_clips = [VideoFileClip(video) for video in video_files]
 
323
  error_msg = f"Error during merging: {str(e)}\n{traceback.format_exc()}"
324
  logger.error(error_msg)
325
  return error_msg
326
+ finally:
327
+ # Clean up temporary directory if it was created in this function
328
+ if temp_dir and os.path.exists(temp_dir):
329
+ try:
330
+ shutil.rmtree(temp_dir)
331
+ logger.info(f"Cleaned up temporary directory: {temp_dir}")
332
+ except Exception as e:
333
+ logger.warning(f"Failed to clean up temporary directory {temp_dir}: {str(e)}")
334
 
335
  # --- Gradio App Using Blocks ---
336
 
337
+ def gradio_merge_files(file_objects, orig_vol, music_vol):
338
  """
339
+ Gradio endpoint to merge videos and/or audio from binary file uploads.
340
  Args:
341
+ file_objects: List of file objects (binary uploads)
342
  orig_vol: Volume for original video audio (0.0 to 1.0)
343
  music_vol: Volume for background audio (0.0 to 1.0)
344
  Returns:
345
  Path to the merged file (video or audio) or error message
346
  """
347
+ try:
348
+ logger.info(f"Received {len(file_objects) if file_objects else 0} file objects")
349
+
350
+ if not file_objects or len(file_objects) < 2:
351
+ error_msg = "Error: Please upload at least 2 files."
352
+ logger.error(error_msg)
353
+ return error_msg, None
354
+
355
+ # Create a temporary directory to store uploaded files
356
+ temp_dir = tempfile.mkdtemp()
357
+ all_files = []
358
+
359
+ # Save each file object to the temporary directory
360
+ for file_obj in file_objects:
361
+ if file_obj is None:
362
+ logger.warning("Skipping None file object")
363
+ continue
364
+ # Get the original filename from the file object
365
+ original_filename = os.path.basename(file_obj.name)
366
+ # Ensure the filename matches expected patterns
367
+ if not re.match(r'file\d+\.mp4', original_filename, re.IGNORECASE) and \
368
+ not re.match(r'audio\d+\.(mp3|wav)', original_filename, re.IGNORECASE):
369
+ logger.warning(f"Filename {original_filename} does not match expected pattern; skipping")
370
+ continue
371
+ # Create a temporary file path
372
+ temp_file_path = os.path.join(temp_dir, original_filename)
373
+ # Copy the file data to the temporary location
374
+ with open(temp_file_path, 'wb') as temp_file:
375
+ shutil.copyfileobj(file_obj, temp_file)
376
+ all_files.append(temp_file_path)
377
+ logger.info(f"Saved uploaded file to {temp_file_path}")
378
+
379
+ if len(all_files) < 2:
380
+ error_msg = "Error: Fewer than 2 valid files after filtering."
381
+ logger.error(error_msg)
382
+ return error_msg, None
383
+
384
+ # Split files into videos and audios based on extensions
385
+ video_files, audio_files = split_files_by_extension(all_files)
386
+ logger.info(f"Identified {len(video_files)} video files: {video_files}")
387
+ logger.info(f"Identified {len(audio_files)} audio files: {audio_files}")
388
+
389
+ result = merge_videos_and_audios(
390
+ video_files=video_files,
391
+ audio_files=audio_files,
392
+ orig_vol=orig_vol,
393
+ music_vol=music_vol,
394
+ temp_dir=temp_dir
395
+ )
396
+
397
+ if isinstance(result, str) and result.startswith("Error"):
398
+ logger.error(result)
399
+ return result, None
400
  else:
401
+ logger.info(f"Merge successful. Output saved at: {result}")
402
+ # Return appropriate output based on file type
403
+ if result.endswith(".mp3"):
404
+ return None, result # Audio output
405
+ else:
406
+ return result, None # Video output
407
+ except Exception as e:
408
+ error_msg = f"Error processing files: {str(e)}\n{traceback.format_exc()}"
409
+ logger.error(error_msg)
410
+ return error_msg, None
411
+ finally:
412
+ # Cleanup is handled in merge_videos_and_audios
413
+ pass
414
 
415
  # --- Main Execution ---
416
 
 
441
  with gr.Blocks(title="Video and Audio Merger API") as app:
442
  gr.Markdown("## Video and Audio Merger API")
443
  gr.Markdown("Upload at least 2 files total (videos, audios, or a combination) to merge them.")
444
+ gr.Markdown("For API usage, send binary files via multipart/form-data. Name videos as file1.mp4, file2.mp4, etc., and audios as audio1.mp3, audio2.mp3, etc.")
445
 
446
  with gr.Row():
447
+ file_input = gr.File(label="Upload Files (Videos: .mp4, Audios: .mp3/.wav)", type="file", file_count="multiple")
448
 
449
  with gr.Row():
450
  orig_vol_input = gr.Slider(minimum=0.0, maximum=1.0, value=1.0, step=0.05, label="Original Video Audio Volume")