ownvoice
Servidor MCP que envuelve la CLI de ownvoice para verificaciones de voz e identidad.
Documentación
OwnVoice
Entrena un adaptador de voz LoRA para pocket-tts y conserva el resultado: un archivo en tu propio disco, no una suscripción a una API.

Instalación
Requiere Python 3.11 o posterior.
pip install ownvoice-cli
Entornos npx / nativos de agentes: OwnVoice es una CLI de Python/PyTorch, por lo que el paquete npm es un envoltorio delgado, no una reimplementación de Node. Arranca en la CLI real a través de uv o pipx, el que ya esté en PATH, útil para entornos sandbox de agentes de código y runners de CI que usan Node por defecto.
npx ownvoice-cli check
Tanto el envoltorio npm como el paquete PyPI (ownvoice-cli) están activos, así que el comando de arriba funciona hoy.
[!NOTE] El paquete npm fue renombrado a
ownvoice-cli(desde el antiguoownvoice, ahora obsoleto) para coincidir con su equivalente en PyPI. Los scripts o agentes que aún usen el nombre anterior deben cambiar aownvoice-cli.
[!TIP]
ownvoice check(ver abajo) no necesita GPU en absoluto y se ejecuta en CPU, coincidiendo con el diseño de pocket-tts que también funciona en CPU. Entrenar un adaptador real es mucho más rápido en una GPU NVIDIA: si tienes una, instala primero la versión CUDA de PyTorch siguiendo pytorch.org/get-started/locally, y luego instala OwnVoice sobre ella, para quepipno baje silenciosamente la versión solo-CPU. En Apple Silicon o en una máquina solo-CPU, lapip installpredeterminada de torch es suficiente:ownvoice checkyownvoice inferfuncionarán con normalidad,ownvoice trainsolo tardará más por época.
Inicio rápido

