VoiceClips commited on
Commit
ae2e0e7
·
verified ·
1 Parent(s): 1b3bdb6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -13
app.py CHANGED
@@ -7,6 +7,7 @@ import subprocess
7
  import base64
8
  import json
9
  import shutil
 
10
 
11
  app = FastAPI(title="VoiceClips heavy video processor (Wav2Lip + FFmpeg)")
12
 
@@ -20,9 +21,10 @@ class TranslationJob(BaseModel):
20
  caption_style: str
21
  resolution: str
22
  user_token: str
23
- custom_font: str = None
24
- custom_size: int = None
25
- custom_color: str = None
 
26
 
27
  def load_env_local():
28
  """Load environment variables from local .env.local file if it exists."""
@@ -298,7 +300,15 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
298
 
299
  print(f"[{video_id}] Running in PRODUCTION MODE...")
300
 
301
- input_video_path = f"temp_{video_id}_input.mp4"
 
 
 
 
 
 
 
 
302
  extracted_audio_path = f"temp_{video_id}_audio.mp3"
303
  synthesized_audio_path = f"temp_{video_id}_tts.mp3"
304
  srt_file_path = f"temp_{video_id}.srt"
@@ -306,15 +316,26 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
306
  lipsync_output_path = f"temp_{video_id}_lipsync.mp4"
307
 
308
  try:
309
- # 1. Download original video
310
- print(f"[{video_id}] Downloading original video...")
311
  res = requests.get(job.original_video_url, stream=True)
312
  res.raise_for_status()
313
- with open(input_video_path, "wb") as f:
314
  for chunk in res.iter_content(chunk_size=8192):
315
  f.write(chunk)
316
 
317
- # 2. Extract audio
 
 
 
 
 
 
 
 
 
 
 
318
  print(f"[{video_id}] Extracting audio using FFmpeg...")
319
  cmd_extract = [
320
  "ffmpeg", "-y", "-i", input_video_path,
@@ -323,7 +344,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
323
  ]
324
  subprocess.run(cmd_extract, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
325
 
326
- # 3. Gemini Transcription & Translation
327
  print(f"[{video_id}] Calling Gemini 2.0 Flash...")
328
  with open(extracted_audio_path, "rb") as audio_file:
329
  audio_data = base64.b64encode(audio_file.read()).decode("utf-8")
@@ -359,7 +380,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
359
  else:
360
  translated_text = gemini_output
361
 
362
- # 4. ElevenLabs Voice Cloning Synthesis
363
  print(f"[{video_id}] Calling ElevenLabs TTS Voice Cloning...")
364
  voice_id = "21m00Tcm4TlvDq8ikWAM"
365
  elevenlabs_url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
@@ -393,7 +414,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
393
  with open(synthesized_audio_path, "wb") as f:
394
  f.write(tts_res.content)
395
 
396
- # 5. Lip-Sync & FFmpeg Merge
397
  if job.has_lip_sync:
398
  setup_success = setup_wav2lip()
399
  if not setup_success:
@@ -451,7 +472,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
451
  ]
