Whisper e Piper em uma VPS sem GPU
Execute Whisper e Piper em uma VPS comum, saiba quanto gastam de CPU e disco e exponha uma API compatível com OpenAI para seus clientes.
Conversão de voz para texto e TTS autoalojados, em resumo
A conversão de voz para texto e o TTS (text to speech) autoalojados são o tipo mais barato de IA que pode executar num servidor seu. A transcrição usa o Whisper através do runtime faster-whisper. A síntese usa o Piper. Ambos funcionam numa VPS com CPU comum, sem qualquer GPU. O modelo Whisper pequeno precisa de cerca de 484 MB de espaço em disco, e uma voz do Piper é um único ficheiro com bem menos de 150 MB.
Por isso, o áudio é o ponto de partida. Um gerador de imagens autoalojado e a geração de vídeo autoalojada precisam de uma GPU antes de serem utilizáveis. O áudio não.
Este guia aborda as duas direções e a camada que as liga. O Whisper converte áudio em texto. O Piper converte texto em áudio. Um servidor HTTP compatível com OpenAI à frente de ambos permite apontar um cliente existente para o seu servidor, alterando apenas a URL base.
Todas as versões indicadas aqui eram atuais em agosto de 2026.
Por que faster-whisper, e não o pacote de referência Whisper
O pacote whisper da OpenAI executa o modelo em PyTorch. O faster-whisper executa os mesmos pesos do modelo no CTranslate2, um mecanismo de inferência desenvolvido especificamente para modelos transformer. Os pesos são idênticos, portanto a transcrição também é idêntica. A diferença está exclusivamente no ambiente de execução.
O CTranslate2 quantiza os pesos durante o carregamento. Por isso, compute_type="int8" é um único argumento, e não uma etapa de conversão separada. Ele também não depende do PyTorch. pip install faster-whisper instala o CTranslate2, um tokenizer e o PyAV para descodificação de áudio. Assim, o ambiente virtual ocupa algumas centenas de megabytes, em vez de vários gigabytes. Num VPS com um disco de 40 GB, essa diferença separa uma instalação confortável de uma instalação apertada.
Estes são os números publicados pelo próprio projeto para o modelo small em CPU. O benchmark transcreve 13 minutos de áudio usando 8 threads num Intel Core i7-12700K. A coluna x_realtime corresponde a esses 13 minutos divididos pelo tempo medido: 7.6 significa que uma gravação de 13 minutos terminou em pouco mais de 1 minuto e 40 segundos.
The data behind this chart
[
{
"label": "openai/whisper, fp32",
"x_realtime": 1.9,
"seconds": 418,
"memory_mb": "2,335"
},
{
"label": "whisper.cpp, fp32",
"x_realtime": 6.2,
"seconds": 125,
"memory_mb": "1,049"
},
{
"label": "faster-whisper, fp32",
"x_realtime": 5.0,
"seconds": 157,
"memory_mb": "2,257"
},
{
"label": "faster-whisper, int8",
"x_realtime": 7.6,
"seconds": 102,
"memory_mb": "1,477"
},
{
"label": "faster-whisper, int8, batch 8",
"x_realtime": 15.3,
"seconds": 51,
"memory_mb": "3,608"
}
]Leia a segunda linha com atenção. Em fp32, o whisper.cpp é mais rápido do que o faster-whisper nesta CPU: 6.2x contra 5.0x. Além disso, usa menos de metade da memória. É a mesma família ggml usada pelo componente llama.cpp da stack de LLM local. O faster-whisper torna-se mais rápido quando int8 e o processamento em lotes estão ativados, chegando a 15.3x, e usa 3,608 MB de RAM para isso. Portanto: escolha o faster-whisper para a API Python e o processamento em lotes; escolha o whisper.cpp quando a RAM for a limitação que não pode ultrapassar.
A primeira linha é o ponto central desta secção. O pacote de referência atinge 1.9x do tempo real na mesma máquina. Isso significa que uma hora de áudio demora meia hora de CPU.
Quanto espaço em disco ocupam os pesos dos modelos Whisper?
The data behind this chart
[
{
"label": "tiny",
"weights_mb": 75.5
},
{
"label": "base",
"weights_mb": 145
},
{
"label": "small",
"weights_mb": 484
},
{
"label": "medium",
"weights_mb": "1,530"
},
{
"label": "large-v3",
"weights_mb": "3,090"
}
]Estas são as conversões publicadas pelo CTranslate2, em float16. Tenha em atenção o que compute_type="int8" não faz: não reduz o tamanho do download. Os pesos são obtidos em float16, e o CTranslate2 quantiza-os na memória no momento do carregamento. Por isso, large-v3 ocupa 3,090 MB em disco, quer seja executado em float16, quer em int8. int8 reduz o uso de RAM e aumenta a velocidade, mas não reduz o espaço em disco.
Os modelos são descarregados na primeira utilização para ~/.cache/huggingface/hub. Num VPS com um volume raiz pequeno, indique um local com espaço suficiente utilizando o argumento download_root ou a variável de ambiente HF_HOME. Caso contrário, a primeira execução pode encher o disco e o processo termina a meio do download.
Instalar faster-whisper sem quebrar o Python do sistema
Ubuntu 24.04 e Debian 13 marcam o Python do sistema como gerido externamente. Executar pip install faster-whisper fora de um ambiente virtual termina imediatamente com:
error: externally-managed-environmentEsse é o sistema de pacotes a proteger os ficheiros que apt gere. Use um ambiente virtual.
sudo apt update
sudo apt install -y python3-venv ffmpeg
python3 -m venv ~/stt
~/stt/bin/pip install --upgrade pip
~/stt/bin/pip install faster-whisper==1.2.1A versão 1.2.1 é a versão atual, publicada em outubro de 2025. faster-whisper descodifica áudio através do PyAV, que inclui as suas próprias bibliotecas ffmpeg. Por isso, lê um mp3 ou m4a sem um binário ffmpeg separado. O pacote ffmpeg acima é usado para o processamento de vídeo mais adiante neste guia.
Verifique a instalação antes de descarregar três gigabytes de pesos:
~/stt/bin/python -c "from faster_whisper import WhisperModel; print('ok')"Uma linha com ok significa que os wheels foram instalados. Um ImportError com o nome ctranslate2 significa que o wheel para a sua arquitetura não foi instalado. Isto acontece em imagens ARM de 32 bits.
Transcrever uma gravação de reunião ou uma nota de voz
Guarde isto como transcribe.py:
from faster_whisper import WhisperModel
model = WhisperModel("small", device="cpu", compute_type="int8", cpu_threads=4)
segments, info = model.transcribe("meeting.m4a", beam_size=5, vad_filter=True)
print("language: %s (%.2f)" % (info.language, info.language_probability))
for segment in segments:
print("[%.2fs -> %.2fs] %s" % (segment.start, segment.end, segment.text))Execute-o com ~/stt/bin/python transcribe.py. Na primeira execução, os pesos são transferidos, por isso nada é apresentado durante algum tempo. Depois disso, o modelo é carregado da cache em poucos segundos.
segments é um gerador, por isso a transcrição só começa quando faz iteração sobre ele. É comum medir a chamada transcribe(), verificar que ela retorna imediatamente e concluir que algo está errado. Nada está errado. O processamento ocorre no loop.
vad_filter=True executa primeiro o Silero VAD (deteção de atividade vocal) e remove os trechos silenciosos antes de o Whisper os processar. Numa gravação de reunião com pausas longas, este é o maior ganho de velocidade isolado disponível, porque o Whisper não perde tempo com áudio sem fala. Isto também reduz os loops de frases repetidas que o Whisper produz quando recebe silêncio e tenta encontrar palavras nele.
Defina cpu_threads como o número de cores que realmente tem. Defini-lo acima do número de vCPUs torna a transcrição mais lenta, porque as threads adicionais competem pelo mesmo core e o scheduler paga o custo de cada troca.
Legendas para uma biblioteca Jellyfin
O Jellyfin lê ficheiros de legendas externos colocados junto do vídeo e com o mesmo nome. Assim, Movie (2019).en.srt junto de Movie (2019).mkv aparece como uma faixa em inglês, sem transcodificação nem reconstrução da biblioteca.
Extraia primeiro o áudio. O Whisper reamostra tudo internamente para mono a 16 kHz. Fornecer-lhe áudio mono a 16 kHz evita trabalho em ambas as extremidades:
ffmpeg -i "Movie (2019).mkv" -vn -ac 1 -ar 16000 -c:a pcm_s16le "Movie (2019).wav"O faster-whisper não inclui um gravador de SRT, por isso formate os segmentos manualmente. Guarde isto como srt.py:
import sys
from faster_whisper import WhisperModel
def ts(seconds):
ms = int(round(seconds * 1000))
hours, ms = divmod(ms, 3600000)
minutes, ms = divmod(ms, 60000)
secs, ms = divmod(ms, 1000)
return "%02d:%02d:%02d,%03d" % (hours, minutes, secs, ms)
model = WhisperModel("small", device="cpu", compute_type="int8")
segments, info = model.transcribe(sys.argv[1], vad_filter=True)
with open(sys.argv[2], "w", encoding="utf-8") as out:
for index, segment in enumerate(segments, start=1):
out.write("%d\n" % index)
out.write("%s --> %s\n" % (ts(segment.start), ts(segment.end)))
out.write("%s\n\n" % segment.text.strip())Depois percorra a biblioteca:
for f in /srv/media/films/*.mkv; do
ffmpeg -nostdin -y -i "$f" -vn -ac 1 -ar 16000 -c:a pcm_s16le "${f%.mkv}.wav"
nice -n 15 ~/stt/bin/python srt.py "${f%.mkv}.wav" "${f%.mkv}.en.srt"
rm -f "${f%.mkv}.wav"
done-nostdin não é decorativo. Sem essa opção, o ffmpeg lê da entrada padrão do loop, consome o resto da lista de ficheiros e o loop termina depois de um filme, sem apresentar uma mensagem de erro.
Calcule o tempo necessário antes de começar. À velocidade de 7.6x indicada acima, um filme de 100 minutos precisa de aproximadamente 13 minutos de CPU. Uma biblioteca com cinquenta filmes será, portanto, uma tarefa para executar durante a noite. Num plano com vCPU partilhada, o processo será ainda mais lento. É para isso que serve nice: a geração das legendas cede então recursos às restantes tarefas executadas pelo servidor.
Síntese de voz com Piper
Piper é um motor neuronal de síntese de voz que executa um modelo de voz ONNX na CPU. Inclui o espeak-ng para converter texto em fonemas, portanto não é necessário instalar um fonemizador separado. A versão atual é a 1.6.0, publicada em julho de 2026.
python3 -m venv ~/tts
~/tts/bin/pip install piper-tts==1.6.0
~/tts/bin/python -m piper.download_voices en_US-lessac-medium
~/tts/bin/python -m piper -m en_US-lessac-medium -f test.wav -- 'This is a test.'download_voices escreve dois ficheiros no diretório de trabalho: os pesos .onnx e uma configuração .onnx.json que contém a taxa de amostragem e a lista de oradores. Estes ficheiros têm de permanecer juntos. Se guardar as vozes num local fixo, passe --data-dir aos dois comandos, porque, caso contrário, o reprodutor procura no diretório de trabalho e não encontra uma voz que não esteja nesse diretório.
O -- antes do texto também é importante. Sem ele, qualquer frase que comece por um hífen é interpretada como uma opção da linha de comandos.
As vozes são disponibilizadas com vários níveis de qualidade. Uma voz inglesa de qualidade média ocupa aproximadamente 60 MB, e uma de qualidade elevada ocupa cerca do dobro. Uma qualidade superior significa um modelo maior e mais CPU por segundo de fala, não um orador diferente.
Não invoque a CLI num ciclo. O modelo é carregado em cada invocação, e o carregamento do modelo domina o custo de uma frase curta. Execute antes o servidor HTTP:
~/tts/bin/pip install 'piper-tts[http]==1.6.0'
~/tts/bin/python -m piper.http_server -m en_US-lessac-medium --host 127.0.0.1 --port 5000curl -X POST -H 'Content-Type: application/json' \
-d '{ "text": "This is a test." }' \
-o test.wav localhost:5000/synthesizeSe conseguir reproduzir um test.wav, significa que funciona. Esse endpoint segue o formato próprio do Piper, não o da OpenAI, por isso um cliente que espere /v1/audio/speech não conseguirá comunicar com ele. A próxima secção corrige isso.
Mantenha-o em execução com um ficheiro de unidade, em vez de usar um terminal que vai fechar:
[Unit]
Description=Piper text to speech HTTP server
After=network-online.target
[Service]
User=piper
ExecStart=/home/piper/tts/bin/python -m piper.http_server -m en_US-lessac-medium --data-dir /home/piper/voices --host 127.0.0.1 --port 5000
Restart=on-failure
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now piper inicia-o e volta a iniciá-lo depois de um reboot. Se o curl acima não devolver nada, journalctl -u piper -n 50 contém o motivo. Um ficheiro de voz em falta é a causa mais habitual.
O formato de servidor compatível com OpenAI
A maioria dos softwares que processam áudio já fala a API de áudio da OpenAI: um POST multipart para /v1/audio/transcriptions para enviar um ficheiro e um POST JSON para /v1/audio/speech para enviar uma frase. Sirva esses dois caminhos diretamente e o cliente só precisa de uma alteração: o URL base.
Speaches é um servidor que suporta as duas direções. Executa faster-whisper para transcrição e Piper ou Kokoro para síntese de voz, através dos caminhos da OpenAI. A versão atual é v0.9.0-rc.3, de December 2025. O projeto ainda está antes da versão 1.0. Por isso, fixe a tag da imagem e leia as notas de versão antes de atualizar.
curl --silent --remote-name https://raw.githubusercontent.com/speaches-ai/speaches/master/compose.yaml
curl --silent --remote-name https://raw.githubusercontent.com/speaches-ai/speaches/master/compose.cpu.yaml
export COMPOSE_FILE=compose.cpu.yaml
docker compose up --detachA forma com um único contentor, se preferir não manter ficheiros compose:
docker run --rm --detach --publish 8000:8000 --name speaches \
--volume hf-hub-cache:/home/ubuntu/.cache/huggingface/hub \
ghcr.io/speaches-ai/speaches:latest-cpuO volume nomeado é a parte que muitas pessoas esquecem. Sem ele, a cache dos modelos fica dentro do contentor. Assim, cada reinício volta a descarregar gigabytes de pesos antes de responder ao primeiro pedido.
A síntese de voz precisa de uma voz descarregada antes de /v1/audio/speech responder:
uvx speaches-cli model download speaches-ai/Kokoro-82M-v1.0-ONNXDepois disso, qualquer cliente OpenAI funciona se alterar o URL base:
from pathlib import Path
from openai import OpenAI
openai = OpenAI(base_url="http://localhost:8000/v1", api_key="cant-be-empty")
res = openai.audio.speech.create(
model="speaches-ai/Kokoro-82M-v1.0-ONNX",
voice="af_heart",
input="Hello, world!",
response_format="mp3",
speed=1,
)
with Path("output.mp3").open("wb") as f:
f.write(res.response.read())O marcador api_key é obrigatório porque a biblioteca cliente da OpenAI recusa enviar um pedido sem ele. O servidor ignora o respetivo valor até configurar uma chave real.
vox-box é o outro projeto que merece ser mencionado. É um pacote Python, não um contentor, e serve os mesmos caminhos com Whisper, FunASR, Bark, Dia ou CosyVoice. A versão atual é 0.0.21, de December 2025, e requer Python 3.10 ou superior.
python3 -m venv ~/voice
~/voice/bin/pip install vox-box==0.0.21
~/voice/bin/vox-box start --huggingface-repo-id Systran/faster-whisper-small \
--data-dir ~/voice/data --host 127.0.0.1 --port 8010O exemplo do próprio projeto associa-se à porta 80, o que requer root. Num servidor que execute outros serviços, é preferível usar uma porta alta atrás de um reverse proxy. vox-box start aceita um único modelo. Para suportar as duas direções, é necessária uma segunda instância numa segunda porta, com um repo id de voz.
Consulte o servidor para saber o que foi carregado e use esse id no campo model:
curl http://127.0.0.1:8010/v1/modelscurl http://127.0.0.1:8010/v1/audio/transcriptions \
-H "Content-Type: multipart/form-data" \
-F file="@voice-note.m4a" \
-F model="faster-whisper-small"Um corpo JSON no formato {"text": "..."} significa que todo o caminho funciona. Um 404 para o nome do modelo significa que o nome foi presumido em vez de ser obtido na saída de /v1/models.
Nenhum destes servidores ativa a autenticação por predefinição. Associe-os a 127.0.0.1 e aceda-lhes através de uma VPN ou de um reverse proxy que solicite credenciais. Um /v1/audio/transcriptions aberto num IP público oferece CPU gratuita a quem o encontrar, e será encontrado.
Uma interface de voz para um assistente autoalojado
Quando ambos os sentidos respondem através de endpoints OpenAI, uma interface de chat pode controlá-los. O Open WebUI e as respetivas alternativas aceitam um URL base compatível com OpenAI para o áudio nas definições, pelo que uma única máquina pode executar um LLM local com Ollama e fechar o circuito de voz em ambas as extremidades.
Faça uma estimativa realista da latência, porque estes três passos são executados sequencialmente nos mesmos núcleos. Uma pergunta de 10 segundos demora cerca de 1.3 segundos a transcrever no valor de 7.6x indicado acima, antes de o modelo ler um único token. Some a geração de tokens no CPU e o tempo total é suficientemente elevado para os testadores assumirem que o serviço falhou. A transcrição em lote é confortável no CPU. A conversação não é, e é neste ponto que um VPS com GPU começa a justificar o preço.
Quando a GPU realmente vale a pena?
The data behind this chart
[
{
"label": "openai/whisper, fp16",
"x_realtime": 5.5,
"seconds": 143,
"memory_mb": "4,708"
},
{
"label": "faster-whisper, fp16",
"x_realtime": 12.4,
"seconds": 63,
"memory_mb": "4,525"
},
{
"label": "faster-whisper, int8",
"x_realtime": 13.2,
"seconds": 59,
"memory_mb": "2,926"
},
{
"label": "faster-whisper, int8, batch 8",
"x_realtime": 48.8,
"seconds": 16,
"memory_mb": "4,500"
}
]Na GPU, o modelo grande em int8 funciona a 13.2x do tempo real e ocupa 2,926 MB de VRAM. Com processamento em lote, chega a 48.8x. Observe com atenção o que os dois gráficos não mostram. Eles usam modelos diferentes: as linhas da GPU usam large-v2 e as linhas da CPU usam small. A GPU não torna o modelo small seis vezes mais rápido. Ela torna o modelo mais preciso utilizável.
De onde vêm estes números
Ambos os gráficos reproduzem o benchmark publicado no README do faster-whisper. O áudio é um único ficheiro de 13 minutos. As linhas da CPU usaram 8 threads num Intel Core i7-12700K, e as linhas da GPU usaram CUDA 12.4 numa NVIDIA RTX 3070 Ti com 8 GB de VRAM. As colunas de segundos e memória contêm os valores publicados. A coluna x_realtime é calculada a partir deles: 780 segundos de áudio divididos pelo tempo medido, arredondados para uma casa decimal. A coluna de memória corresponde à RAM do sistema no gráfico da CPU e à VRAM no gráfico da GPU.
Um plano partilhado de vCPU não atingirá os valores da CPU. Esse benchmark tinha 8 threads de um processador de desktop rápido exclusivamente disponíveis. Considere 7.6x um limite superior e meça o seu próprio servidor com time numa gravação real antes de planear qualquer coisa com base nesse valor.
Quatro regras práticas que se confirmam no uso real:
- Transcrição ocasional das suas próprias gravações: CPU, small, int8. Duas vCPU dedicadas são suficientes.
- Processamento em lote durante a noite, como a geração de legendas: CPU, small ou medium, int8, executado com
nice. - Qualquer tarefa interativa ou o processamento de uma biblioteca inteira numa só noite: GPU.
- Piper: CPU, sempre. Um modelo de voz deste tamanho quase não beneficia de uma GPU.
Se estiver a avaliar que outras cargas o mesmo hardware pode suportar, a questão mais abrangente sobre que modelos de IA pode alojar localmente aborda os tamanhos que cabem e os que não cabem.
Modos de falha e as mensagens que verá
error: externally-managed-environment durante a instalação. O Python do sistema está protegido pela distribuição. Crie um ambiente virtual como mostrado acima.
Incompatibilidade do cuDNN num servidor com GPU. A falha aparece assim:
Unable to load any of {libcudnn_ops.so.9.1.0, libcudnn_ops.so.9.1, libcudnn_ops.so.9, libcudnn_ops.so}
Invalid handle. Cannot load symbol cudnnCreateTensorDescriptorO CTranslate2 4.5.0 e versões posteriores exigem cuDNN 9 para CUDA 12, mas o host tem cuDNN 8. Instale cuDNN 9 ou fixe o runtime mais antigo com pip install --force-reinstall ctranslate2==4.4.0. Faça apenas uma das duas opções. Fazer ambas deixa-o na situação inicial.
This CTranslate2 package was not compiled with CUDA support é uma falha diferente, com um comportamento semelhante. O wheel instalado é a compilação apenas para CPU. Recrie o ambiente virtual no host com GPU e deixe o pip escolher novamente o wheel.
Frases repetidas na transcrição. Uma frase repetida dez vezes é quase sempre silêncio ou música a ser descodificada como fala. Ative primeiro vad_filter=True. Se o problema persistir, ouça o segmento: áudio quase silencioso não fornece ao Whisper informação suficiente para se orientar, e ele repete a última hipótese em que teve confiança.
Idioma detetado incorretamente. O Whisper faz a estimativa apenas com base nos primeiros 30 segundos. Um info.language_probability muito abaixo de 1.0 significa que não teve confiança, o que acontece quando a gravação começa com música ou com vozes sobrepostas. Passe language="en" quando já souber a resposta.
O processo apresenta Killed e termina. Esse é o mecanismo do kernel que termina processos por falta de memória, e dmesg apresentará a linha oom-kill correspondente. O large-v3 precisa de mais de 3 GB apenas para os pesos, antes de qualquer memória de trabalho. Numa VPS de 2 GB, small com int8 é o maior modelo que cabe.
O Piper não encontra a voz. O player procura no diretório de trabalho, a menos que passe --data-dir. Execute ls no diretório esperado e confirme que .onnx e .onnx.json estão ambos presentes, porque a ausência de qualquer um deles causa falha, tal como a ausência dos dois.
FAQ
Posso executar conversão de voz para texto numa VPS apenas com CPU?
Sim. Para processamento em lote, é a opção mais sensata. Com faster-whisper e o modelo small em int8, o benchmark publicado pelo projeto converte 13 minutos de áudio em 102 segundos usando 8 threads de um i7 de desktop, cerca de 7.6x do tempo real, com 1,477 MB de RAM. Um plano com vCPU partilhada é mais lento do que isso, por isso meça o seu próprio servidor. A conversão de texto para voz com Piper é ainda mais simples e não precisa de GPU em nenhuma circunstância.
Que tamanho de modelo Whisper devo usar?
Comece com small em int8. Ocupa 484 MB em disco e lida bem com voz gravada e nítida. Passe para medium quando os sotaques ou o ruído de fundo causarem erros que não possa aceitar. Use large-v3 apenas quando a precisão for mais importante do que tudo o resto, porque requer 3,090 MB de disco e mais de 3 GB de memória. No sentido oposto, tiny, com 75.5 MB, é útil para detetar o idioma e testar um pipeline, mas não para transcrições que uma pessoa vá ler.
Por que o faster-whisper é mais rápido do que o pacote Whisper original?
O modelo é o mesmo. O runtime não é. O pacote de referência executa o Whisper em PyTorch, enquanto o faster-whisper executa os mesmos pesos em CTranslate2, um motor criado para inferência de transformers que quantiza os pesos durante o carregamento e não precisa de uma instalação do PyTorch. No benchmark de CPU publicado, isso corresponde a 1.9x do tempo real para o pacote de referência, contra 7.6x para o faster-whisper em int8, com menor utilização de memória.
Por que a minha transcrição repete a mesma frase continuamente?
O Whisper está a interpretar silêncio ou música como voz e a reutilizar a sua última previsão com elevada confiança. Defina vad_filter=True na chamada transcribe(). Essa opção executa primeiro a deteção de atividade vocal do Silero e remove os trechos silenciosos antes de o modelo os processar. Se continuar a repetir, verifique o nível de áudio. Uma gravação praticamente silenciosa do princípio ao fim não fornece informação suficiente ao modelo.
Como obtenho um endpoint de áudio compatível com OpenAI no meu próprio servidor?
Execute um servidor que implemente POST /v1/audio/transcriptions e POST /v1/audio/speech. Depois, indique esse servidor ao cliente através de uma nova URL base. Speaches é uma opção. É publicado como uma imagem de container com uma build para CPU e usa faster-whisper para transcrição e Piper ou Kokoro para síntese de voz. vox-box é outra opção. Instale-o com pip install vox-box e inicie-o com vox-box start --huggingface-repo-id. Ele disponibiliza um modelo por processo. Nenhuma das opções ativa autenticação por predefinição. Por isso, faça o bind em localhost e coloque um proxy ou uma VPN à frente.