Modelos de voz a voz

Soniqo admite dos familias de modelos MLX nativos para conversación de voz a voz: PersonaPlex 7B y VoiceChat 11B. Ambos consumen voz y generan directamente el audio del modelo, pero usan arquitecturas dúplex y contratos de runtime distintos.

Elige un modelo

ModeloModelo de conversaciónIdeal para
PersonaPlex 7BFull-duplex simultáneo con Moshi, Depformer y MimiEscucha y habla solapados, con 18 voces seleccionables
VoiceChat 11BDúplex continuo y sincronizado por tramas con FastConformer, Nemotron-H, EAR-TTS y un códec neuronalTramas de streaming de 80 ms, eventos de texto/función y voz nativa del checkpoint

Estos son modelos conversacionales de voz a voz. Hibiki también transforma voz directamente en voz, pero su tarea es la traducción de voz en streaming y se documenta por separado.

PersonaPlex 7B

Modelo de diálogo voz a voz full-duplex basado en la arquitectura Moshi (Kyutai). PersonaPlex 7B genera respuestas habladas directamente a partir de la entrada hablada — sin pipeline intermedio de texto. El modelo incluye 18 presets de voz y está disponible con cuantización de 8 bits (recomendada) y 4 bits. 8 bits es el valor por defecto — es un 30 % más rápido y produce respuestas coherentes, mientras que 4 bits degrada la calidad de la salida.

VoiceChat 11B

Referencia de speech-to-speech dúplex: SALM-Duplex: Efficient and Direct Duplex Modeling for Speech-to-Speech Language Model (Interspeech 2025), citada por la ficha upstream de VoiceChat de NVIDIA.

M5 Pro, 48 GB, Release, cadencia live de 80 ms, INT5 con cabezales protegidos: tres ejecuciones controladas midieron un RTF de la ruta completa de 0.94, 0.92 y 0.92, con unos 8.70 GB de RSS máximo. El primer texto hablado llegó en 44.3–46.7 ms y el primer audio reproducible en 74.0–76.4 ms. Son cifras de cálculo en caliente, no latencia de toma de turno aprendida; el rendimiento INT8 optimizado aún no se ha vuelto a medir.

VoiceChat es el otro runtime nativo MLX de voz a voz de speech-swift. Combina percepción FastConformer causal, canales dúplex de texto/función Nemotron-H, EAR-TTS independiente condicionado por texto y un códec neuronal de 22,05 kHz. La sesión acepta audio mono de 16 kHz de forma continua y devuelve eventos de texto y una trama de salida de 1.764 muestras cada 80 ms.

Carga con VoiceChatModel.load(from:), inicia una VoiceChatSession y envía audio mediante pushAudio. Un bundle completo debe contener encoder/, llm/ y tts/; se rechazan los bundles antiguos de solo comprensión.

Rendimiento actual

INT5 mantiene un rendimiento agregado inferior a RTF 1 en el M5 Pro probado. Las tres ejecuciones también mantuvieron el p95 total por trama por debajo de 80 ms, entre 76.2 y 78.6 ms; por tanto, el margen de plazo sigue siendo estrecho. Mide por separado el inicio del turno del modelo y la latencia de cálculo del hardware.

Arquitectura y uso de PersonaPlex

PersonaPlex es un modelo autorregresivo multi-stream con tres componentes principales:

ComponenteDetalles
Temporal Transformer32 capas, dim=4096, 32 cabezas, SwiGLU (hidden_scale=4.125), RoPE, cuantizado a 8 bits (por defecto)
Depformer6 capas, dim=1024, 16 cabezas, MultiLinear (weights_per_step=true), dep_q=16
Codec Mimi16 codebooks, frame rate de 12.5 Hz, salida de audio a 24 kHz

El modelo procesa 17 streams simultáneamente: 1 stream de texto + 8 streams de audio del usuario + 8 streams de audio del agent. Esta arquitectura permite la conversación full-duplex en la que el modelo puede escuchar y hablar al mismo tiempo.

Presets de voz

PersonaPlex incluye 18 presets de voz integrados con estilos naturales y variados:

CategoríaPresets
Femenino naturalNATF0, NATF1, NATF2, NATF3
Masculino naturalNATM0, NATM1, NATM2, NATM3
Femenino variadoVARF0, VARF1, VARF2, VARF3, VARF4
Masculino variadoVARM0, VARM1, VARM2, VARM3, VARM4

Monólogo interno

PersonaPlex genera dos streams paralelos en cada paso: 8 tokens de codebook de audio para el codec Mimi y un token de texto para el monólogo interno del modelo. El stream de texto es lo que el modelo está “pensando” mientras habla — puede divergir ligeramente del audio final, pero en la práctica refleja la respuesta hablada con suficiente fidelidad como para usarlo como transcripción en vivo.