1. ownvoice check, la validación gratuita del día cero
Antes de grabar cualquier cosa o alquilar una GPU, confirma que la inyección LoRA de PEFT realmente funciona contra la estructura real del modelo de pocket-tts. Esto es completamente gratuito: solo CPU, sin entrenamiento, sin GPU.
$ ownvoice check
[ownvoice check] PASS: PEFT LoRA injection succeeded against pocket-tts's flow_lm module (target_modules="all-linear").
Si falla, OwnVoice imprime el árbol de módulos real del modelo en lugar de un stack trace crudo, para que veas exactamente qué no coincidió y puedas reportarlo con precisión:
$ ownvoice check
[ownvoice check] FAIL: PEFT LoRA injection failed against pocket-tts's flow_lm module structure: <error detail>. Please post an honest blocker (this error plus the module tree above) as a comment on https://github.com/kyutai-labs/pocket-tts/issues/30 rather than working around it silently, that issue is exactly where this gap needs to be visible.
Module tree (for debugging / for the issue #30 blocker post):
<root>: FlowLMModel
input_linear: Linear
transformer: StreamingTransformer
transformer.layers.0.self_attn.in_proj: Linear
transformer.layers.0.self_attn.out_proj: Linear
...
2. ownvoice train
Graba de 5 a 10 minutos de audio limpio de la voz que quieres entrenar (tu propia voz, con tu propio consentimiento, ver Consentimiento y mal uso abajo), divídelo en unos pocos clips de .wav en un directorio, y luego apunta OwnVoice a él:
$ ownvoice train --voice-clips ./my-voice-clips
[ownvoice train] USABLE ADAPTER
Usable adapter (similarity 0.812 >= 0.75). Try it now:
ownvoice infer --adapter ownvoice-adapter/adapter.safetensors --text "This is my own voice, trained with OwnVoice."
Solo se requiere --voice-clips. Todos los demás parámetros tienen un valor predeterminado razonable: --out (./ownvoice-adapter/), --epochs (10), --lora-rank (8), --lora-alpha (16), --lora-dropout (0.05), --learning-rate (1e-4) y --eval-text (la frase sintetizada para calcular la puntuación de similitud).
Una ejecución que termina pero no supera la barra de similitud aún sale con 0. Es un resultado etiquetado con un siguiente paso concreto, no un fallo:
$ ownvoice train --voice-clips ./my-voice-clips
[ownvoice train] BELOW THRESHOLD
Below threshold (similarity 0.612 < 0.75). The adapter was still saved, try more/cleaner voice clips, more epochs, or a higher --lora-rank, then re-run. You can still listen to it:
ownvoice infer --adapter ownvoice-adapter/adapter.safetensors --text "This is my own voice, trained with OwnVoice."
Solo un problema de carga de datos (sin clips utilizables) o una falla de inyección PEFT capturada hacen que el comando salga con código no cero. Cada ejecución exitosa escribe adapter.safetensors y metadata.json (configuración de entrenamiento, la puntuación de similitud, una marca de tiempo) en el directorio de salida: dos archivos que conservas, sin necesidad de ida y vuelta al servidor para usarlos de nuevo.
3. ownvoice infer
$ ownvoice infer --adapter ownvoice-adapter/adapter.safetensors --text "Hello, this is my own voice."
[ownvoice infer] Wrote ownvoice-output.wav
Cada subcomando también admite --json para un modo de salida estructurado y analizable por máquina, útil si un script o un agente llama a ownvoice programáticamente en lugar de que una persona lea la terminal:
$ ownvoice check --json
{"success": true, "message": "PEFT LoRA injection succeeded against pocket-tts's flow_lm module (target_modules=\"all-linear\").", "module_tree": null}

Por qué existe esto
pocket-tts es un modelo local de texto a voz genuinamente bueno, con licencia MIT y capaz de funcionar en CPU, de Kyutai. Sus propios mantenedores han sido claros en que el código de ajuste fino no llegará pronto: en el issue #30, el mantenedor @vvolhejn escribió "No planeamos lanzar código de ajuste fino para nuestros modelos TTS y STT en el futuro cercano", y 18 personas reaccionaron a ese hilo pidiendo exactamente esto. OwnVoice es una CLI pequeña e independiente que llena ese vacío específico: apúntala a un puñado de tus propias grabaciones de voz, y entrenará un adaptador LoRA que conservas y ejecutas tú mismo.
No es un servicio alojado, no tiene facturación y no rastrea el uso. Es un script de entrenamiento, un script de inferencia y un script de puntuación, conectados entre sí mediante tres comandos CLI.
Qué no es OwnVoice
pocket-tts ya incluye clonación de voz zero-shot de serie: pasa un archivo .wav a --voice (o llama a get_state_for_audio_prompt() desde Python) y clona esa voz sin ningún paso de entrenamiento. Si eso es todo lo que necesitas, usa pocket-tts directamente, es más simple y más rápido.
OwnVoice existe para un caso más específico: incorporar una voz permanentemente en pesos entrenados, de modo que la generación ya no dependa de distribuir o reprocesar un clip de audio de referencia en tiempo de ejecución, con (basado en el objetivo de entrenamiento, aún no comparado de forma independiente a escala) una salida más consistente en muchas generaciones que la que tiende a producir una incrustación zero-shot de un solo clip. Ese es el vacío específico que describían los 18 reaccionadores al issue #30, y es lo único que OwnVoice añade sobre lo que pocket-tts ya hace bien.
Cómo funciona
voice clips (wav)
|
v
data.py --validate format/duration--> clean clip set
|
v
train.py --PEFT LoRA (target_modules="all-linear")--> adapter.safetensors + metadata.json
|
v
infer.py --generate test utterance--> synthesized audio
|
v
score.py --resample to 16kHz mono--> Resemblyzer cosine similarity
|
v
CLI report (>= 0.75 = usable adapter, below triggers a labeled next-step message)
ownvoice/data.py carga y valida el directorio de clips de voz. ownvoice/train.py carga el modelo base congelado de pocket-tts, inyecta un adaptador LoRA en su transformer flow_lm con PEFT (target_modules="all-linear"), ejecuta el bucle de entrenamiento y guarda el adaptador más un manifiesto. ownvoice/infer.py carga un adaptador guardado de nuevo sobre el modelo base y genera habla. ownvoice/score.py remuestrea el audio a 16kHz mono con torchaudio.transforms.Resample y puntúa la similitud del hablante con Resemblyzer.
OwnVoice es intencionalmente de un solo modelo: envuelve solo pocket-tts, sin capa de abstracción para un segundo modelo base, ya que ninguno está dentro del alcance.
Consentimiento y mal uso
Esta herramienta clona una voz a partir de audio que tienes derecho a usar. No clones la voz de otra persona, ni la de una figura pública, sin su consentimiento explícito. OwnVoice no incluye ninguna función de generación masiva o autoescalado en esta versión, lo que mantiene pequeño el radio de impacto de cualquier caso individual de mal uso.
Comparativa de tiempo de configuración con herramientas similares
| Herramienta | Tiempo hasta la primera configuración funcional | Decisión de diseño notable | Fuente |
|---|---|---|---|
| kokoro-tts | menos de 2 minutos | pip install git+..., síntesis CLI instantánea, sin ajuste fino | README de kokoro-tts |
| Unsloth | menos de 1 minuto para comenzar una ejecución | inicio de entrenamiento con un solo comando (uv pip install) | docs de Unsloth |
| pocket-tts | segundos | --voice <wav> clonación zero-shot, sin entrenamiento disponible | README de pocket-tts |
| OwnVoice | menos de 2 minutos para un entorno de entrenamiento confirmado y funcional | ownvoice check: validación gratuita, instantánea y solo-CPU de compatibilidad con PEFT antes de gastar en una GPU | este repositorio |
La ejecución de entrenamiento de OwnVoice es tiempo real de GPU, etiquetado honestamente y no oculto tras una barra de progreso falsa, la misma norma de categoría que usa Unsloth. Lo que OwnVoice comprime a menos de dos minutos es todo lo anterior: confirmar que tu entorno realmente funciona.
Estado de implementación
Esta es una versión joven, en etapa temprana. ownvoice check, el análisis de argumentos CLI, la validación de clips de voz, las matemáticas de puntuación de similitud y la ruta de guardado/carga de adaptador y manifiesto están implementados y cubiertos por el conjunto de pruebas (pytest). La inyección LoRA fue verificada estructuralmente contra el código fuente real de pocket-tts y luego confirmada en la práctica: ownvoice check se ejecutó contra los pesos reales descargados de pocket-tts, en CPU, y la inyección target_modules="all-linear" de PEFT realmente tuvo éxito. La ruta completa de entrenamiento y generación se ha verificado de extremo a extremo de verdad: una ejecución real de entrenamiento LoRA de 2 épocas contra los pesos cargados de pocket-tts produjo una pérdida de flow-matching finita y no NaN, y el adaptador resultante produjo un archivo .wav generado real y no silencioso mediante ownvoice infer. Esa validación reveló dos fallos reales en el enfoque ingenuo y los corrigió: (1) el paquete PyPI publicado por pocket-tts, solo para inferencia, no expone realmente una forma de calcular la pérdida de entrenamiento a través de FlowLMModel.forward() a pesar de que su propio docstring afirma lo contrario, por lo que OwnVoice calcula la pérdida de flow-matching directamente desde los submódulos reales de flow_lm; (2) intercambiar base_model.flow_lm por el modelo envuelto con PEFT antes de llamar a generate_audio() rompe la búsqueda del estado de caché KV interno de pocket-tts; no se necesita ningún intercambio, ya que la inyección LoRA de PEFT ya muta base_model.flow_lm en el lugar. Una limitación externa real que debes conocer: los pesos de pocket-tts descargables públicamente (kyutai/pocket-tts-without-voice-cloning) rechazan directamente una ruta/URL de clip de referencia; OwnVoice lo resuelve precargando y remuestreando el clip por sí mismo, pero la fidelidad de clonación de voz desde ese checkpoint es una limitación conocida del modelo base, no un error de OwnVoice; para los pesos de clonación de mejor calidad de Kyutai, solicita acceso restringido en huggingface.co/kyutai/pocket-tts. Ejecuta ownvoice check tú mismo y lee el código fuente antes de confiar más en todo esto, esa es la cantidad correcta de escepticismo para un proyecto tan temprano.
Preguntas frecuentes
¿Qué es OwnVoice y por qué no usar solo pocket-tts?
OwnVoice entrena un adaptador LoRA para pocket-tts y lo guarda en tu propio disco como adapter.safetensors más metadata.json. Existe porque los mantenedores de pocket-tts han dicho que el código de ajuste fino no está en su hoja de ruta a corto plazo (ver issue #30). Una vez que tienes un adaptador entrenado, nunca más necesitas OwnVoice para usarlo: ownvoice infer simplemente carga el adaptador de nuevo sobre el modelo base.
¿En qué se diferencia de la clonación zero-shot --voice <wav> integrada de pocket-tts?
pocket-tts ya clona una voz desde un solo clip de referencia sin paso de entrenamiento, --voice <wav> en la CLI o get_state_for_audio_prompt() en Python. OwnVoice cambia esa velocidad por un adaptador entrenado permanentemente, de modo que la generación ya no depende de llevar un clip de referencia en tiempo de ejecución, con (basado en el objetivo de entrenamiento, aún no comparado de forma independiente a escala) una salida más consistente en generaciones repetidas que la que tiende a dar una incrustación zero-shot de un solo clip. Si el zero-shot es suficiente para tu caso de uso, usa pocket-tts directamente, es más simple y más rápido.
¿Qué necesito para instalarlo y funciona en Apple Silicon o en una máquina solo-CPU?
Python 3.11 o superior, y luego pip install ownvoice-cli. ownvoice check y ownvoice infer no necesitan GPU en absoluto y funcionan bien en Apple Silicon o en una máquina solo-CPU, coincidiendo con el diseño de pocket-tts que también funciona en CPU. ownvoice train también se ejecuta en CPU, solo tarda más por época; instala la versión CUDA de PyTorch primero si tienes una GPU NVIDIA y quieres que el entrenamiento vaya más rápido.
¿Cómo se compara OwnVoice con kokoro-tts y Unsloth?
kokoro-tts te permite sintetizar voz en menos de 2 minutos, pero no tiene ningún paso de ajuste fino. Unsloth logra que una ejecución de entrenamiento comience en menos de un minuto, pero es un framework general de ajuste fino de LLM, no específico de TTS. OwnVoice es más específico que ambos: un solo modelo base (solo pocket-tts), un solo trabajo (un adaptador de voz), más un paso gratuito ownvoice check que confirma que la inyección LoRA de PEFT realmente funciona contra tu entorno antes de que gastes en una GPU, una verificación que ninguna de esas herramientas tiene un equivalente.
Mi ejecución de entrenamiento terminó pero imprimió "BELOW THRESHOLD", ¿es un error?
No. Es un resultado etiquetado, no un fallo, ownvoice train sale con 0 en cualquier caso. Por debajo de la barra de similitud de coseno de 0.75, el adaptador aún se guarda en disco y OwnVoice te dice claramente que pruebes con más clips de voz o más limpios, más épocas, o un --lora-rank más alto, y luego vuelvas a ejecutar. Solo dos cosas hacen fallar el comando con una salida no cero: no hay clips utilizables para cargar, o una falla de inyección PEFT capturada.
¿Puedo usar OwnVoice y los adaptadores que produce con fines comerciales?
El código propio de OwnVoice es MIT (ver LICENSE). El paquete de código de pocket-tts también es MIT, pero los pesos del modelo que OwnVoice realmente descarga y entrena, kyutai/pocket-tts-without-voice-cloning y el gated kyutai/pocket-tts, tienen licencia CC-BY-4.0, no MIT. CC-BY-4.0 permite uso comercial pero requiere atribución a Kyutai. Dado que cualquier adaptador que entrenes se deriva de esos pesos, verifica ese requisito de atribución antes de lanzar un producto comercial basado en él.
¿De quién puedo clonar la voz realmente con esto? Solo de ti mismo, o de alguien más con su consentimiento explícito y verificado, nunca de la voz de una figura pública sin él. Ver Consentimiento y mal uso arriba. OwnVoice no incluye funcionalidad de generación masiva ni autoescalado en esta versión, lo que mantiene pequeño el radio de impacto de cualquier caso aislado de mal uso.
Servidor MCP
OwnVoice incluye un servidor de Model Context Protocol, por lo que un agente compatible con MCP puede ejecutar ownvoice check / train / infer directamente a través de stdio, en lugar de invocar un proceso externo y parsear texto por sí mismo.
pip install "ownvoice-cli[mcp]"
Agrégalo a la configuración de un cliente MCP (por ejemplo, el claude_desktop_config.json de Claude Desktop):
{
"mcpServers": {
"ownvoice": {
"command": "ownvoice-mcp"
}
}
}
El servidor expone una única herramienta, run(args: list[str]) -> dict, que invoca la CLI real de ownvoice con los argv dados y devuelve su resultado como JSON estructurado, de modo que el llamador obtiene exactamente el mismo comportamiento que la CLI orientada a humanos, incluido el modo --json. Ejemplo de llamada: run(args=["check", "--json"]) devuelve {"result": {"success": true, "message": "...", "module_tree": null}}. Una salida con código distinto de cero, un fallo de lanzamiento o un tiempo de espera del subproceso siempre se devuelve como {"error": "..."} en lugar de lanzarse como excepción.
Contribuciones
Se aceptan issues y PRs, todo bajo licencia MIT. Si quieres ayudar a cerrar la brecha real que este proyecto aborda, la contribución más útil es upstream: un script de entrenamiento de adaptadores LoRA ligero y devuelto a kyutai-labs/pocket-tts mismo, discutido en issue #30.
Licencia
MIT. Ver LICENSE.