lipsync / app.py
Oviya
add app.py
ad8f099
import os
import sys
import types
import uuid
# --------------------------------------------------------------------
# Fix environment issues
# --------------------------------------------------------------------
# Fix OMP_NUM_THREADS error
os.environ["OMP_NUM_THREADS"] = "1"
# Dummy google.colab for wyn_wav2lip
google = types.ModuleType("google")
colab = types.ModuleType("google.colab")
class _DummyDrive:
def mount(self, *args, **kwargs):
print("google.colab.drive.mount() called (dummy).")
colab.drive = _DummyDrive()
google.colab = colab
sys.modules["google"] = google
sys.modules["google.colab"] = colab
# --------------------------------------------------------------------
# Imports
# --------------------------------------------------------------------
import gradio as gr
from wyn_wav2lip.wav2lip import Wav2Lip
import soundfile as sf
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
MEDIA_DIR = os.path.join(BASE_DIR, "media")
os.makedirs(MEDIA_DIR, exist_ok=True)
print("Initialising Wav2Lip...")
wav2lip = Wav2Lip()
wav2lip.setup()
print("Wav2Lip ready.")
def run_wav2lip(image_path: str, audio_path: str) -> str:
"""Run Wav2Lip and return absolute path to created video file."""
existing_mp4 = {
f for f in os.listdir(MEDIA_DIR)
if f.lower().endswith(".mp4")
}
old_cwd = os.getcwd()
os.chdir(MEDIA_DIR)
try:
# Wav2Lip expects filenames relative to current working dir
wav2lip.run(
video_file=os.path.basename(image_path),
vocal_file=os.path.basename(audio_path),
)
finally:
os.chdir(old_cwd)
new_mp4 = [
f for f in os.listdir(MEDIA_DIR)
if f.lower().endswith(".mp4") and f not in existing_mp4
]
if not new_mp4:
mp4_candidates = [
os.path.join(MEDIA_DIR, f)
for f in os.listdir(MEDIA_DIR)
if f.lower().endswith(".mp4")
]
if not mp4_candidates:
raise RuntimeError("No MP4 created by Wav2Lip.")
return max(mp4_candidates, key=os.path.getmtime)
return os.path.join(MEDIA_DIR, new_mp4[0])
def lipsync_func(image, audio):
"""
image: PIL image (from gr.Image)
audio: (sr, data) tuple (from gr.Audio(type="numpy"))
"""
if image is None or audio is None:
return None
# Save image
img_id = uuid.uuid4().hex
image_path = os.path.join(MEDIA_DIR, f"{img_id}.png")
image.save(image_path)
# Save audio
aud_id = uuid.uuid4().hex
audio_path = os.path.join(MEDIA_DIR, f"{aud_id}.wav")
sr, data = audio
sf.write(audio_path, data, sr)
# Run Wav2Lip
video_path = run_wav2lip(image_path, audio_path)
return video_path
demo = gr.Interface(
fn=lipsync_func,
inputs=[
gr.Image(type="pil", label="Teacher image"),
gr.Audio(type="numpy", label="Teacher audio (.wav)")
],
outputs=gr.Video(label="Lip-synced video"),
title="Wav2Lip Lipsync Service",
description="Upload a static teacher image and a WAV audio. The model will generate a talking video."
)
if __name__ == "__main__":
demo.launch()