Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -331,6 +331,7 @@ def run_simulation_pipeline(job: TranslationJob, supabase_url: str, supabase_ano
|
|
| 331 |
time.sleep(1)
|
| 332 |
|
| 333 |
# Target Lang Mock URL selector
|
|
|
|
| 334 |
mock_output_video = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"
|
| 335 |
|
| 336 |
print(f"[{video_id}] Simulation complete. Updating database to completed.")
|
|
@@ -370,7 +371,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 370 |
for chunk in res.iter_content(chunk_size=8192):
|
| 371 |
f.write(chunk)
|
| 372 |
|
| 373 |
-
#
|
| 374 |
print(f"[{video_id}] Standardizing downloaded video to MP4 format...")
|
| 375 |
cmd_standardize = [
|
| 376 |
"ffmpeg", "-y", "-i", downloaded_video_path,
|
|
@@ -437,6 +438,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 437 |
|
| 438 |
# 4. Synthesize voice cloning using ElevenLabs API
|
| 439 |
print(f"[{video_id}] Calling ElevenLabs TTS Voice Cloning with tone '{job.voice_tone}'...")
|
|
|
|
| 440 |
voice_id = "21m00Tcm4TlvDq8ikWAM"
|
| 441 |
elevenlabs_url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
|
| 442 |
|
|
@@ -445,6 +447,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 445 |
"Content-Type": "application/json"
|
| 446 |
}
|
| 447 |
|
|
|
|
| 448 |
stability = 0.5
|
| 449 |
similarity_boost = 0.75
|
| 450 |
if job.voice_tone == 'excited':
|
|
@@ -487,6 +490,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 487 |
"--outfile", f"../{lipsync_output_path}"
|
| 488 |
]
|
| 489 |
|
|
|
|
| 490 |
result = subprocess.run(cmd_lipsync, cwd="Wav2Lip", capture_output=True, text=True)
|
| 491 |
if result.returncode != 0:
|
| 492 |
print(f"Wav2Lip stdout: {result.stdout}")
|
|
@@ -508,6 +512,8 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 508 |
)
|
| 509 |
|
| 510 |
if job.has_lip_sync:
|
|
|
|
|
|
|
| 511 |
cmd_merge = [
|
| 512 |
"ffmpeg", "-y", "-i", video_src_for_subtitles,
|
| 513 |
"-vf", f"subtitles={srt_file_path}:force_style='{style_str}'",
|
|
@@ -516,6 +522,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 516 |
output_video_path
|
| 517 |
]
|
| 518 |
else:
|
|
|
|
| 519 |
cmd_merge = [
|
| 520 |
"ffmpeg", "-y", "-i", video_src_for_subtitles, "-i", synthesized_audio_path,
|
| 521 |
"-vf", f"subtitles={srt_file_path}:force_style='{style_str}'",
|
|
@@ -537,6 +544,7 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 537 |
]
|
| 538 |
subprocess.run(cmd_merge, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 539 |
|
|
|
|
| 540 |
base_url = supabase_url.rstrip("/")
|
| 541 |
if base_url.endswith("/rest/v1"):
|
| 542 |
base_url = base_url[:-8].rstrip("/")
|
|
@@ -552,11 +560,13 @@ def run_production_pipeline(job: TranslationJob, gemini_key: str, elevenlabs_key
|
|
| 552 |
"Content-Type": "video/mp4"
|
| 553 |
}
|
| 554 |
upload_res = requests.post(storage_upload_url, headers=upload_headers, data=out_file)
|
|
|
|
| 555 |
if upload_res.status_code == 400 and "AlreadyExists" in upload_res.text:
|
| 556 |
upload_res = requests.put(storage_upload_url, headers=upload_headers, data=out_file)
|
| 557 |
|
| 558 |
upload_res.raise_for_status()
|
| 559 |
|
|
|
|
| 560 |
public_video_url = f"{base_url}/storage/v1/object/public/videos/{video_id}_translated.mp4"
|
| 561 |
print(f"[{video_id}] Video successfully uploaded. Public URL: {public_video_url}")
|
| 562 |
|
|
@@ -583,5 +593,6 @@ def process_video(job: TranslationJob, background_tasks: BackgroundTasks):
|
|
| 583 |
|
| 584 |
if __name__ == "__main__":
|
| 585 |
import uvicorn
|
|
|
|
| 586 |
load_env_local()
|
| 587 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 331 |
time.sleep(1)
|
| 332 |
|
| 333 |
# Target Lang Mock URL selector
|
| 334 |
+
# To make it feel premium, we can point to a high quality public MP4 file
|
| 335 |
mock_output_video = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"
|
| 336 |
|
| 337 |
print(f"[{video_id}] Simulation complete. Updating database to completed.")
|
|
|
|
| 371 |
for chunk in res.iter_content(chunk_size=8192):
|
| 372 |
f.write(chunk)
|
| 373 |
|
| 374 |
+
# 1.5. Standardize video (H.264/AAC, 25 FPS, YUV420p) for OpenCV / Wav2Lip stability
|
| 375 |
print(f"[{video_id}] Standardizing downloaded video to MP4 format...")
|
| 376 |
cmd_standardize = [
|
| 377 |
"ffmpeg", "-y", "-i", downloaded_video_path,
|
|
|
|
| 438 |
|
| 439 |
# 4. Synthesize voice cloning using ElevenLabs API
|
| 440 |
print(f"[{video_id}] Calling ElevenLabs TTS Voice Cloning with tone '{job.voice_tone}'...")
|
| 441 |
+
# We can use the default standard voice (e.g. Rachel: 21m00Tcm4TlvDq8ikWAM)
|
| 442 |
voice_id = "21m00Tcm4TlvDq8ikWAM"
|
| 443 |
elevenlabs_url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
|
| 444 |
|
|
|
|
| 447 |
"Content-Type": "application/json"
|
| 448 |
}
|
| 449 |
|
| 450 |
+
# Optional stability configurations based on voice tone
|
| 451 |
stability = 0.5
|
| 452 |
similarity_boost = 0.75
|
| 453 |
if job.voice_tone == 'excited':
|
|
|
|
| 490 |
"--outfile", f"../{lipsync_output_path}"
|
| 491 |
]
|
| 492 |
|
| 493 |
+
# Execute in the Wav2Lip directory to resolve relative imports
|
| 494 |
result = subprocess.run(cmd_lipsync, cwd="Wav2Lip", capture_output=True, text=True)
|
| 495 |
if result.returncode != 0:
|
| 496 |
print(f"Wav2Lip stdout: {result.stdout}")
|
|
|
|
| 512 |
)
|
| 513 |
|
| 514 |
if job.has_lip_sync:
|
| 515 |
+
# Lip-synced video already has the synthesized audio merged inside it.
|
| 516 |
+
# So we map audio track from the same file (0:a)
|
| 517 |
cmd_merge = [
|
| 518 |
"ffmpeg", "-y", "-i", video_src_for_subtitles,
|
| 519 |
"-vf", f"subtitles={srt_file_path}:force_style='{style_str}'",
|
|
|
|
| 522 |
output_video_path
|
| 523 |
]
|
| 524 |
else:
|
| 525 |
+
# Map audio from input 1 (synthesized audio path)
|
| 526 |
cmd_merge = [
|
| 527 |
"ffmpeg", "-y", "-i", video_src_for_subtitles, "-i", synthesized_audio_path,
|
| 528 |
"-vf", f"subtitles={srt_file_path}:force_style='{style_str}'",
|
|
|
|
| 544 |
]
|
| 545 |
subprocess.run(cmd_merge, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
| 546 |
|
| 547 |
+
# Normalize Supabase base URL (remove trailing slash and rest/v1 path if present)
|
| 548 |
base_url = supabase_url.rstrip("/")
|
| 549 |
if base_url.endswith("/rest/v1"):
|
| 550 |
base_url = base_url[:-8].rstrip("/")
|
|
|
|
| 560 |
"Content-Type": "video/mp4"
|
| 561 |
}
|
| 562 |
upload_res = requests.post(storage_upload_url, headers=upload_headers, data=out_file)
|
| 563 |
+
# If exists, we can try to PUT (overwrite)
|
| 564 |
if upload_res.status_code == 400 and "AlreadyExists" in upload_res.text:
|
| 565 |
upload_res = requests.put(storage_upload_url, headers=upload_headers, data=out_file)
|
| 566 |
|
| 567 |
upload_res.raise_for_status()
|
| 568 |
|
| 569 |
+
# Get public url
|
| 570 |
public_video_url = f"{base_url}/storage/v1/object/public/videos/{video_id}_translated.mp4"
|
| 571 |
print(f"[{video_id}] Video successfully uploaded. Public URL: {public_video_url}")
|
| 572 |
|
|
|
|
| 593 |
|
| 594 |
if __name__ == "__main__":
|
| 595 |
import uvicorn
|
| 596 |
+
# Make sure we load local variables before starting
|
| 597 |
load_env_local()
|
| 598 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|