# WhisperX con diarización

WhisperX amplía Whisper de OpenAI con tres mejoras críticas: **marcas de tiempo a nivel de palabra** mediante alineación forzada de fonemas, **diarización de oradores** usando pyannote.audio, y **hasta 70× la velocidad en tiempo real** a través de inferencia por lotes con faster-whisper. Es la herramienta de referencia para canalizaciones de transcripción en producción que necesitan sincronización precisa e identificación de oradores.

**GitHub:** [m-bain/whisperX](https://github.com/m-bain/whisperX) **PyPI:** [whisperx](https://pypi.org/project/whisperx/) **Licencia:** BSD-4-Clause **Artículo:** [arxiv.org/abs/2303.00747](https://arxiv.org/abs/2303.00747)

## Características clave

* **Marcas de tiempo a nivel de palabra** — ±50 ms de precisión mediante alineación forzada con wav2vec2 (vs ±500 ms en Whisper estándar)
* **Diarización de oradores** — identifica quién dijo qué mediante pyannote.audio 3.1
* **Inferencia por lotes** — hasta 70× la velocidad en tiempo real en RTX 4090
* **Prefiltrado VAD** — Silero VAD elimina silencios antes de la transcripción
* **Todos los modelos Whisper** — desde tiny hasta large-v3-turbo
* **Múltiples formatos de salida** — JSON, SRT, VTT, TXT, TSV
* **Detección automática de idioma** — o forzar un idioma específico para un procesamiento más rápido

## Requisitos

| Componente | Mínimo                | Recomendado              |
| ---------- | --------------------- | ------------------------ |
| GPU        | RTX 3060 12 GB        | RTX 4090 24 GB           |
| VRAM       | 4 GB (modelo pequeño) | 10 GB+ (large-v3-turbo)  |
| RAM        | 8 GB                  | 16 GB+                   |
| Disco      | 5 GB                  | 20 GB (caché de modelos) |
| Python     | 3.9+                  | 3.11                     |
| CUDA       | 11.8+                 | 12.1+                    |

**Token de HuggingFace requerido** para diarización — acepta la licencia en [pyannote/speaker-diarization-3.1](https://huggingface.co/pyannote/speaker-diarization-3.1).

**Recomendación de Clore.ai:** RTX 3090 (~~$0.30–1.00/día) para el modelo large-v3-turbo con tamaño de lote 16. RTX 4090 (~~$0.50–2.00/día) para el máximo rendimiento con tamaño de lote 32.

## Instalación

```bash
# Instalar WhisperX
pip install whisperx

# Verificar GPU
python -c "import torch; print(torch.cuda.get_device_name(0))"
```

Si encuentras conflictos de versión de CUDA:

```bash
pip install torch==2.5.1+cu124 torchaudio==2.5.1+cu124 --index-url https://download.pytorch.org/whl/cu124
pip install whisperx
```

## Inicio rápido

```python
import whisperx
import json

device = "cuda"
compute_type = "float16"  # "int8" para menor VRAM
batch_size = 16            # reducir a 4-8 si la VRAM es limitada

# 1. Cargar modelo
model = whisperx.load_model("large-v3-turbo", device, compute_type=compute_type)

# 2. Cargar y transcribir audio
audio = whisperx.load_audio("interview.mp3")
result = model.transcribe(audio, batch_size=batch_size)
print(f"Language: {result['language']}")

# 3. Alinear para marcas de tiempo a nivel de palabra
model_a, metadata = whisperx.load_align_model(
    language_code=result["language"], device=device
)
result = whisperx.align(
    result["segments"], model_a, metadata, audio, device,
    return_char_alignments=False,
)

# 4. Imprimir resultados
for seg in result["segments"]:
    print(f"[{seg['start']:.2f}s → {seg['end']:.2f}s] {seg['text']}")
    for w in seg.get("words", []):
        print(f"  '{w['word']}' @ {w.get('start', 0):.2f}s")

# 5. Guardar
with open("transcript.json", "w") as f:
    json.dump(result, f, indent=2, ensure_ascii=False)
```

## Ejemplos de uso

### Transcripción con diarización de oradores

```python
import whisperx
import gc
import torch

device = "cuda"
HF_TOKEN = "hf_your_token_here"  # desde huggingface.co/settings/tokens

# Paso 1: Transcribir
model = whisperx.load_model("large-v3-turbo", device, compute_type="float16")
audio = whisperx.load_audio("meeting.mp3")
result = model.transcribe(audio, batch_size=16)

# Liberar memoria GPU antes de cargar el modelo de alineación
del model; gc.collect(); torch.cuda.empty_cache()

# Paso 2: Alinear
model_a, metadata = whisperx.load_align_model(
    language_code=result["language"], device=device
)
result = whisperx.align(result["segments"], model_a, metadata, audio, device)
del model_a; gc.collect(); torch.cuda.empty_cache()

# Paso 3: Diarizar
diarize_model = whisperx.DiarizationPipeline(
    use_auth_token=HF_TOKEN, device=device
)
diarize_segments = diarize_model(audio, min_speakers=2, max_speakers=6)

# Paso 4: Asignar oradores a palabras
result = whisperx.assign_word_speakers(diarize_segments, result)

for seg in result["segments"]:
    speaker = seg.get("speaker", "UNKNOWN")
    print(f"[{speaker}] [{seg['start']:.1f}s → {seg['end']:.1f}s] {seg['text']}")
```

### Uso en línea de comandos

```bash
# Transcripción básica
whisperx audio.mp3 --model large-v3-turbo --device cuda

# Forzar idioma (más rápido, omite detección)
whisperx audio.mp3 --model large-v3-turbo --language en --device cuda

# Con diarización de oradores
whisperx audio.mp3 --model large-v3-turbo --diarize --hf_token hf_your_token

# Salida de subtítulos SRT
whisperx audio.mp3 --model large-v3-turbo --output_format srt --output_dir ./subs/

# Modo baja VRAM
whisperx audio.mp3 --model medium --compute_type int8 --batch_size 4 --device cuda

# Procesar por lotes un directorio
for f in /data/audio/*.mp3; do
  whisperx "$f" --model large-v3-turbo --output_dir /data/transcripts/
done
```

### Script de generación SRT

```python
import whisperx

def transcribe_to_srt(audio_path, output_path, model_name="large-v3-turbo"):
    device = "cuda"
    model = whisperx.load_model(model_name, device, compute_type="float16")
    audio = whisperx.load_audio(audio_path)
    result = model.transcribe(audio, batch_size=16)

    model_a, metadata = whisperx.load_align_model(
        language_code=result["language"], device=device
    )
    result = whisperx.align(result["segments"], model_a, metadata, audio, device)

    with open(output_path, "w") as f:
        for i, seg in enumerate(result["segments"], 1):
            start = format_ts(seg["start"])
            end = format_ts(seg["end"])
            f.write(f"{i}\n{start} --> {end}\n{seg['text'].strip()}\n\n")

    print(f"SRT guardado en {output_path}")

def format_ts(seconds):
    h = int(seconds // 3600)
    m = int((seconds % 3600) // 60)
    s = int(seconds % 60)
    ms = int((seconds % 1) * 1000)
    return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"

transcribe_to_srt("podcast.mp3", "podcast.srt")
```

## Pruebas de rendimiento

| Método           | Modelo             | Audio de 1 h | GPU          | Velocidad aproximada |
| ---------------- | ------------------ | ------------ | ------------ | -------------------- |
| Whisper estándar | large-v3           | \~60 min     | RTX 3090     | 1×                   |
| faster-whisper   | large-v3           | \~5 min      | RTX 3090     | \~12×                |
| **WhisperX**     | **large-v3-turbo** | **\~1 min**  | **RTX 3090** | **\~60×**            |
| **WhisperX**     | **large-v3-turbo** | **\~50 seg** | **RTX 4090** | **\~70×**            |

| Tamaño de lote | Velocidad (RTX 4090) | VRAM  |
| -------------- | -------------------- | ----- |
| 4              | \~30× en tiempo real | 6 GB  |
| 8              | \~45× en tiempo real | 8 GB  |
| 16             | \~60× en tiempo real | 10 GB |
| 32             | \~70× en tiempo real | 14 GB |

## Consejos para usuarios de Clore.ai

* **Liberar VRAM entre pasos** — eliminar modelos y llamar `torch.cuda.empty_cache()` entre transcripción, alineación y diarización
* **Token de HuggingFace** — debes aceptar la licencia del modelo pyannote antes de que la diarización funcione; establece `HF_TOKEN` como una variable de entorno
* **Ajuste del tamaño de lote** — comienza con `batch_size=16`, reduce a 4–8 en tarjetas de 12 GB, aumenta a 32 en tarjetas de 24 GB
* **`int8` cómputo** — usar `compute_type="int8"` para reducir a la mitad el uso de VRAM con una pérdida mínima de calidad
* **Imagen Docker** — `pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime`
* **Caché persistente de modelos** — monta `/root/.cache/huggingface` para evitar volver a descargar modelos en cada reinicio del contenedor

## Solución de problemas

| Problema                            | Solución                                                                                                                                |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `CUDA fuera de memoria`             | Reducir `batch_size`, usar `compute_type="int8"`, o usar un modelo más pequeño (medium, small)                                          |
| Diarización devuelve `UNKNOWN`      | Asegúrate de que el token de HuggingFace sea válido y de que aceptaste la licencia de pyannote                                          |
| `No hay módulo llamado 'whisperx'`  | `pip install whisperx` — asegúrate de que no sea un error tipográfico (es `whisperx`, no en `whisper-x`)                                |
| Marcas de tiempo de palabras pobres | Comprueba que `whisperx.align()` se llame después de `transcribe()` — la salida cruda de Whisper carece de precisión a nivel de palabra |
| Detección de idioma incorrecta      | Forzar idioma con `--language en` o `language="en"` en la API de Python                                                                 |
| Procesamiento lento                 | Aumente `batch_size`, usar `large-v3-turbo` en lugar de `large-v3`, asegúrate de que la GPU no esté compartida                          |


---

# 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/audio-y-voz/whisperx.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.
