saq1b commited on
Commit
113c6a4
·
1 Parent(s): 6586de4

Refactor video processing functions: remove unused code and streamline make_video endpoint

Browse files
Files changed (1) hide show
  1. main.py +0 -170
main.py CHANGED
@@ -1,13 +1,11 @@
1
  from fastapi import FastAPI, HTTPException
2
  from fastapi.staticfiles import StaticFiles
3
- from fastapi.responses import FileResponse
4
  from pydantic import BaseModel, HttpUrl
5
  from typing import List
6
  import os
7
  import asyncio
8
  import uuid
9
  import aiohttp
10
- import traceback
11
  import re
12
  from urllib.parse import urlparse
13
  import shutil
@@ -27,10 +25,6 @@ class SlideshowRequest(BaseModel):
27
  duration: int
28
  zoom: bool = False
29
 
30
- class MakeVideoInput(BaseModel):
31
- assets: dict
32
- volume_adjustment: float = 1.0
33
-
34
  def extract_google_drive_id(url):
35
  """Extract file ID from a Google Drive URL"""
36
  pattern = r'(?:/file/d/|id=|/open\?id=)([^/&]+)'
@@ -203,170 +197,6 @@ async def make_slideshow(request: SlideshowRequest):
203
  shutil.rmtree(request_dir)
204
  raise HTTPException(status_code=500, detail=f"Error: {str(e)}")
205
 
