saq1b commited on
Commit
a1d44af
·
verified ·
1 Parent(s): 5f98112

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +97 -37
main.py CHANGED
@@ -5,6 +5,7 @@ import asyncio
5
  import aiohttp
6
  import tempfile
7
  import uuid
 
8
  import os
9
  import random
10
  import traceback
@@ -247,48 +248,107 @@ async def make_video(request: Request):
247
  # Generate a unique filename for the output
248
  output_filename = f"{uuid.uuid4()}.mp4"
249
  output_path = os.path.join(OUTPUT_DIR, output_filename)
 
 
250
 
251
  data = await request.json()
252
- image_urls = data.get("image_urls")
253
- audio_url = data.get("audio_url")
254
- duration = data.get("duration", 5) # Default duration of 5 seconds per image
255
-
256
- if not image_urls or not isinstance(image_urls, list) or not audio_url:
257
- raise HTTPException(status_code=400, detail="Invalid image_urls or audio_url in request.")
258
-
259
- # Download audio file
260
- audio_file = await download_file(audio_url, ".mp3")
261
-
262
- # Download image files and create a temporary file with the list of input files
263
- image_files = []
264
- concat_list_path = os.path.join(OUTPUT_DIR, "concat_list.txt")
265
- with open(concat_list_path, "w") as f:
266
- for i, url in enumerate(image_urls):
267
- image_file = await download_file(url, f"_{i}.jpg")
268
- image_files.append(image_file)
269
- f.write(f"file '{image_file}'\nduration {duration}\n") # Set duration for each image
270
-
271
- # Add the last image again to ensure the audio doesn't cut off abruptly
272
- f.write(f"file '{image_files[-1]}'\n")
273
-
274
- # Run ffmpeg command to create video from images and add audio
275
- ffmpeg_cmd = f"ffmpeg -f concat -safe 0 -i {concat_list_path} -i {audio_file} -c:v libx264 -pix_fmt yuv420p -c:a aac -shortest {output_path}"
276
- process = await asyncio.create_subprocess_shell(
277
- ffmpeg_cmd,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  stdout=asyncio.subprocess.PIPE,
279
  stderr=asyncio.subprocess.PIPE
280
  )
