Files
system-docs/v4-archive/penny/docs/PENNY_ASISTENTE_VOZ.md
2025-12-24 17:28:34 +00:00

671 lines
22 KiB
Markdown

# PENNY — Asistente Personal de Voz
**Especificación Técnica v1.0**
**Componente del Sistema DECK**
---
## 1. Definición
### 1.1 ¿Qué es PENNY?
PENNY es el **asistente personal de voz** del DECK. Interfaz conversacional hablada 100% natural.
```
┌─────────────────────────────────────────────────────────────────────┐
│ PENNY │
│ │
│ • ES la voz del DECK │
│ • ES la interfaz hablada con el usuario │
│ • ES quien llama a GRACE cuando necesita datos │
│ • HABLA con el usuario (GRACE no puede) │
│ • REGISTRA todo en el log (planos de información) │
│ │
│ "PENNY habla, GRACE procesa, el Log recuerda." │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
### 1.2 Principios
| Principio | Descripción |
|-----------|-------------|
| **Privacidad radical** | Modelos autoalojados, zero retención en proceso |
| **Conversación natural** | Turnos fluidos, interrupciones, latencia <2s |
| **Log como verdad** | Todo persiste en DECK, incluyendo personalidad |
| **Planos separados** | Contextos cargables independientemente |
| **Proceso stateless** | Servidor remoto no guarda nada |
---
## 2. Arquitectura
### 2.1 Diagrama General
```
┌─────────────────────────────────────────────────────────────────────┐
│ SERVIDOR DE PROCESO (Remoto) │
│ GPU potente · Pago por uso · ZERO RETENCIÓN │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Silero │─▶│ Whisper │─▶│ LLM │─▶│ TTS │ │
│ │ VAD │ │ Large │ │ (local) │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Modelos cargados desde almacenamiento ─── NO guardan estado │
│ Al terminar sesión: memoria volátil borrada │
│ │
└─────────────────────────────────────────────────────────────────────┘
▲ │
│ Audio + Planos │ Audio + Datos
│ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ DECK │
│ Servidor Personal │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PLANOS │ │ GRACE │ │ THE VAULT │ │
│ │ (Log) │ │ (Contrato │ │ (Recados) │ │
│ │ │ │ Común) │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ Única ubicación con persistencia │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
### 2.2 Separación de Responsabilidades
| Ubicación | Responsabilidad | Persistencia |
|-----------|-----------------|--------------|
| **Servidor Proceso** | VAD, ASR, LLM, TTS | NINGUNA |
| **DECK** | Planos, Log, GRACE, Vault | TOTAL |
### 2.3 Flujo Voice-to-Voice
```
DECK SERVIDOR PROCESO
│ │
│──── Audio + Planos ──────────────▶│
│ │
│ 1. VAD detecta voz
│ 2. ASR transcribe
│ 3. LLM genera respuesta
│ 4. TTS sintetiza
│ │
│◀──── Audio + Datos ──────────────│
│ │
│ (memoria borrada)
├── Log registra turno
├── GRACE procesa si necesario
└── Vault guarda si recado
```
### 2.4 Zero Retención en Proceso
```
┌─────────────────────────────────────────────────────────────────────┐
│ POLÍTICA ZERO RETENCIÓN │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ SERVIDOR DE PROCESO: │
│ │
│ ✗ NO guarda audio de entrada │
│ ✗ NO guarda transcripciones │
│ ✗ NO guarda prompts ni respuestas │
│ ✗ NO guarda contexto entre sesiones │
│ ✗ NO tiene logs persistentes │
│ │
│ ✓ Modelos cargados desde almacenamiento (solo lectura) │
│ ✓ Procesamiento en memoria volátil │
│ ✓ Al terminar: todo descartado │
│ │
│ DECK: │
│ │
│ ✓ Único lugar con persistencia │
│ ✓ Log completo de conversaciones │
│ ✓ Planos de información │
│ ✓ Control total del usuario sobre sus datos │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 3. Planos de Información
Todo persiste en DECK. Los planos se envían al servidor de proceso en cada sesión.
### 3.1 Estructura de Planos
```
┌─────────────────────────────────────────────────────────────────────┐
│ PLANO 0: SISTEMA INMUTABLE │
│ Capacidades, limitaciones, reglas fundamentales │
├─────────────────────────────────────────────────────────────────────┤
│ PLANO 1: PERSONALIDAD CONFIGURABLE │
│ Nombre, tono, estilo, configuración voz │
├─────────────────────────────────────────────────────────────────────┤
│ PLANO 2: CONTEXTO PERSONAL PERSISTENTE │
│ Info usuario, preferencias, historial │
├─────────────────────────────────────────────────────────────────────┤
│ PLANO 3: CONTEXTO AMBIENTAL DINÁMICO │
│ Fecha, hora, estado sistema, recados pendientes │
├─────────────────────────────────────────────────────────────────────┤
│ PLANO 4: DATASET BAJO DEMANDA │
│ Datos específicos de tarea (catálogos, documentos) │
├─────────────────────────────────────────────────────────────────────┤
│ PLANO 5: CONVERSACIÓN VOLÁTIL │
│ Historial de sesión actual │
└─────────────────────────────────────────────────────────────────────┘
```
### 3.2 Definición de Planos
#### PLANO 0: SISTEMA
```yaml
plano: SISTEMA
persistencia: permanente
modificable: false
contenido:
version: "1.0"
nombre_asistente: "Penny"
capacidades:
- conversacion_natural
- gestion_recados
- consulta_datos_via_grace
limitaciones:
- no_modifica_datos_directamente
- no_ejecuta_acciones_externas
reglas:
- respuestas_concisas_max_3_oraciones
- confirmar_antes_de_crear_recados
- nunca_inventar_datos
```
#### PLANO 1: PERSONALIDAD
```yaml
plano: PERSONALIDAD
persistencia: permanente
modificable: true
contenido:
nombre: "Penny"
tono: "Cercano pero profesional"
estilo: "Directo, sin rodeos"
tratamiento: "Tuteo natural"
muletillas_evitar:
- "¡Claro que sí!"
- "¡Por supuesto!"
voz:
speaker_reference: "penny_base"
idioma: "es"
```
#### PLANO 2: CONTEXTO PERSONAL
```yaml
plano: CONTEXTO_PERSONAL
persistencia: permanente
modificable: true
player_id: "uuid-usuario"
contenido:
nombre_usuario: "Carlos"
preferencias:
formato_hora: "24h"
formato_fecha: "dd/mm/yyyy"
recordar:
- "Prefiere respuestas cortas"
- "Reuniones los lunes por la mañana"
```
#### PLANO 3: CONTEXTO AMBIENTAL
```yaml
plano: CONTEXTO_AMBIENTAL
persistencia: sesion
modificable: auto
contenido:
fecha: "2025-12-16"
hora: "10:30"
dia_semana: "martes"
recados_pendientes: 3
eventos_hoy:
- "14:00 - Llamada cliente"
```
#### PLANO 4: DATASET
```yaml
plano: DATASET
persistencia: sesion
carga: bajo_demanda
contenido:
tipo: "catalogo_productos"
fuente: "catalogo_2025"
registros: 1547
```
#### PLANO 5: CONVERSACIÓN
```yaml
plano: CONVERSACION
persistencia: sesion
modificable: append_only
contenido:
sesion_id: "uuid"
turnos:
- turno: 1
rol: "usuario"
texto: "¿Qué tengo pendiente?"
timestamp: "2025-12-16T10:25:15Z"
- turno: 2
rol: "penny"
texto: "Tienes 3 recados pendientes..."
latencia_ms: 1850
```
---
## 4. Estructura del Log
### 4.1 Tabla: PENNY_LOG
```sql
CREATE TABLE penny_log (
id UUID PRIMARY KEY,
sesion_id UUID NOT NULL,
turno_index INTEGER NOT NULL,
-- Timing
timestamp_inicio TIMESTAMPTZ NOT NULL,
timestamp_fin TIMESTAMPTZ,
-- Contenido
rol VARCHAR(10) CHECK (rol IN ('usuario', 'penny', 'sistema')),
texto TEXT NOT NULL,
texto_hash VARCHAR(64),
-- Audio (referencia local en DECK)
audio_ref VARCHAR(255),
audio_duracion_ms INTEGER,
-- Métricas
latencia_total_ms INTEGER,
latencia_asr_ms INTEGER,
latencia_llm_ms INTEGER,
latencia_tts_ms INTEGER,
tokens_prompt INTEGER,
tokens_respuesta INTEGER,
-- Trazabilidad
trace_id UUID,
grace_llamadas JSONB DEFAULT '[]',
planos_activos JSONB NOT NULL,
-- Estado
interrumpido BOOLEAN DEFAULT false
);
```
### 4.2 Tabla: PENNY_PLANOS
```sql
CREATE TABLE penny_planos (
id UUID PRIMARY KEY,
plano_tipo VARCHAR(50) NOT NULL,
plano_version VARCHAR(20) NOT NULL,
player_id UUID,
contenido JSONB NOT NULL,
contenido_hash VARCHAR(64),
fecha_modificacion TIMESTAMPTZ DEFAULT NOW(),
activo BOOLEAN DEFAULT true
);
```
### 4.3 Tabla: PENNY_SESIONES
```sql
CREATE TABLE penny_sesiones (
id UUID PRIMARY KEY,
player_id UUID NOT NULL,
inicio TIMESTAMPTZ NOT NULL,
fin TIMESTAMPTZ,
total_turnos INTEGER DEFAULT 0,
planos_cargados JSONB NOT NULL,
resumen TEXT,
estado VARCHAR(20) DEFAULT 'activa'
);
```
---
## 5. Integración con GRACE
### 5.1 Principio
```
PENNY puede HABLAR GRACE puede PROCESAR
PENNY no puede PROCESAR GRACE no puede HABLAR
Cuando PENNY necesita datos → llama a GRACE con Contrato Común
```
### 5.2 Módulos Invocables
| Módulo | Cuándo |
|--------|--------|
| `FIELD_EXTRACTOR` | "¿Qué dice esta factura?" |
| `SUMMARIZER` | "Resume este documento" |
| `CLASSIFIER` | "¿De qué tipo es este email?" |
| `TASK_DETECTOR` | "¿Qué tareas hay en esta reunión?" |
### 5.3 Formato de Llamada
```json
{
"contract_version": "1.2",
"envelope": {
"trace_id": "penny-trace-uuid",
"parent_trace_id": "sesion-uuid",
"timestamp_init": "2025-12-16T10:26:00Z",
"ttl_ms": 10000
},
"routing": {
"module": "FIELD_EXTRACTOR",
"provider_preference": ["local"]
},
"context": {
"lang": "es",
"caller": "PENNY",
"caller_sesion": "uuid-sesion"
},
"payload": {
"type": "document",
"content_ref": "vault://uploads/factura.pdf"
}
}
```
### 5.4 Flujo Ejemplo
```
Usuario: "¿Qué dice la factura que escaneé ayer?"
1. ASR: Audio → Texto
2. PENNY detecta: necesita GRACE.FIELD_EXTRACTOR
3. PENNY → GRACE (Contrato Común)
4. GRACE responde: { proveedor: "Telefónica", total: 45.90 }
5. PENNY + LLM formula respuesta natural
6. TTS: "La factura es de Telefónica por 45,90 euros"
7. Log registra todo (en DECK)
```
---
## 6. Conversación Natural por Turnos
### 6.1 Turn Detection
```yaml
turn_detection:
vad:
speech_threshold: 0.5
min_speech_ms: 250
min_silence_ms: 700 # Fin de turno
end_of_turn:
confident_silence_ms: 500
uncertain_silence_ms: 1000
max_silence_ms: 2000
barge_in:
enabled: true # Usuario puede interrumpir
min_user_speech_ms: 200
cancel_tts: true
backchanneling:
ignore_patterns: # No son turnos completos
- "^(mhm|sí|ajá|vale|ok)$"
```
### 6.2 Estados
```
IDLE ──────▶ LISTENING ──────▶ PROCESSING ──────▶ SPEAKING
▲ │ │
│ │ (barge-in) │
│ ◀────────────────────────────────────┘
│ │
└───────────────────────────────────────────────────┘
(TTS termina)
```
### 6.3 Feedback
```yaml
feedback:
idle: "azul tenue"
listening: "azul pulsante"
processing: "amarillo"
speaking: "verde"
error: "rojo"
```
---
## 7. Stack Técnico
### 7.1 Componentes de Proceso
| Componente | Función | Latencia Objetivo |
|------------|---------|-------------------|
| VAD | Detecta voz/silencio | <50ms |
| ASR | Audio → Texto | 200-400ms |
| LLM | Genera respuesta | 500ms-2s |
| TTS | Texto → Audio | 200-500ms |
### 7.2 Modelos Recomendados
```yaml
vad:
modelo: silero-vad
version: v5
asr:
modelo: faster-whisper
variantes:
- large-v3 # Máxima calidad
- distil-large-v2 # Balance
- medium # Fallback
llm:
opciones:
- qwen2.5-72b # Máxima calidad
- llama3.1-70b # Alternativa
- mistral-22b # Balance
- qwen2.5-7b # Baja latencia
tts:
modelo: xtts-v2
fallback:
- kokoro-82m
- piper
```
### 7.3 Requisitos GPU (Servidor Proceso)
```yaml
minimo:
vram: 24GB
modelos: whisper-large + llm-7b + xtts
recomendado:
vram: 48GB+
modelos: whisper-large + llm-70b + xtts
distribucion_ejemplo_48gb:
whisper_large: ~3GB
qwen2.5_72b_q4: ~40GB
xtts_v2: ~3GB
buffer: ~2GB
```
### 7.4 Latencias Objetivo
| Componente | Objetivo | Máximo |
|------------|----------|--------|
| VAD | <50ms | 100ms |
| ASR | <400ms | 800ms |
| LLM (primer token) | <500ms | 1500ms |
| TTS (primer audio) | <200ms | 500ms |
| **Total voice-to-voice** | **<2s** | **<4s** |
---
## 8. Protocolo de Comunicación
### 8.1 DECK → Servidor Proceso
```json
{
"type": "session_start",
"session_id": "uuid",
"planos": {
"sistema": { ... },
"personalidad": { ... },
"contexto_personal": { ... },
"contexto_ambiental": { ... }
},
"config": {
"voz_referencia": "base64_audio_6s",
"idioma": "es",
"max_tokens": 150
}
}
```
### 8.2 Audio Streaming
```
DECK ──── WebSocket ────▶ Servidor Proceso
◀─── WebSocket ─────
Formato: PCM 16kHz mono
Chunks: 20ms (320 samples)
```
### 8.3 Servidor Proceso → DECK
```json
{
"type": "turn_complete",
"turno": {
"usuario_texto": "¿Qué tengo pendiente?",
"penny_texto": "Tienes 3 recados...",
"audio_respuesta": "base64...",
"metricas": {
"latencia_asr_ms": 350,
"latencia_llm_ms": 1200,
"latencia_tts_ms": 400,
"tokens_prompt": 850,
"tokens_respuesta": 42
}
}
}
```
---
## 9. Estructura de Proyecto
### 9.1 DECK (Persistencia)
```
/deck/penny/
├── planos/
│ ├── sistema.yaml
│ ├── personalidad.yaml
│ └── usuarios/
│ └── {player_id}.yaml
├── voces/
│ └── penny_base.wav
├── db/
│ └── penny.db
└── config/
└── penny.yaml
```
### 9.2 Servidor Proceso (Stateless)
```
/proceso/
├── models/ # Solo lectura desde almacenamiento
│ ├── whisper/
│ ├── llm/
│ ├── tts/
│ └── vad/
├── engine/
│ ├── vad_processor.py
│ ├── asr_processor.py
│ ├── llm_processor.py
│ ├── tts_processor.py
│ └── pipeline.py
└── server/
├── main.py
└── websocket.py
```
---
## 10. Experiencias Reales
```
"Conseguí ~500ms latencia voice-to-voice con streaming de TTS."
— KoljaB, RealtimeVoiceChat
"En una 4090 con faster-distil-whisper bajamos a 300ms total."
— voicechat2
"XTTS-v2 clone de la voz de mi abuelo me hizo llorar."
— GitHub contributor
"El turn detection es lo más difícil. Silero VAD funciona
pero hay que ajustar los thresholds para cada persona."
— Reddit r/LocalLLaMA
```
---
## Resumen
PENNY es:
- **Voz del DECK** — interfaz hablada natural
- **Proceso remoto stateless** — zero retención, modelos autoalojados
- **Persistencia solo en DECK** — planos, log, datos
- **6 planos** de información cargables independientemente
- **Integración GRACE** via Contrato Común
- **<2 segundos** voice-to-voice objetivo
```
┌────────────────────┐ ┌────────────────────┐
│ SERVIDOR PROCESO │ │ DECK │
│ │ │ │
│ • VAD │◀───────▶│ • Planos │
│ • ASR │ Audio │ • Log │
│ • LLM │ Datos │ • GRACE │
│ • TTS │ │ • Vault │
│ │ │ │
│ ZERO RETENCIÓN │ │ PERSISTENCIA │
└────────────────────┘ └────────────────────┘
```
---
*Diciembre 2025*