# SadTalker

Anima rostros con audio para crear videos realistas de cabezas parlantes.

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

## Alquiler en CLORE.AI

1. Visitar [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 oferta)
4. Configura tu pedido:
   * Selecciona la imagen de Docker
   * Configura los puertos (TCP para SSH, HTTP para interfaces web)
   * Agrega variables de entorno si es necesario
   * Introduce el comando de inicio
5. Selecciona el 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 SadTalker?

SadTalker genera videos parlantes:

* Sincronización labial desde cualquier audio
* Movimientos naturales de la cabeza
* Funciona con una sola imagen
* Control de expresión

## Requisitos

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

## Despliegue rápido

**Imagen de Docker:**

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

**Puertos:**

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

**Comando:**

```bash
cd /workspace && \
git clone https://github.com/OpenTalker/SadTalker.git && \
cd SadTalker && \
pip install -r requirements.txt && \
bash scripts/download_models.sh && \
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://YOUR_HTTP_PUB_URL` en lugar de `localhost` en los ejemplos a continuación.

## Instalación

```bash
git clone https://github.com/OpenTalker/SadTalker.git
cd SadTalker

pip install torch torchvision torchaudio
pip install -r requirements.txt

# Descargar modelos preentrenados
bash scripts/download_models.sh
```

## Uso básico

### Línea de comandos

```bash
python inference.py \
    --driven_audio audio.wav \
    --source_image face.jpg \
    --result_dir ./results \
    --enhancer gfpgan
```

### API de Python

```python
from src.facerender.animate import AnimateFromCoeff
from src.generate_batch import get_data
from src.generate_facerender_batch import get_facerender_data
import torch

class SadTalker:
    def __init__(self):
        self.device = "cuda"
        # Inicializar modelos...

    def generate(self, source_image, driven_audio, **kwargs):
        # Procesar audio e imagen
        # Generar animación
        # Devolver ruta del video
        pass

# Uso
sadtalker = SadTalker()
video_path = sadtalker.generate(
    source_image="face.jpg",
    driven_audio="speech.wav"
)
```

## Con mejora de rostro

```bash

# Usando GFPGAN para mejora del rostro
python inference.py \
    --driven_audio audio.wav \
    --source_image face.jpg \
    --enhancer gfpgan \
    --result_dir ./results

# Usando Real-ESRGAN para la imagen completa
python inference.py \
    --driven_audio audio.wav \
    --source_image face.jpg \
    --enhancer realesrgan \
    --result_dir ./results
```

## Parámetros

```bash
python inference.py \
    --driven_audio audio.wav \
    --source_image face.jpg \
    --pose_style 0 \           # 0-46 estilos de movimiento de cabeza
    --expression_scale 1.0 \   # Intensidad de la expresión
    --still \                  # Movimiento de cabeza mínimo
    --preprocess crop \        # crop, resize, full
    --size 256 \               # Tamaño de salida
    --enhancer gfpgan
```

### Estilos de pose

| Rango | Efecto                 |
| ----- | ---------------------- |
| 0-5   | Movimientos sutiles    |
| 6-20  | Movimientos normales   |
| 21-46 | Movimientos expresivos |

## Procesamiento por lotes

```python
import os
import subprocess

def generate_talking_video(image_path, audio_path, output_dir):
    cmd = [
        "python", "inference.py",
        "--driven_audio", audio_path,
        "--source_image", image_path,
        "--result_dir", output_dir,
        "--enhancer", "gfpgan"
    ]
    subprocess.run(cmd, check=True)

# Procesar múltiples imágenes con el mismo audio
images = ["person1.jpg", "person2.jpg", "person3.jpg"]
audio = "speech.wav"

for i, img in enumerate(images):
    output = f"./results/video_{i}"
    generate_talking_video(img, audio, output)
```

## Interfaz Gradio

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

def generate_video(image, audio, pose_style, expression_scale, enhancer):
    with tempfile.TemporaryDirectory() as tmpdir:
        # Guardar entradas
        image_path = os.path.join(tmpdir, "input.jpg")
        audio_path = os.path.join(tmpdir, "audio.wav")
        image.save(image_path)

        # Guardar audio
        import soundfile as sf
        sf.write(audio_path, audio[1], audio[0])

        # Generar
        cmd = [
            "python", "inference.py",
            "--driven_audio", audio_path,
            "--source_image", image_path,
            "--result_dir", tmpdir,
            "--pose_style", str(pose_style),
            "--expression_scale", str(expression_scale),
            "--enhancer", enhancer
        ]
        subprocess.run(cmd, check=True)

        # Encontrar video de salida
        for f in os.listdir(tmpdir):
            if f.endswith(".mp4"):
                return os.path.join(tmpdir, f)

    return None