452
  subprocess.run(cmd_merge, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
453
 
454
- # 6. Upload output to Supabase Storage
455
  print(f"[{video_id}] Uploading output to Supabase Storage...")
456
  storage_upload_url = f"{supabase_url}/storage/v1/object/videos/{video_id}_translated.mp4"
457
 
@@ -475,7 +496,8 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
475
  update_db_status(video_id, user_token, "failed", error_message=f"Hata: {str(e)}")
476
 
477
  finally:
478
- for temp_file in [input_video_path, extracted_audio_path, synthesized_audio_path, srt_file_path, output_video_path, lipsync_output_path]:
 
479
  if os.path.exists(temp_file):
480
  try:
481
  os.remove(temp_file)
 
7
  import base64
8
  import json
9
  import shutil
10
+ from typing import Optional
11
 
12
  app = FastAPI(title="VoiceClips heavy video processor (Wav2Lip + FFmpeg)")
13
 
 
21
  caption_style: str
22
  resolution: str
23
  user_token: str
24
+ # Null (boş) değerlerin 422 hatası vermemesi için Optional yapıldı
25
+ custom_font: Optional[str] = None
26
+ custom_size: Optional[int] = None
27
+ custom_color: Optional[str] = None
28
 
29
  def load_env_local():
30
  """Load environment variables from local .env.local file if it exists."""
 
300
 
301
  print(f"[{video_id}] Running in PRODUCTION MODE...")
302
 
303
+ # Gelen URL'den uzantıyı tespit edip kaydediyoruz (.mp4, .mov, .webm vb.)
304
+ url_without_params = job.original_video_url.split('?')[0]
305
+ file_ext = url_without_params.split('.')[-1].lower() if '.' in url_without_params else 'mp4'
306
+ if file_ext not in ['mp4', 'mov', 'webm']:
307
+ file_ext = 'mp4'
308
+
309
+ # Geçici çalışma dosyaları
310
+ downloaded_video_path = f"temp_{video_id}_downloaded.{file_ext}"
311
+ input_video_path = f"temp_{video_id}_input.mp4" # Standartlaştırılmış MP4 dosyası
312
  extracted_audio_path = f"temp_{video_id}_audio.mp3"
313
  synthesized_audio_path = f"temp_{video_id}_tts.mp3"
314
  srt_file_path = f"temp_{video_id}.srt"
 
316
  lipsync_output_path = f"temp_{video_id}_lipsync.mp4"
317
 
318
  try:
319
+ # 1. Orijinal dosyayı indir
320
+ print(f"[{video_id}] Downloading original video from: {job.original_video_url}")
321
  res = requests.get(job.original_video_url, stream=True)
322
  res.raise_for_status()
323
+ with open(downloaded_video_path, "wb") as f:
324
  for chunk in res.iter_content(chunk_size=8192):
325
  f.write(chunk)
326
 
327
+ # 1.5. Video standardizasyon (H.264/AAC, 25 FPS, YUV420p)
328
+ # Webm ve Mov formatlarını OpenCV ve Wav2Lip ile %100 uyumlu hale getirmek için standart MP4 formatına dönüştürüyoruz.
329
+ print(f"[{video_id}] Standardizing downloaded video to MP4 format...")
330
+ cmd_standardize = [
331
+ "ffmpeg", "-y", "-i", downloaded_video_path,
332
+ "-c:v", "libx264", "-pix_fmt", "yuv420p", "-r", "25",
333
+ "-c:a", "aac", "-ar", "16000", "-ac", "1",
334
+ input_video_path
335
+ ]
336
+ subprocess.run(cmd_standardize, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
337
+
338
+ # 2. Ses Ayıklama
339
  print(f"[{video_id}] Extracting audio using FFmpeg...")
340
  cmd_extract = [
341
  "ffmpeg", "-y", "-i", input_video_path,
 
344
  ]
345
  subprocess.run(cmd_extract, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
346
 
347
+ # 3. Gemini 2.0 ile Transkript & Çeviri
348
  print(f"[{video_id}] Calling Gemini 2.0 Flash...")
349
  with open(extracted_audio_path, "rb") as audio_file:
350
  audio_data = base64.b64encode(audio_file.read()).decode("utf-8")
 
380
  else:
381
  translated_text = gemini_output
382
 
383
+ # 4. ElevenLabs Yapay Zeka Ses Sentezleme
384
  print(f"[{video_id}] Calling ElevenLabs TTS Voice Cloning...")
385
  voice_id = "21m00Tcm4TlvDq8ikWAM"
386
  elevenlabs_url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
 
414
  with open(synthesized_audio_path, "wb") as f:
415
  f.write(tts_res.content)
416
 
417
+ # 5. Lip-Sync & Video Birleştirme
418
  if job.has_lip_sync:
419
  setup_success = setup_wav2lip()
420
  if not setup_success:
 
472
  ]
473
  subprocess.run(cmd_merge, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
474
 
475
+ # 6. Sonuç Videosunu Supabase Storage'a Yükle
476
  print(f"[{video_id}] Uploading output to Supabase Storage...")
477
  storage_upload_url = f"{supabase_url}/storage/v1/object/videos/{video_id}_translated.mp4"
478
 
 
496
  update_db_status(video_id, user_token, "failed", error_message=f"Hata: {str(e)}")
497
 
498
  finally:
499
+ # Geçici dosyaların temizlenmesi
500
+ for temp_file in [downloaded_video_path, input_video_path, extracted_audio_path, synthesized_audio_path, srt_file_path, output_video_path, lipsync_output_path]:
501
  if os.path.exists(temp_file):
502
  try:
503
  os.remove(temp_file)