> For the complete documentation index, see [llms.txt](https://public-intelligence.gitbook.io/taina-agente-ia-ogtic/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://public-intelligence.gitbook.io/taina-agente-ia-ogtic/referencias-tecnicas/integrations/elevenlabs.md).

# ElevenLabs

Esta guía explica cómo Taína utiliza ElevenLabs para Text-to-Speech (TTS) con voces naturales en español.

ElevenLabs es el servicio de Text-to-Speech que permite a Taína:

* **Voces Naturales**: Síntesis de voz de alta calidad
* **Múltiples Idiomas**: Soporte para español y otros idiomas
* **Personalización**: Ajuste de velocidad, tono y estilo
* **Streaming**: Generación de audio en tiempo real

## Configuración de ElevenLabs

### 1. Obtener API Key

#### ElevenLabs Platform

```bash
# 1. Registrarse en ElevenLabs
# https://elevenlabs.io/

# 2. Ir a Profile → API Key
# 3. Generar nueva API key
# 4. Copiar la clave generada

# 5. Configurar en .env
ELEVENLABS_API_KEY=your_elevenlabs_api_key
ELEVENLABS_VOICE_ID=your_voice_id
```

#### Verificar API Key

```bash
# Test de conectividad
curl -X GET "https://api.elevenlabs.io/v1/voices" \
     -H "xi-api-key: $ELEVENLABS_API_KEY"
```

### 2. Configuración en Taína

```python
# src/main.py - Configuración de TTS con ElevenLabs
from livekit.plugins.elevenlabs import TTS

# Configuración de TTS
tts = TTS.create(
    provider="elevenlabs",
    voice_id=os.getenv("ELEVENLABS_VOICE_ID"),
    model="eleven_multilingual_v2",
    language="es",
    stability=0.5,           # Estabilidad de voz (0.0-1.0)
    similarity_boost=0.8,    # Similitud con voz original (0.0-1.0)
    style=0.0,              # Estilo de voz (0.0-1.0)
    use_speaker_boost=True   # Mejora de voz
)
```

### 3. Variables de entorno

```ini
# ElevenLabs Configuration
ELEVENLABS_API_KEY=your_elevenlabs_api_key
ELEVENLABS_VOICE_ID=your_voice_id

# Opcional: Configuración avanzada
ELEVENLABS_MODEL=eleven_multilingual_v2
ELEVENLABS_STABILITY=0.5
ELEVENLABS_SIMILARITY_BOOST=0.8
ELEVENLABS_STYLE=0.0
ELEVENLABS_USE_SPEAKER_BOOST=true
```

## Configuración de voces

### Voces disponibles

```python
# Voces recomendadas para español
spanish_voices = {
    "21m00Tcm4TlvDq8ikWAM": {
        "name": "Rachel",
        "language": "English",
        "description": "Voz clara y profesional",
        "use_case": "General, profesional"
    },
    "AZnzlk1XvdvUeBnXmlld": {
        "name": "Domi",
        "language": "English", 
        "description": "Voz joven y energética",
        "use_case": "Servicios, atención al cliente"
    },
    "EXAVITQu4vr4xnSDxMaL": {
        "name": "Bella",
        "language": "English",
        "description": "Voz suave y amigable",
        "use_case": "Asistencia, soporte"
    },
    "MF3mGyEYCl7XYWbV9V6O": {
        "name": "Elli",
        "language": "English",
        "description": "Voz madura y confiable",
        "use_case": "Gobierno, formal"
    }
}
```

### Configuración de voz

```python
# Configuración optimizada para TAINA
voice_config = {
    "voice_id": "21m00Tcm4TlvDq8ikWAM",  # Rachel - voz profesional
    "model": "eleven_multilingual_v2",    # Modelo multilingüe
    "language": "es",                     # Idioma español
    "stability": 0.5,                    # Estabilidad media
    "similarity_boost": 0.8,             # Alta similitud
    "style": 0.0,                        # Estilo neutro
    "use_speaker_boost": True,            # Mejora de voz
    "output_format": "mp3_44100_128"      # Formato de salida
}
```

## Integración con LiveKit

### Configuración del Agente

```python
# src/main.py - Integración con LiveKit Agent
async def entrypoint(ctx: JobContext):
    """Entrypoint principal con TTS de ElevenLabs"""
    
    await ctx.wait_for_room()
    room = ctx.room
    
    # Configurar STT
    stt = STT.create(
        provider="deepgram",
        model="nova-2",
        language="es"
    )
    
    # Configurar TTS
    tts = TTS.create(
        provider="elevenlabs",
        voice_id=os.getenv("ELEVENLABS_VOICE_ID"),
        model="eleven_multilingual_v2",
        language="es",
        stability=0.5,
        similarity_boost=0.8,
        style=0.0,
        use_speaker_boost=True
    )
    
    # Crear agente
    agent = ProductionAssistant()
    
    # Iniciar con STT/TTS
    await agent.start(ctx, stt=stt, tts=tts)
```

### Manejo de Audio Stream

```python
# Manejo de stream de audio TTS
class TTSStreamHandler:
    def __init__(self, tts):
        self.tts = tts
        self.audio_queue = asyncio.Queue()
        self.is_speaking = False
    
    async def synthesize_speech(self, text):
        """Sintetiza texto a audio"""
        try:
            # Sanitizar texto para TTS
            sanitized_text = self.sanitize_for_tts(text)
            
            # Generar audio
            audio_data = await self.tts.synthesize(
                text=sanitized_text,
                voice_id=os.getenv("ELEVENLABS_VOICE_ID"),
                model="eleven_multilingual_v2",
                voice_settings={
                    "stability": 0.5,
                    "similarity_boost": 0.8,
                    "style": 0.0,
                    "use_speaker_boost": True
                }
            )
            
            # Enviar a cola de audio
            await self.audio_queue.put(audio_data)
            
        except Exception as e:
            print(f"Error sintetizando audio: {e}")
    
    def sanitize_for_tts(self, text):
        """Sanitiza texto para reproducción por TTS"""
        if not text:
            return ""
        
        # Limpiar markdown
        sanitized = text.replace("**", "")
        sanitized = sanitized.replace("*", "")
        
        # Convertir números a palabras
        sanitized = self.convert_numbers_to_words(sanitized)
        
        # Convertir URLs
        sanitized = self.convert_urls_to_words(sanitized)
        
        # Convertir monedas
        sanitized = self.convert_currency_to_words(sanitized)
        
        return sanitized.strip()
    
    def convert_numbers_to_words(self, text):
        """Convierte números a palabras para TTS"""
        import re
        
        # Convertir números grandes
        text = re.sub(r'\b(\d{1,3}(?:,\d{3})*)\b', 
                     lambda m: self.number_to_words(m.group(1)), text)
        
        return text
    
    def convert_currency_to_words(self, text):
        """Convierte monedas a palabras para TTS"""
        import re
        
        # Convertir RD$
        text = re.sub(r'RD\$\s*([\d.,]+)', 
                     lambda m: f"{self.number_to_words(m.group(1))} pesos dominicanos", 
                     text)
        
        # Convertir US$
        text = re.sub(r'US\$\s*([\d.,]+)', 
                     lambda m: f"{self.number_to_words(m.group(1))} dólares", 
                     text)
        
        return text
    
    def convert_urls_to_words(self, text):
        """Convierte URLs a palabras para TTS"""
        import re
        
        # Convertir URLs
        text = re.sub(r'https?://[^\s]+', 
                     lambda m: m.group(0).replace('.', ' punto ').replace('/', ' diagonal '), 
                     text)
        
        return text
```

## Optimización para español

### Sanitización de texto

```python
# src/utils/tts_sanitizer.py
class TTSSanitizer:
    def __init__(self):
        self.currency_patterns = {
            r'RD\$\s*([\d.,]+)': lambda m: f"{self.number_to_words(m.group(1))} pesos dominicanos",
            r'US\$\s*([\d.,]+)': lambda m: f"{self.number_to_words(m.group(1))} dólares"
        }
        
        self.url_patterns = {
            r'https?://[^\s]+': lambda m: m.group(0).replace('.', ' punto ').replace('/', ' diagonal ')
        }
        
        self.number_patterns = {
            r'\b(\d{1,3}(?:,\d{3})*)\b': lambda m: self.number_to_words(m.group(1))
        }
    
    def sanitize(self, text):
        """Sanitiza texto completo para TTS"""
        if not text:
            return ""
        
        # Limpiar markdown
        text = text.replace("**", "").replace("*", "")
        
        # Aplicar conversiones
        for pattern, replacement in self.currency_patterns.items():
            text = re.sub(pattern, replacement, text)
        
        for pattern, replacement in self.url_patterns.items():
            text = re.sub(pattern, replacement, text)
        
        for pattern, replacement in self.number_patterns.items():
            text = re.sub(pattern, replacement, text)
        
        # Limpiar espacios extra
        text = re.sub(r'\s+', ' ', text).strip()
        
        return text
    
    def number_to_words(self, number_str):
        """Convierte números a palabras en español"""
        # Implementación simplificada
        number_map = {
            '0': 'cero', '1': 'uno', '2': 'dos', '3': 'tres', '4': 'cuatro',
            '5': 'cinco', '6': 'seis', '7': 'siete', '8': 'ocho', '9': 'nueve'
        }
        
        # Para números simples
        if len(number_str) <= 3:
            return ' '.join(number_map[digit] for digit in number_str)
        
        # Para números complejos, usar biblioteca especializada
        return number_str  # Fallback
```

### Configuración de voz para Gobierno

```python
# Configuración específica para servicios gubernamentales
government_voice_config = {
    "voice_id": "21m00Tcm4TlvDq8ikWAM",  # Rachel - profesional
    "model": "eleven_multilingual_v2",
    "language": "es",
    "stability": 0.6,                    # Mayor estabilidad
    "similarity_boost": 0.8,            # Alta similitud
    "style": 0.0,                       # Estilo neutro
    "use_speaker_boost": True,
    "output_format": "mp3_44100_128",
    "speech_rate": 1.0,                  # Velocidad normal
    "pitch": 1.0,                       # Tono normal
    "volume": 1.0                       # Volumen normal
}
```

## Manejo de errores

### Errores comunes

#### Error: "Invalid API key"

```bash
# Verificar API key
python3 -c "
import os
from dotenv import load_dotenv
load_dotenv()

api_key = os.getenv('ELEVENLABS_API_KEY')
voice_id = os.getenv('ELEVENLABS_VOICE_ID')

if api_key:
    print(f'API Key: {api_key[:10]}...')
    print('Length:', len(api_key))
else:
    print('API Key not found')

if voice_id:
    print(f'Voice ID: {voice_id}')
else:
    print('Voice ID not found')
"

# Test de conectividad
curl -X GET "https://api.elevenlabs.io/v1/voices" \
     -H "xi-api-key: $ELEVENLABS_API_KEY"
```

#### Error: "Voice not found"

```bash
# Listar voces disponibles
curl -X GET "https://api.elevenlabs.io/v1/voices" \
     -H "xi-api-key: $ELEVENLABS_API_KEY" | jq '.voices[] | {voice_id, name}'
```

#### Error: "Rate limit exceeded"

```python
# Implementar rate limiting
import asyncio
from datetime import datetime, timedelta

class ElevenLabsRateLimiter:
    def __init__(self, max_requests=100, time_window=60):
        self.max_requests = max_requests
        self.time_window = time_window
        self.requests = []
    
    async def acquire(self):
        now = datetime.now()
        # Limpiar requests antiguos
        self.requests = [req for req in self.requests 
                        if now - req < timedelta(seconds=self.time_window)]
        
        if len(self.requests) >= self.max_requests:
            sleep_time = self.time_window - (now - self.requests[0]).seconds
            await asyncio.sleep(sleep_time)
        
        self.requests.append(now)
```

### Manejo de timeouts

```python
# Configuración de timeouts
timeout_config = {
    "connection_timeout": 10,    # 10 segundos
    "request_timeout": 30,       # 30 segundos
    "audio_timeout": 60,         # 60 segundos para audio
    "max_text_length": 5000      # 5000 caracteres máximo
}

# Implementar timeout
async def synthesize_with_timeout(text, timeout=30):
    try:
        result = await asyncio.wait_for(
            tts.synthesize(text),
            timeout=timeout
        )
        return result
    except asyncio.TimeoutError:
        print("TTS timeout - text too long")
        return None
```

## Validación operativa

### Verificación de conectividad

```python
# verify_elevenlabs_connection.py
import asyncio
import os
from livekit.plugins.elevenlabs import TTS


async def validate_elevenlabs_connection():
    """Verifica conectividad básica con ElevenLabs"""
    try:
        tts = TTS.create(
            provider="elevenlabs",
            voice_id=os.getenv("ELEVENLABS_VOICE_ID"),
            model="eleven_multilingual_v2"
        )

        sample_text = "Hola, soy Taína, tu asistente virtual del gobierno dominicano."
        audio_data = await tts.synthesize(sample_text)

        print("✅ ElevenLabs conectado exitosamente")
        print(f"Audio generado: {len(audio_data)} bytes")

        with open("sample_audio.mp3", "wb") as f:
            f.write(audio_data)
        print("Audio guardado en sample_audio.mp3")

    except Exception as e:
        print(f"❌ Error conectando con ElevenLabs: {e}")


asyncio.run(validate_elevenlabs_connection())
```

### Verificación de calidad de voz

```python
# verify_voice_quality.py
import asyncio
import os
from livekit.plugins.elevenlabs import TTS


async def validate_voice_quality():
    """Ajusta la voz con diferentes configuraciones"""
    sample_texts = [
        "Hola, necesito renovar mi licencia de conducir",
        "¿Cuánto cuesta el trámite de pasaporte?",
        "El costo es de mil novecientos pesos dominicanos",
        "Puedes hacer el trámite en línea en www.gob.do"
    ]

    voice_configs = [
        {"stability": 0.3, "similarity_boost": 0.7, "style": 0.0},
        {"stability": 0.5, "similarity_boost": 0.8, "style": 0.0},
        {"stability": 0.7, "similarity_boost": 0.9, "style": 0.0}
    ]

    tts = TTS.create(
        provider="elevenlabs",
        voice_id=os.getenv("ELEVENLABS_VOICE_ID"),
        model="eleven_multilingual_v2"
    )

    for i, config in enumerate(voice_configs, start=1):
        print(f"Configuración {i}: {config}")

        for text in sample_texts:
            try:
                audio_data = await tts.synthesize(
                    text=text,
                    voice_settings=config
                )

                print(f"  Texto: {text}")
                print(f"  Audio: {len(audio_data)} bytes")
                print(f"  Calidad: {'✅' if len(audio_data) > 1000 else '❌'}")

            except Exception as e:
                print(f"  Error: {e}")

            print("  ---")


asyncio.run(validate_voice_quality())
```

## Monitoreo y métricas

### Métricas de TTS

```python
# src/utils/tts_metrics.py
class ElevenLabsMetrics:
    def __init__(self):
        self.request_count = 0
        self.total_characters = 0
        self.successful_syntheses = 0
        self.failed_syntheses = 0
        self.average_audio_length = 0
        self.response_times = []
    
    def record_synthesis(self, text_length, audio_length, response_time, success=True):
        self.request_count += 1
        self.total_characters += text_length
        self.response_times.append(response_time)
        
        if success:
            self.successful_syntheses += 1
            self.average_audio_length = (
                (self.average_audio_length * (self.successful_syntheses - 1) + audio_length) 
                / self.successful_syntheses
            )
        else:
            self.failed_syntheses += 1
    
    def get_stats(self):
        return {
            "total_requests": self.request_count,
            "success_rate": self.successful_syntheses / max(self.request_count, 1),
            "total_characters": self.total_characters,
            "average_audio_length": self.average_audio_length,
            "avg_response_time": sum(self.response_times) / len(self.response_times),
            "characters_per_second": self.total_characters / max(sum(self.response_times), 1)
        }
```

### Health Check

```python
# src/tools.py - Health check para ElevenLabs
@function_tool()
async def health_check() -> str:
    """Verifica el estado del sistema incluyendo ElevenLabs"""
    
    status = {
        "timestamp": datetime.now().isoformat(),
        "elevenlabs": "unknown",
        "knowledge_base": "unknown",
        "memory_usage": "unknown"
    }
    
    # Verificar ElevenLabs
    try:
        tts = TTS.create(
            provider="elevenlabs",
            voice_id=os.getenv("ELEVENLABS_VOICE_ID"),
            model="eleven_multilingual_v2"
        )
        
        # Test con texto mínimo
        test_text = "test"
        audio_data = await tts.synthesize(test_text)
        
        if audio_data and len(audio_data) > 0:
            status["elevenlabs"] = "healthy"
        else:
            status["elevenlabs"] = "unhealthy"
            
    except Exception as e:
        status["elevenlabs"] = f"error: {str(e)}"
    
    return json.dumps(status)
```

## Configuración de producción

### Optimizaciones de rendimiento

```python
# Configuración optimizada para producción
production_config = {
    "voice_id": "21m00Tcm4TlvDq8ikWAM",
    "model": "eleven_multilingual_v2",
    "language": "es",
    "stability": 0.5,
    "similarity_boost": 0.8,
    "style": 0.0,
    "use_speaker_boost": True,
    "output_format": "mp3_44100_128",
    "speech_rate": 1.0,
    "pitch": 1.0,
    "volume": 1.0,
    "max_text_length": 5000,
    "timeout": 30,
    "retry_attempts": 3
}
```

### Configuración de caching

```python
# Cache de audio generado
class TTSCache:
    def __init__(self, max_size=100):
        self.cache = {}
        self.max_size = max_size
    
    def get_cache_key(self, text, voice_settings):
        """Genera clave única para el cache"""
        import hashlib
        content = f"{text}:{json.dumps(voice_settings, sort_keys=True)}"
        return hashlib.md5(content.encode()).hexdigest()
    
    def get(self, text, voice_settings):
        key = self.get_cache_key(text, voice_settings)
        return self.cache.get(key)
    
    def set(self, text, voice_settings, audio_data):
        key = self.get_cache_key(text, voice_settings)
        if len(self.cache) >= self.max_size:
            # Eliminar entrada más antigua
            oldest_key = next(iter(self.cache))
            del self.cache[oldest_key]
        self.cache[key] = audio_data
```

## Recursos adicionales

* [ElevenLabs Documentation](https://docs.elevenlabs.io/)
* [ElevenLabs API Reference](https://docs.elevenlabs.io/api-reference)
* [LiveKit ElevenLabs Plugin](https://docs.livekit.io/agents/plugins/elevenlabs/)
* [Voice Cloning Guide](https://docs.elevenlabs.io/voice-cloning)

## Próximos pasos

1. **Arquitectura de la Base de Conocimiento**: [Arquitectura de la base de conocimiento](/taina-agente-ia-ogtic/arquitectura-y-conceptos/architecture/knowledge-base.md)
2. **Referencia de Configuración**: [Referencia de configuración](/taina-agente-ia-ogtic/referencias-tecnicas/api/configuration.md)
3. **Solución de Problemas**: [Solución de problemas](https://github.com/public-intelligence/taina_ogtic/blob/master/taina-gitbook-ogtic/taina-asistente-ia/index/how-to/troubleshoot.md)

***

¿Necesitas ayuda? Consulta la [guía de solución de problemas](https://github.com/public-intelligence/taina_ogtic/blob/master/taina-gitbook-ogtic/taina-asistente-ia/index/how-to/troubleshoot.md) o la [documentación de configuración](/taina-agente-ia-ogtic/referencias-tecnicas/api/configuration.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://public-intelligence.gitbook.io/taina-agente-ia-ogtic/referencias-tecnicas/integrations/elevenlabs.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
