jcnok commited on
Commit
ce2e6d9
·
verified ·
1 Parent(s): 107810f

Update app.py

Browse files

add endpoint para unir narração com fundo musical

Files changed (1) hide show
  1. app.py +74 -1
app.py CHANGED
@@ -247,7 +247,80 @@ async def get_duration_from_url(payload: Dict):
247
  # Este bloco é executado sempre, mesmo se ocorrerem erros
248
  if os.path.exists(temp_audio_path):
249
  os.remove(temp_audio_path)
250
- print(f"--- CLEANUP: Removed temporary probe file {temp_audio_path} ---")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
 
252
  # ==============================================================================
253
  # ENDPOINT "TUDO-EM-UM" OTIMIZADO (VERSÃO FINAL)
 
247
  # Este bloco é executado sempre, mesmo se ocorrerem erros
248
  if os.path.exists(temp_audio_path):
249
  os.remove(temp_audio_path)
250
+ print(f"--- CLEANUP: Removed temporary probe file {temp_audio_path} ---")
251
+
252
+ # ==============================================================================
253
+ # ENDPOINT PARA MIXAR NARRAÇÃO E MÚSICA DE FUNDO
254
+ # ==============================================================================
255
+
256
+ @app.post("/mix-audio-tracks/")
257
+ async def mix_audio_tracks(
258
+ narration_file: UploadFile = File(...),
259
+ music_file: UploadFile = File(...),
260
+ music_volume: float = Form(0.3)
261
+ ):
262
+ """
263
+ Mixes a narration track with a background music track.
264
+
265
+ It lowers the volume of the music track and mixes it with the narration,
266
+ ensuring the final track's duration matches the narration.
267
+
268
+ Args:
269
+ narration_file (UploadFile): The main narration audio file.
270
+ music_file (UploadFile): The background music audio file.
271
+ music_volume (float): The desired volume for the background music (0.0 to 1.0).
272
+
273
+ Returns:
274
+ FileResponse: The final mixed audio file.
275
+ """
276
+ # Validação de entrada
277
+ if not (0.0 <= music_volume <= 1.0):
278
+ raise HTTPException(status_code=400, detail="music_volume must be between 0.0 and 1.0")
279
+
280
+ # Setup do ambiente temporário
281
+ unique_id = str(uuid.uuid4())
282
+ temp_processing_dir = os.path.join(TEMP_DIR, unique_id)
283
+ os.makedirs(temp_processing_dir)
284
+
285
+ narration_path = os.path.join(temp_processing_dir, "narration.mp3")
286
+ music_path = os.path.join(temp_processing_dir, "music.mp3")
287
+ mixed_audio_path = os.path.join(temp_processing_dir, "mixed_audio.mp3")
288
+
289
+ try:
290
+ # Salva os arquivos recebidos
291
+ with open(narration_path, "wb") as buffer:
292
+ shutil.copyfileobj(narration_file.file, buffer)
293
+ with open(music_path, "wb") as buffer:
294
+ shutil.copyfileobj(music_file.file, buffer)
295
+
296
+ # Constrói o comando FFmpeg com o filtro 'amix'
297
+ # [0:a] -> primeiro input (narração)
298
+ # [1:a] -> segundo input (música)
299
+ # volume=... -> aplica o volume apenas no segundo input
300
+ # duration=first -> a mixagem termina quando o primeiro input (narração) acabar
301
+ command = (
302
+ f"ffmpeg -i {shlex.quote(narration_path)} -i {shlex.quote(music_path)} "
303
+ f"-filter_complex \"[1:a]volume={music_volume}[bg];[0:a][bg]amix=inputs=2:duration=first\" "
304
+ f"-y {shlex.quote(mixed_audio_path)}"
305
+ )
306
+
307
+ # Executa o comando
308
+ await run_subprocess(command)
309
+ print("SUCCESS: Narration and music mixed successfully.")
310
+
311
+ # Retorna o arquivo final e agenda a limpeza
312
+ cleanup_task = BackgroundTask(cleanup_directory, directory_path=temp_processing_dir)
313
+ return FileResponse(
314
+ path=mixed_audio_path,
315
+ filename="mixed_audio.mp3",
316
+ media_type="audio/mpeg",
317
+ background=cleanup_task
318
+ )
319
+
320
+ except Exception as e:
321
+ cleanup_directory(directory_path=temp_processing_dir)
322
+ raise HTTPException(status_code=500, detail=f"An internal server error occurred: {str(e)}")
323
+
324
 
325
  # ==============================================================================
326
  # ENDPOINT "TUDO-EM-UM" OTIMIZADO (VERSÃO FINAL)