# Wav2Lip

Sincroniza los labios con cualquier audio con Wav2Lip.

{% hint style="success" %}
Todos los ejemplos se pueden ejecutar en servidores GPU alquilados a través de [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Alquilar en CLORE.AI

1. Visita [CLORE.AI Marketplace](https://clore.ai/marketplace)
2. Filtrar por tipo de GPU, VRAM y precio
3. Elegir **Bajo demanda** (tarifa fija) o **Spot** (precio de puja)
4. Configura tu pedido:
   * Selecciona imagen Docker
   * Establece puertos (TCP para SSH, HTTP para interfaces web)
   * Agrega variables de entorno si es necesario
   * Introduce el comando de inicio
5. Selecciona pago: **CLORE**, **BTC**, o **USDT/USDC**
6. Crea el pedido y espera el despliegue

### Accede a tu servidor

* Encuentra los detalles de conexión en **Mis Pedidos**
* Interfaces web: Usa la URL del puerto HTTP
* SSH: `ssh -p <port> root@<proxy-address>`

## ¿Qué es Wav2Lip?

Wav2Lip ofrece:

* Sincronización labial precisa para cualquier rostro
* Funciona con cualquier audio
* Entrada de video o imagen
* Capaz de tiempo real

## Requisitos

| Modo         | VRAM | Recomendado |
| ------------ | ---- | ----------- |
| Básico       | 4GB  | RTX 3060    |
| Alta calidad | 6GB  | RTX 3080    |
| HD           | 8GB  | RTX 4080    |

## Despliegue rápido

**Imagen Docker:**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel
```

**Puertos:**

```
22/tcp
7860/http
```

**Comando:**

```bash
cd /workspace && \
git clone https://github.com/Rudrabha/Wav2Lip.git && \
cd Wav2Lip && \
pip install -r requirements.txt && \
wget "https://huggingface.co/spaces/wav2lip/wav2lip/resolve/main/checkpoints/wav2lip_gan.pth" -P checkpoints/ && \
python app.py
```

## Accediendo a tu servicio

Después del despliegue, encuentra tu `http_pub` URL en **Mis Pedidos**:

1. Ir a **Mis Pedidos** página
2. Haz clic en tu pedido
3. Encuentra la `http_pub` URL (por ejemplo, `abc123.clorecloud.net`)

Usa `https://TU_HTTP_PUB_URL` en lugar de `localhost` en los ejemplos abajo.

## Instalación

```bash
git clone https://github.com/Rudrabha/Wav2Lip.git
cd Wav2Lip
pip install -r requirements.txt

# Descargar modelos preentrenados
mkdir -p checkpoints
wget "https://huggingface.co/spaces/wav2lip/wav2lip/resolve/main/checkpoints/wav2lip.pth" -P checkpoints/
wget "https://huggingface.co/spaces/wav2lip/wav2lip/resolve/main/checkpoints/wav2lip_gan.pth" -P checkpoints/
```

## Uso básico

### Línea de comandos

```bash
python inference.py \
    --checkpoint_path checkpoints/wav2lip_gan.pth \
    --face input_video.mp4 \
    --audio audio.wav \
    --outfile output.mp4
```

### Con entrada de imagen

```bash
python inference.py \
    --checkpoint_path checkpoints/wav2lip_gan.pth \
    --face face_image.jpg \
    --audio speech.wav \
    --outfile talking.mp4
```

## API de Python

```python
import subprocess

def wav2lip_sync(face_path, audio_path, output_path, checkpoint="checkpoints/wav2lip_gan.pth"):
    cmd = [
        "python", "inference.py",
        "--checkpoint_path", checkpoint,
        "--face", face_path,
        "--audio", audio_path,
        "--outfile", output_path
    ]
    subprocess.run(cmd, check=True)
    return output_path

# Uso
result = wav2lip_sync(
    face_path="video.mp4",
    audio_path="new_audio.wav",
    output_path="synced.mp4"
)
```

## Opciones de calidad

### Calidad estándar (más rápido)

```bash
python inference.py \
    --checkpoint_path checkpoints/wav2lip.pth \
    --face input.mp4 \
    --audio audio.wav \
    --outfile output.mp4
```

### Alta calidad (GAN)

```bash
python inference.py \
    --checkpoint_path checkpoints/wav2lip_gan.pth \
    --face input.mp4 \
    --audio audio.wav \
    --outfile output.mp4 \
    --pads 0 10 0 0 \
    --resize_factor 1
```

## Parámetros

```bash
python inference.py \
    --checkpoint_path checkpoints/wav2lip_gan.pth \
    --face video.mp4 \
    --audio audio.wav \
    --outfile result.mp4 \
    --pads 0 10 0 0 \      # Relleno: arriba derecha abajo izquierda
    --resize_factor 1 \    # Factor de reducción
    --crop "0 -1 0 -1" \   # Región de recorte
    --box "-1 -1 -1 -1" \  # Caja de la cara (detección automática)
    --nosmooth            # Desactivar suavizado temporal
```

### Consejos de relleno

| Posición de la cara | Rellenos recomendados |
| ------------------- | --------------------- |
| Centrada            | 0 10 0 0              |
| Primer plano        | 0 15 0 0              |
| Lejana              | 0 5 0 0               |

## Procesamiento por lotes

```python
import os
import subprocess

def batch_wav2lip(faces_dir, audio_path, output_dir):
    os.makedirs(output_dir, exist_ok=True)

    for filename in os.listdir(faces_dir):
        if filename.endswith(('.mp4', '.jpg', '.png')):
            face_path = os.path.join(faces_dir, filename)
            output_path = os.path.join(output_dir, f"synced_{filename}")

            if filename.endswith(('.jpg', '.png')):
                output_path = output_path.rsplit('.', 1)[0] + '.mp4'

            cmd = [
                "python", "inference.py",
                "--checkpoint_path", "checkpoints/wav2lip_gan.pth",
                "--face", face_path,
                "--audio", audio_path,
                "--outfile", output_path
            ]

            try:
                subprocess.run(cmd, check=True)
                print(f"Procesado: {filename}")
            except subprocess.CalledProcessError as e:
                print(f"Error processing {filename}: {e}")

# Uso
batch_wav2lip("./faces", "speech.wav", "./outputs")
```

## Interfaz Gradio

```python
import gradio as gr
import subprocess
import tempfile
import os

def lip_sync(face_video, audio, quality):
    checkpoint = "checkpoints/wav2lip_gan.pth" if quality == "High (GAN)" else "checkpoints/wav2lip.pth"

    with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as out_file:
        output_path = out_file.name

    cmd = [
        "python", "inference.py",
        "--checkpoint_path", checkpoint,
        "--face", face_video,
        "--audio", audio,
        "--outfile", output_path
    ]

    subprocess.run(cmd, check=True)
    return output_path

demo = gr.Interface(
    fn=lip_sync,
    inputs=[
        gr.Video(label="Face Video/Image"),
        gr.Audio(type="filepath", label="Audio"),
        gr.Radio(["Standard", "High (GAN)"], value="High (GAN)", label="Quality")
    ],
    outputs=gr.Video(label="Video con labios sincronizados"),
    title="Wav2Lip - Sincronización labial"
)

demo.launch(server_name="0.0.0.0", server_port=7860)
```

## Servidor API

```python
from fastapi import FastAPI, UploadFile, File
from fastapi.responses import FileResponse
import tempfile
import subprocess
import os

app = FastAPI()

@app.post("/sync")
async def sync_lips(
    face: UploadFile = File(...),
    audio: UploadFile = File(...),
    quality: str = "gan"
):
    with tempfile.TemporaryDirectory() as tmpdir:
        # Guardar subidas
        face_ext = os.path.splitext(face.filename)[1]
        face_path = os.path.join(tmpdir, f"face{face_ext}")
        audio_path = os.path.join(tmpdir, "audio.wav")
        output_path = os.path.join(tmpdir, "output.mp4")

        with open(face_path, "wb") as f:
            f.write(await face.read())
        with open(audio_path, "wb") as f:
            f.write(await audio.read())

        # Ejecutar Wav2Lip
        checkpoint = "checkpoints/wav2lip_gan.pth" if quality == "gan" else "checkpoints/wav2lip.pth"

        cmd = [
            "python", "inference.py",
            "--checkpoint_path", checkpoint,
            "--face", face_path,
            "--audio", audio_path,
            "--outfile", output_path
        ]

        subprocess.run(cmd, check=True)

        return FileResponse(output_path, media_type="video/mp4")

# Ejecutar: uvicorn server:app --host 0.0.0.0 --port 8000
```

## TTS + canal Wav2Lip

Texto a video completo:

```python
from TTS.api import TTS
import subprocess

def text_to_lipsync(text, face_path, output_path, language="en"):
    # Generar voz
    tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2")
    audio_path = "temp_speech.wav"
    tts.tts_to_file(text=text, file_path=audio_path, language=language)

    # Sincronización labial
    cmd = [
        "python", "inference.py",
        "--checkpoint_path", "checkpoints/wav2lip_gan.pth",
        "--face", face_path,
        "--audio", audio_path,
        "--outfile", output_path
    ]
    subprocess.run(cmd, check=True)

    return output_path

# Uso
text_to_lipsync(
    "Hello, welcome to our presentation.",
    "presenter.jpg",
    "talking_presenter.mp4"
)
```

## Postprocesamiento

### Mejorar resultado

```python
import subprocess

def upscale_video(input_path, output_path):
    cmd = [
        "python", "-m", "realesrgan",
        "--input", input_path,
        "--output", output_path,
        "--scale", "2"
    ]
    subprocess.run(cmd, check=True)
```

### Agregar audio de nuevo

```bash

# Si se perdió el audio, volver a agregarlo
ffmpeg -i synced_video.mp4 -i original_audio.wav \
    -c:v copy -c:a aac \
    -map 0:v:0 -map 1:a:0 \
    final_output.mp4
```

## Solución de problemas

### Rostro no detectado

* Asegúrate de que la cara sea claramente visible
* Buena iluminación
* Preferible de frente
* Entrada de mayor resolución

### Mala calidad de sincronización

* Usar wav2lip\_gan.pth
* Ajustar el relleno
* Verificar la tasa de muestreo del audio (se recomienda 16 kHz)

### Salida entrecortada

* Aumentar resize\_factor
* Desactivar nosmooth
* Usar video de entrada de mayor calidad

## Rendimiento

| Entrada                | GPU      | Tiempo de procesamiento |
| ---------------------- | -------- | ----------------------- |
| video de 10 s          | RTX 3060 | \~30s                   |
| video de 10 s          | RTX 4090 | \~15s                   |
| video de 30 s          | RTX 4090 | \~45s                   |
| Imagen + audio de 10 s | RTX 3090 | \~20 s                  |

## Comparación con SadTalker

| Función              | Wav2Lip    | SadTalker   |
| -------------------- | ---------- | ----------- |
| Precisión labial     | Excelente  | Bueno       |
| Movimiento de cabeza | Ninguna    | Natural     |
| Expresión            | Ninguna    | Controlable |
| Velocidad            | Más rápido | Más lento   |
| Mejor para           | Doblaje    | Avatares    |

## Estimación de costos

Tarifas típicas del marketplace de CLORE.AI (a fecha de 2024):

| GPU       | Tarifa por hora | Tarifa diaria | Sesión de 4 horas |
| --------- | --------------- | ------------- | ----------------- |
| RTX 3060  | \~$0.03         | \~$0.70       | \~$0.12           |
| RTX 3090  | \~$0.06         | \~$1.50       | \~$0.25           |
| RTX 4090  | \~$0.10         | \~$2.30       | \~$0.40           |
| A100 40GB | \~$0.17         | \~$4.00       | \~$0.70           |
| A100 80GB | \~$0.25         | \~$6.00       | \~$1.00           |

*Los precios varían según el proveedor y la demanda. Consulta* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *para las tarifas actuales.*

**Ahorra dinero:**

* Usa **Spot** market para cargas de trabajo flexibles (a menudo 30-50% más barato)
* Paga con **CLORE** tokens
* Compara precios entre diferentes proveedores

## Próximos pasos

* [SadTalker](https://docs.clore.ai/guides/guides_v2-es/cabezas-parlantes/sadtalker) - Movimiento de cabeza + labios
* [XTTS](https://docs.clore.ai/guides/guides_v2-es/audio-y-voz/xtts-coqui) - Generar voz
* [Clon de voz RVC](https://docs.clore.ai/guides/guides_v2-es/audio-y-voz/rvc-voice-clone) - Conversión de voz