demo = gr.Interface(
    fn=generate_video,
    inputs=[
        gr.Image(type="pil", label="Source Face"),
        gr.Audio(label="Driving Audio"),
        gr.Slider(0, 46, value=0, step=1, label="Pose Style"),
        gr.Slider(0.5, 1.5, value=1.0, step=0.1, label="Expression Scale"),
        gr.Dropdown(["gfpgan", "realesrgan", "none"], value="gfpgan", label="Enhancer")
    ],
    outputs=gr.Video(label="Generated Video"),
    title="SadTalker - Talking Head Generation"
)

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("/generate")
async def generate(
    image: UploadFile = File(...),
    audio: UploadFile = File(...),
    pose_style: int = 0,
    expression_scale: float = 1.0
):
    with tempfile.TemporaryDirectory() as tmpdir:
        # Guardar subidas
        image_path = os.path.join(tmpdir, "input.jpg")
        audio_path = os.path.join(tmpdir, "audio.wav")

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

        # Generar
        cmd = [
            "python", "inference.py",
            "--driven_audio", audio_path,
            "--source_image", image_path,
            "--result_dir", tmpdir,
            "--pose_style", str(pose_style),
            "--expression_scale", str(expression_scale),
            "--enhancer", "gfpgan"
        ]
        subprocess.run(cmd, check=True)

        # Devolver video
        for f in os.listdir(tmpdir):
            if f.endswith(".mp4"):
                return FileResponse(os.path.join(tmpdir, f), media_type="video/mp4")

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

## Texto a voz + SadTalker

Canal completo:

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

def text_to_talking_video(text, image_path, output_path):
    # Generar voz con TTS
    tts = TTS("tts_models/en/ljspeech/tacotron2-DDC")
    audio_path = "temp_audio.wav"
    tts.tts_to_file(text=text, file_path=audio_path)

    # Generar video parlante
    cmd = [
        "python", "inference.py",
        "--driven_audio", audio_path,
        "--source_image", image_path,
        "--result_dir", output_path,
        "--enhancer", "gfpgan"
    ]
    subprocess.run(cmd, check=True)

# Uso
text_to_talking_video(
    "Hello, welcome to our presentation. Today we'll discuss AI.",
    "presenter.jpg",
    "./output"
)
```

## Control de expresión

```python

# Expresión mínima (estilo presentador de noticias)
cmd = [
    "python", "inference.py",
    "--driven_audio", "audio.wav",
    "--source_image", "face.jpg",
    "--expression_scale", "0.5",
    "--still"  # Reduce el movimiento de la cabeza
]

# Expresivo (personaje animado)
cmd = [
    "python", "inference.py",
    "--driven_audio", "audio.wav",
    "--source_image", "face.jpg",
    "--expression_scale", "1.5",
    "--pose_style", "30"
]
```

## Ajustes de calidad

| Ajuste              | Velocidad    | Calidad |
| ------------------- | ------------ | ------- |
| Sin enhancer, 256px | Rápido       | Básico  |
| GFPGAN, 256px       | Medio        | Bueno   |
| GFPGAN, 512px       | Lento        | Mejor   |
| RealESRGAN, 512px   | El más lento | Mejor   |

## Opciones de preprocesamiento

```bash

# Recortar - enfocar en el rostro (recomendado)
--preprocess crop

# Redimensionar - redimensionar imagen completa
--preprocess resize

# Completo - usar la imagen completa
--preprocess full
```

## Solución de problemas

### Rostro no detectado

* Usa una imagen clara y frontal del rostro
* Buena iluminación
* Evita oclusiones (gafas, pelo)

### Problemas de sincronización de audio

* Usa archivos WAV a 16 kHz
* Evita música de fondo
* Solo habla clara

### Movimiento entrecortado

* Aumenta ligeramente expression\_scale
* Prueba un pose\_style diferente
* Usa audio más largo

### Memoria insuficiente

* Reduce el tamaño de salida
* Desactiva el enhancer
* Usa el preprocesamiento crop

## Rendimiento

| Resolución     | GPU      | Tiempo (video de 10 s) |
| -------------- | -------- | ---------------------- |
| 256px          | RTX 3060 | \~30s                  |
| 256px          | RTX 4090 | \~15s                  |
| 512px + GFPGAN | RTX 4090 | \~45s                  |

## 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 tarifas actuales.*

**Ahorra dinero:**

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

## Próximos pasos

* [Wav2Lip](/guides/guides_v2-es/cabezas-parlantes/wav2lip.md) - Sincronización labial alternativa
* [Bark TTS](/guides/guides_v2-es/audio-y-voz/bark-tts.md) - Generar voz
* [XTTS](/guides/guides_v2-es/audio-y-voz/xtts-coqui.md) - Clonación de voz + TTS


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-es/cabezas-parlantes/sadtalker.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