281
- stdout, stderr = await process.communicate()
282
-
283
- if process.returncode != 0:
284
- print(f"FFmpeg error: {stderr.decode()}")
285
- raise HTTPException(status_code=500, detail=f"FFmpeg failed: {stderr.decode()}")
286
-
287
- # Clean up temporary files
288
- for file in image_files:
289
- os.remove(file)
290
- os.remove(audio_file)
291
- os.remove(concat_list_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
 
293
  # Return the URL path to the output file
294
  return f"/output/{output_filename}"
 
5
  import aiohttp
6
  import tempfile
7
  import uuid
8
+ import shutil
9
  import os
10
  import random
11
  import traceback
 
248
  # Generate a unique filename for the output
249
  output_filename = f"{uuid.uuid4()}.mp4"
250
  output_path = os.path.join(OUTPUT_DIR, output_filename)
251
+ temp_dir = os.path.join(tempfile.gettempdir(), generate_hash())
252
+ os.makedirs(temp_dir, exist_ok=True)
253
 
254
  data = await request.json()
255
+ assets = data.get("assets", {})
256
+ clips = assets.get("clips", [])
257
+ music_url = assets.get("music_url")
258
+ volume_adjustment = data.get("volume_adjustment", 1.0) # Default to normal volume if not specified
259
+
260
+ if not clips or not isinstance(clips, list):
261
+ raise HTTPException(status_code=400, detail="Invalid clips in request.")
262
+
263
+ # Create a list to hold clip video files that we'll concatenate later
264
+ clip_videos = []
265
+ segment_list_path = os.path.join(temp_dir, "segment_list.txt")
266
+
267
+ with open(segment_list_path, "w") as segment_file:
268
+ # Process each clip: combine image with its audio
269
+ for i, clip in enumerate(clips):
270
+ image_url = clip.get("image_url")
271
+ audio_url = clip.get("audio_url")
272
+
273
+ if not image_url or not audio_url:
274
+ raise HTTPException(status_code=400, detail=f"Missing image_url or audio_url in clip {i}")
275
+
276
+ # Download files
277
+ image_file = await download_file(image_url, ".jpg")
278
+ audio_file = await download_file(audio_url, ".mp3")
279
+
280
+ # Create segment video
281
+ segment_output = os.path.join(temp_dir, f"segment_{i}.mp4")
282
+
283
+ # Run ffmpeg command to create video segment
284
+ segment_cmd = f'ffmpeg -loop 1 -i {image_file} -i {audio_file} -c:v libx264 -tune stillimage -c:a aac -b:a 192k -shortest -pix_fmt yuv420p {segment_output}'
285
+ proc = await asyncio.create_subprocess_shell(
286
+ segment_cmd,
287
+ stdout=asyncio.subprocess.PIPE,
288
+ stderr=asyncio.subprocess.PIPE
289
+ )
290
+ _, stderr = await proc.communicate()
291
+
292
+ if proc.returncode != 0:
293
+ print(f"FFmpeg error for segment {i}: {stderr.decode()}")
294
+ raise HTTPException(status_code=500, detail=f"FFmpeg failed for segment {i}: {stderr.decode()}")
295
+
296
+ # Add to list for concatenation
297
+ clip_videos.append(segment_output)
298
+ segment_file.write(f"file '{segment_output}'\n")
299
+
300
+ # Clean up individual files
301
+ os.remove(image_file)
302
+ os.remove(audio_file)
303
+
304
+ # Concatenate all segment videos
305
+ concat_output = os.path.join(temp_dir, "concat_output.mp4")
306
+ concat_cmd = f'ffmpeg -f concat -safe 0 -i {segment_list_path} -c copy {concat_output}'
307
+
308
+ proc = await asyncio.create_subprocess_shell(
309
+ concat_cmd,
310
  stdout=asyncio.subprocess.PIPE,
311
  stderr=asyncio.subprocess.PIPE
312
  )
313
+ _, stderr = await proc.communicate()
314
+
315
+ if proc.returncode != 0:
316
+ print(f"FFmpeg concat error: {stderr.decode()}")
317
+ raise HTTPException(status_code=500, detail=f"FFmpeg concat failed: {stderr.decode()}")
318
+
319
+ # If there's a music URL, download it and mix with the video
320
+ if music_url:
321
+ music_file = await download_file(music_url, ".wav")
322
+
323
+ # Final command to mix music with video at specified volume
324
+ final_cmd = (
325
+ f'ffmpeg -i {concat_output} -i {music_file} -filter_complex '
326
+ f'"[1:a]volume={volume_adjustment}[music];[0:a][music]amix=inputs=2:duration=longest" '
327
+ f'-c:v copy {output_path}'
328
+ )
329
+
330
+ proc = await asyncio.create_subprocess_shell(
331
+ final_cmd,
332
+ stdout=asyncio.subprocess.PIPE,
333
+ stderr=asyncio.subprocess.PIPE
334
+ )
335
+ _, stderr = await proc.communicate()
336
+
337
+ if proc.returncode != 0:
338
+ print(f"FFmpeg final mix error: {stderr.decode()}")
339
+ raise HTTPException(status_code=500, detail=f"FFmpeg music mixing failed: {stderr.decode()}")
340
+
341
+ os.remove(music_file)
342
+ else:
343
+ # If no music, just copy the concatenated output
344
+ shutil.copy(concat_output, output_path)
345
+
346
+ # Clean up temporary files and directory
347
+ for video_file in clip_videos:
348
+ os.remove(video_file)
349
+ os.remove(segment_list_path)
350
+ os.remove(concat_output)
351
+ os.rmdir(temp_dir)
352
 
353
  # Return the URL path to the output file
354
  return f"/output/{output_filename}"