206
-
207
- async def download_file_with_extension(url, extension, output_dir):
208
- """Download file and save with the provided extension"""
209
- file_id = str(uuid.uuid4())
210
- file_path = os.path.join(output_dir, f"{file_id}{extension}")
211
- success = await download_file(url, file_path)
212
- if not success:
213
- raise HTTPException(status_code=400, detail=f"Failed to download file from {url}")
214
- return file_path
215
-
216
- async def add_audio_to_image(image_path, audio_path, output_dir):
217
- """Create a video from an image and audio file"""
218
- output_id = str(uuid.uuid4())
219
- output_path = os.path.join(output_dir, f"{output_id}.mp4")
220
-
221
- cmd = [
222
- "ffmpeg", "-y",
223
- "-loop", "1",
224
- "-i", image_path,
225
- "-i", audio_path,
226
- "-c:v", "libx264",
227
- "-tune", "stillimage",
228
- "-c:a", "aac",
229
- "-pix_fmt", "yuv420p",
230
- "-shortest",
231
- output_path
232
- ]
233
-
234
- process = await asyncio.create_subprocess_exec(
235
- *cmd,
236
- stdout=asyncio.subprocess.PIPE,
237
- stderr=asyncio.subprocess.PIPE
238
- )
239
- stdout, stderr = await process.communicate()
240
-
241
- if process.returncode != 0:
242
- print(f"FFmpeg error: {stderr.decode()}")
243
- raise HTTPException(status_code=500, detail="Failed to add audio to image")
244
-
245
- return {"output_path": output_path}
246
-
247
- async def concatenate_videos(clip_paths, output_dir):
248
- """Concatenate multiple video clips"""
249
- output_id = str(uuid.uuid4())
250
- output_path = os.path.join(output_dir, f"{output_id}.mp4")
251
-
252
- # Create temporary file list for ffmpeg concat
253
- concat_file = os.path.join(output_dir, "concat_list.txt")
254
-
255
- async with aiofiles.open(concat_file, "w") as f:
256
- for clip in clip_paths:
257
- await f.write(f"file '{clip}'\n")
258
-
259
- cmd = [
260
- "ffmpeg", "-y",
261
- "-f", "concat",
262
- "-safe", "0",
263
- "-i", concat_file,
264
- "-c", "copy",
265
- output_path
266
- ]
267
-
268
- process = await asyncio.create_subprocess_exec(
269
- *cmd,
270
- stdout=asyncio.subprocess.PIPE,
271
- stderr=asyncio.subprocess.PIPE
272
- )
273
- stdout, stderr = await process.communicate()
274
-
275
- # Clean up
276
- if os.path.exists(concat_file):
277
- os.remove(concat_file)
278
-
279
- if process.returncode != 0:
280
- print(f"FFmpeg error: {stderr.decode()}")
281
- raise HTTPException(status_code=500, detail="Failed to concatenate videos")
282
-
283
- return {"output_path": output_path}
284
-
285
- async def add_audio_to_video(video_path, audio_path, volume_adjustment, output_dir):
286
- """Add background music to video with volume adjustment"""
287
- output_filename = f"final_video_{str(uuid.uuid4())}.mp4"
288
- output_path = os.path.join(output_dir, output_filename)
289
-
290
- cmd = [
291
- "ffmpeg", "-y",
292
- "-i", video_path,
293
- "-i", audio_path,
294
- "-filter_complex", f"[1:a]volume={volume_adjustment}[a1];[0:a][a1]amix=inputs=2:duration=longest[a]",
295
- "-map", "0:v",
296
- "-map", "[a]",
297
- "-c:v", "copy",
298
- "-c:a", "aac",
299
- "-b:a", "192k",
300
- output_path
301
- ]
302
-
303
- process = await asyncio.create_subprocess_exec(
304
- *cmd,
305
- stdout=asyncio.subprocess.PIPE,
306
- stderr=asyncio.subprocess.PIPE
307
- )
308
- stdout, stderr = await process.communicate()
309
-
310
- if process.returncode != 0:
311
- print(f"FFmpeg error: {stderr.decode()}")
312
- raise HTTPException(status_code=500, detail="Failed to add audio to video")
313
-
314
- return {"output_path": output_path, "output_filename": output_filename}
315
-
316
- @app.post("/make_video")
317
- async def make_video(input_data: MakeVideoInput):
318
- try:
319
- # Create unique directory for this request
320
- request_id = str(uuid.uuid4())
321
- request_dir = os.path.join("staticfiles", request_id)
322
- os.makedirs(request_dir, exist_ok=True)
323
-
324
- assets = input_data.assets
325
- volume_adjustment = input_data.volume_adjustment
326
-
327
- # Download music
328
- music_url = assets["music_url"]
329
- music_path = await download_file_with_extension(music_url, ".mp3", request_dir)
330
-
331
- # Process each clip
332
- clips = []
333
- for clip_data in assets["clips"]:
334
- image_url = clip_data["image_url"]
335
- audio_url = clip_data["audio_url"]
336
-
337
- image_path = await download_file_with_extension(image_url, ".png", request_dir)
338
- audio_path = await download_file_with_extension(audio_url, ".mp3", request_dir)
339
-
340
- add_audio_to_image_result = await add_audio_to_image(image_path, audio_path, request_dir)
341
-
342
- clips.append(add_audio_to_image_result["output_path"])
343
-
344
- # Concatenate all the clips
345
- concatenate_videos_result = await concatenate_videos(clips, request_dir)
346
- concatenate_videos_output_path = concatenate_videos_result["output_path"]
347
-
348
- # Add background music
349
- add_audio_to_video_result = await add_audio_to_video(
350
- concatenate_videos_output_path,
351
- music_path,
352
- volume_adjustment,
353
- request_dir
354
- )
355
-
356
- # Return the final video
357
- return FileResponse(
358
- add_audio_to_video_result["output_path"],
359
- media_type="video/mp4",
360
- filename=add_audio_to_video_result["output_filename"]
361
- )
362
- except Exception as e:
363
- # Clean up on error
364
- if os.path.exists(request_dir):
365
- shutil.rmtree(request_dir)
366
- print(f"An error occurred: {str(e)}")
367
- print(traceback.format_exc())
368
- raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
369
-
370
  if __name__ == "__main__":
371
  import uvicorn
372
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
  from fastapi import FastAPI, HTTPException
2
  from fastapi.staticfiles import StaticFiles
 
3
  from pydantic import BaseModel, HttpUrl
4
  from typing import List
5
  import os
6
  import asyncio
7
  import uuid
8
  import aiohttp
 
9
  import re
10
  from urllib.parse import urlparse
11
  import shutil
 
25
  duration: int
26
  zoom: bool = False
27
 
 
 
 
 
28
  def extract_google_drive_id(url):
29
  """Extract file ID from a Google Drive URL"""
30
  pattern = r'(?:/file/d/|id=|/open\?id=)([^/&]+)'
 
197
  shutil.rmtree(request_dir)
198
  raise HTTPException(status_code=500, detail=f"Error: {str(e)}")
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  if __name__ == "__main__":
201
  import uvicorn
202
  uvicorn.run(app, host="0.0.0.0", port=7860)