Los tokens de texto se devuelven como IDs de piezas SentencePiece en crudo. Decodifícalos con el SentencePieceDecoder que incluye PersonaPlex:

import PersonaPlex
import AudioCommon

let model = try await PersonaPlexModel.fromPretrained()
let decoder = model.tokenizer  // SentencePieceDecoder?

let result = model.respond(userAudio: userSamples, voice: .NATM0)
let transcript = decoder?.decode(result.textTokens) ?? ""
print(transcript)        // "Sure, I can help with that..."
playAudio(result.audio)  // 24 kHz mono Float32

En modo streaming, respondStream emite chunks de textTokens según se van produciendo — decodifícalos de forma incremental para alimentar una vista de subtítulos en vivo mientras el audio sigue generándose. El flag --transcript de la CLI hace exactamente esto por detrás.

Por qué importa: SentencePieceDecoder está construido sobre el lector de protobuf compartido AudioCommon.SentencePieceModel, así que PersonaPlex, OmnilingualASR y cualquier futuro modelo basado en SentencePiece decodifican a través de la misma implementación del tokenizador. Consulta la referencia de SentencePieceModel.

Prompts del sistema

Pasa cualquier prompt del sistema personalizado como una simple cadena de texto — no hace falta tokenización externa:

let response = model.respond(
    userAudio: audio,
    voice: .NATM0,
    systemPrompt: "You enjoy having a good conversation."
)

O usa un preset integrado:

Uso de la CLI

Genera una respuesta hablada a partir de una entrada de audio:

# Basic speech-to-speech
.build/release/speech respond --input question.wav

# Choose a voice preset
.build/release/speech respond --input question.wav --voice NATM0

# Stream audio output during generation
.build/release/speech respond --input question.wav --stream

# Custom system prompt text
.build/release/speech respond --input question.wav --system-prompt-text "You enjoy having a good conversation."

# Use a preset system prompt
.build/release/speech respond --input question.wav --system-prompt customer-service

# Get transcript alongside audio
.build/release/speech respond --input question.wav --transcript

# JSON output with metadata
.build/release/speech respond --input question.wav --json

Opciones

OpciónDescripción
--inputArchivo de audio de entrada (WAV, obligatorio)
--voiceNombre del preset de voz (p. ej., NATM0, VARF2)
--system-promptPreset de prompt del sistema: assistant, focused, customer-service, teacher
--system-prompt-textTexto personalizado del prompt del sistema (sobrescribe --system-prompt)
--max-stepsPasos máximos de generación
--streamEmite chunks de audio durante la generación
--compileUsa inferencia compilada de MLX para una generación más rápida
--transcriptEmite la transcripción de texto junto al audio
--jsonSalida JSON con metadatos

Los parámetros de sampling también se pueden sobrescribir:

OpciónPor defectoDescripción
--audio-temp0.8Temperatura de sampling de tokens de audio
--audio-top-k250Top-k sampling para tokens de audio
--text-temp0.7Temperatura de sampling de tokens de texto
--text-top-k25Top-k sampling para tokens de texto

Streaming

El flag --stream activa la salida de audio en tiempo real. Los chunks de audio se emiten conforme se generan, por lo que la reproducción puede comenzar antes de que la respuesta completa esté lista. Esto resulta especialmente útil para aplicaciones interactivas donde la baja latencia importa.

Rendimiento

MétricaValor
Factor de tiempo real (RTF)~1.4 (8 bits, casi en tiempo real)
Latencia por paso~112 ms/paso en M2 Max (8 bits)
Tamaño del modelo (8 bits)~9.1 GB
RAM máxima (8 bits)~11 GB
Tamaño del modelo (4 bits)~4.9 GB
RAM máxima (4 bits)~7 GB
Importante

PersonaPlex 7B (8 bits) requiere al menos 24 GB de RAM. La variante de 4 bits cabe en dispositivos con 16 GB pero produce una salida degradada. En dispositivos con 8 GB no cabe ninguna de las variantes. Usa --compile para obtener el mejor rendimiento en el hardware compatible.

Variantes del modelo

ModeloTamañoHuggingFace
PersonaPlex-7B (8 bits) recomendado9.1 GBaufklarer/PersonaPlex-7B-MLX-8bit
PersonaPlex-7B (4 bits)4.9 GBaufklarer/PersonaPlex-7B-MLX-4bit

API de Swift

import PersonaPlex
import AudioCommon

let model = try await PersonaPlexModel.fromPretrained()
let response = model.respond(
    userAudio: userSamples,
    voice: .NATM0,
    systemPrompt: "You are a helpful assistant."
)
try WAVWriter.write(samples: response.audio, sampleRate: 24000, to: URL(filePath: "answer.wav"))