Clonar voz por API, com IA local na sua VPS
Olá meus Unicórnios! 🦄✨
A nossa IA local já lê, já ouve e já fala. Hoje ela vai falar com a sua voz. 🎭
Clonagem de voz é isso: você grava meio minuto falando, e a partir dali o programa lê qualquer texto com o seu timbre. Serve para narrar um artigo sem gravar nada, para dar uma voz constante a um assistente, ou para gerar cem áudios iguais sem passar cem vezes pelo microfone. 🎙️
E, como sempre nesta série, tudo roda no seu servidor. 🏠 Isso importa mais aqui do que em qualquer artigo anterior: nos sites de clonagem online, o arquivo que você envia é a sua voz, e ela fica guardada numa máquina que não é sua, sob regras que você não escolheu. Aqui ela nunca sai de casa.
O caminho é curto: instalar, gravar a amostra, cadastrar por API e usar. Vamos por partes. 🚀
🎯 Por que este e não outro
Existem vários programas que clonam voz e rodam na sua máquina. A maioria tem o mesmo defeito, e ele só aparece quando você já instalou: não dá para cadastrar uma voz por API. Você tem que copiar o arquivo para uma pasta do servidor e editar um arquivo de configuração à mão, toda vez.
Para uma voz só, tudo bem. Para um sistema que cadastra voz sozinho, é o fim da linha: seu programa teria que abrir conexão de arquivo com o servidor e reescrever configuração, o que ninguém quer fazer.
O Chatterbox resolve isso. Ele trata voz como recurso da API, com o ciclo de vida inteiro em HTTP:
| O que você quer | Rota |
|---|---|
| Cadastrar uma voz | POST /voices |
| Ver as vozes cadastradas | GET /voices |
| Renomear | PUT /voices/{nome} |
| Apagar | DELETE /voices/{nome} |
| Definir a voz padrão | POST /voices/default |
| Gerar o áudio | POST /v1/audio/speech |
Repare que não há nenhuma linha dizendo "edite o arquivo tal". É tudo curl. 🎯
📦 Instalando
Diferente dos outros artigos da série, aqui não tem imagem pronta para baixar: a gente clona o projeto e monta a imagem na hora. O git clone traz o código, e o --depth 1 pega só a versão atual em vez do histórico inteiro (baixa bem menos):
cd /opt
git clone --depth 1 https://github.com/travisvn/chatterbox-tts-api.git chatterbox-api
O projeto traz vários arquivos de configuração, um para cada tipo de máquina. O que interessa é o de CPU, porque a nossa VPS não tem placa de vídeo:
cd /opt/chatterbox-api/docker
ls docker-compose*
Antes de subir, vale trocar uma linha por segurança. Abra o arquivo com o nano, que é o editor de texto mais simples do Linux:
nano docker-compose.cpu.yml
Se você nunca usou o nano: ele abre o arquivo direto na tela, você digita como num bloco de notas, e os comandos ficam no rodapé. Ctrl+O e Enter gravam, Ctrl+X fecha. Aqueles ^O e ^X do rodapé são esses mesmos comandos: o acento circunflexo quer dizer "Ctrl". E para colar no terminal use Ctrl+Shift+V, porque o Ctrl+V comum não funciona. 📋
Ache a linha da porta, que vem assim:
- '${PORT:-4123}:${PORT:-4123}'
E deixe assim:
- '172.17.0.1:4123:4123'
Essa mudança é pequena e importante. Do jeito original, a porta fica aberta para a internet inteira, e o servidor não tem senha nenhuma: quem achar o endereço gera áudio de graça na sua máquina. Com o 172.17.0.1 na frente, ele só responde para a rede interna do Docker. É a mesma decisão que a gente tomou com o Ollama, no primeiro artigo da série. 🔒
Agora monte a imagem. Esse comando lê o projeto, baixa as dependências e monta tudo:
docker compose -f docker-compose.cpu.yml build
Vá tomar um café. Vários. ☕ Isso demora bastante, porque ele compila o programa e baixa as bibliotecas de inteligência artificial. A imagem final fica com 7,55 GB.
Boa parte desse tamanho é gordura: mesmo sendo a versão de CPU, as bibliotecas trazem junto os pacotes de placa de vídeo da NVIDIA, que não vão ser usados. Não quebra nada, só ocupa disco.
Com a imagem pronta, suba o serviço. O -d deixa ele rodando em segundo plano:
docker compose -f docker-compose.cpu.yml up -d
🩺 Esperando ficar pronto
O serviço sobe rápido, mas ele ainda precisa baixar o modelo de voz antes de funcionar. Existe uma rota só para você saber em que pé está:
curl -s http://172.17.0.1:4123/health
Enquanto está baixando, a resposta diz isto:
{
"status": "initializing",
"model_loaded": false,
"initialization_progress": "Loading TTS model (this may take a while)..."
}
Espere até virar isto, que é o sinal verde:
{
"status": "healthy",
"model_loaded": true,
"device": "cpu"
}
Repare no "device": "cpu". É a confirmação de que ele está rodando no processador, sem placa de vídeo. ✅
🎤 Gravando a sua voz
Agora a parte bonita: a voz que vai ser clonada é um arquivo .wav com você falando, e só. Nada de treinar modelo, nada de esperar horas. 🎙️
Grave no celular, no computador, no aplicativo de gravador que você já tem. O que importa é isto:
- De 6 a 30 segundos. Menos que isso não dá material suficiente, e muito mais não melhora nada.
- Uma voz só, a sua, sem ninguém falando junto.
- Sem música de fundo e sem eco. Este é o item que mais estraga resultado: o programa copia o que ouvir, e se ouvir o ventilador, ele copia o ventilador junto. Um quarto com a porta fechada já resolve.
- Fale normalmente, num ritmo natural. Não precisa impostar a voz nem ler devagar demais: quanto mais parecido com o seu jeito de falar, mais parecida fica a clonagem.
Não sabe o que dizer? Leia qualquer parágrafo de um livro em voz alta. O conteúdo não importa, só o timbre.
O gravador do celular normalmente salva em .m4a ou .mp3, e aqui a gente quer .wav. Converta com o ffmpeg, que faz isso numa linha (o -ar 22050 ajusta a frequência e o -ac 1 deixa em canal único):
ffmpeg -i gravacao.m4a -ar 22050 -ac 1 minhavoz.wav
Se o ffmpeg não estiver instalado, o apt install resolve (o -y responde "sim" às perguntas):
apt install -y ffmpeg
Confira o que saiu com o file, que olha dentro do arquivo e diz o que ele é de verdade, não o que o nome promete:
file minhavoz.wav
minhavoz.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 22050 Hz
Precisa dizer WAVE audio. Se disser MPEG ou ISO Media, o arquivo continua sendo MP3 ou M4A com o nome trocado, e o cadastro vai recusar. Volte um passo e converta com o ffmpeg. ⚠️
📤 Cadastrando a voz por API
Aqui está o motivo de todo o artigo. A voz vai para o servidor por HTTP, sem você copiar arquivo para pasta nenhuma nem editar configuração.
São três campos. O -F do curl é o que manda arquivo junto com texto, e o @ antes do caminho quer dizer "mande o conteúdo deste arquivo", em vez de mandar o nome dele como texto:
curl -X POST http://172.17.0.1:4123/voices \
-F "voice_name=minhavoz" \
-F "language=pt" \
-F "[email protected]"
A resposta confirma o cadastro:
{
"message": "Voice uploaded successfully",
"voice": {
"name": "minhavoz",
"filename": "minhavoz.wav",
"file_size": 622158,
"upload_date": "2026-08-18T14:10:29.017878",
"language": "pt"
}
}
O voice_name é o apelido que você vai usar depois para pedir o áudio, e pode ser qualquer palavra.
O language é a pegadinha. Ele vem como en por padrão, então quem esquecer o campo cadastra a voz como inglesa sem perceber, e o resultado sai com sotaque. Para português, mande sempre pt. 🇧🇷
🗂️ Vendo, renomeando e apagando
Como a voz é um recurso da API, todo o resto também é curl. Para ver o que está cadastrado:
curl -s http://172.17.0.1:4123/voices
{
"voices": [
{
"name": "minhavoz",
"filename": "minhavoz.wav",
"file_size": 622158,
"file_hash": "264c282a01b0849adfb637e294448016",
"upload_date": "2026-08-18T14:10:29.017878",
"path": "/voices/minhavoz.wav",
"language": "pt",
"exists": true
}
],
"count": 1
}
Para renomear, o campo é o new_name:
curl -X PUT http://172.17.0.1:4123/voices/minhavoz \
-F "new_name=vozdapaloma"
{
"message": "Voice renamed successfully",
"old_name": "minhavoz",
"new_name": "vozdapaloma"
}
Para apagar:
curl -X DELETE http://172.17.0.1:4123/voices/vozdapaloma
{
"message": "Voice deleted successfully",
"voice_name": "vozdapaloma"
}
E para dizer qual voz o servidor usa quando você não pedir nenhuma:
curl -X POST http://172.17.0.1:4123/voices/default \
-F "voice_name=minhavoz"
Um detalhe que evita susto: a voz cadastrada sobrevive a reinício. Ela fica guardada num volume do Docker, não dentro do contêiner, então um docker restart não apaga nada. 💾
🪄 A primeira frase com a sua voz
Agora o momento bonito. O voice é o apelido que você cadastrou:
curl -X POST http://172.17.0.1:4123/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{"input":"Ola meus unicornios! Esta voz foi clonada com inteligencia artificial local.","voice":"minhavoz","language":"pt"}' \
-o clonado.wav
E prepare-se para esperar. ⏳ Muito.
Essa frase virou 4,4 segundos de áudio, e levou 4 minutos e 12 segundos para ficar pronta, ocupando 5,1 GB de memória. Não é a sua internet nem a sua VPS: é o preço de clonar voz sem placa de vídeo.
| O que | Quanto |
|---|---|
| Áudio gerado | 4,4 s |
| Tempo de geração | 4 min 12 s |
| Memória usada | 5,1 GB |
| Proporção | quase 60x o tempo do áudio |
Olhe essa tabela com carinho, porque ela decide se isto serve para você. Um artigo de três mil palavras levaria umas vinte horas de processamento nessa máquina. 😳
Então seja honesta consigo mesma sobre o uso: isto serve para gerar áudio em lote e guardar o arquivo, tipo narrar um texto durante a madrugada e servir o resultado pronto depois. Não serve para responder na hora, nem para um assistente que fala enquanto você conversa. Para isso não tem jeito sem placa de vídeo, e trocar de programa não resolve.
Como a espera é longa, existe uma rota feita justamente para isso: você manda o texto, recebe um número de trabalho e vai buscar o resultado quando estiver pronto, sem segurar a conexão aberta por minutos:
curl -X POST http://172.17.0.1:4123/audio/speech/long \
-H "Content-Type: application/json" \
-d '{"input":"Um texto bem grande aqui...","voice":"minhavoz","language":"pt"}'
Ela devolve um identificador, e você consulta o andamento com GET /audio/speech/long/{id} até ele ficar pronto para baixar. Para texto longo, é esse o caminho.
🔍 Conferindo o que saiu
Vale conferir o arquivo antes de sair usando, com o mesmo file de antes:
file clonado.wav
clonado.wav: RIFF (little-endian) data, WAVE audio, IEEE Float, mono 24000 Hz
Duas coisas para reparar aqui, porque as duas pegam quem automatiza:
A primeira: apesar de a rota se chamar /v1/audio/speech, igualzinha à de um serviço pago famoso, o que sai é WAV, não MP3. Se o seu programa espera MP3 pela extensão, ele vai engasgar.
A segunda: o formato é IEEE Float, e não o WAV comum de 16 bits. Isso quebra ferramenta que só lê o formato tradicional, e o erro é feio e sem explicação. Se precisar converter para algo mais comum, o ffmpeg resolve:
ffmpeg -i clonado.wav -acodec libmp3lame clonado.mp3
🖥️ Usando no painel do Open WebUI
Para o Open WebUI ler as respostas com a sua voz, aponte ele para este serviço. No painel, clique no seu nome no canto inferior esquerdo, vá em Painel do Admin, depois em Configurações e em Áudio.
Na seção Texto-para-Fala, escolha o motor OpenAI, ponha a URL http://172.17.0.1:4123/v1, uma chave qualquer no campo de senha (o servidor não confere) e o nome da sua voz em Voz TTS:
Só lembre da tabela lá de cima antes de sair clicando no botão de ouvir: cada resposta longa vai levar minutos para virar áudio. Para o painel, sinceramente, o motor mais leve do artigo anterior é mais agradável. A clonagem compensa quando o que importa é a voz, não a espera. ⏳
Por hoje é só, meus unicórnios! 🦄✨
Que a magia do arco-íris continue brilhando em suas vidas! Até mais! 🌈🌟
Perguntas frequentes
Como eu cadastro a minha voz por API?
POST /voices em multipart, mandando três campos: voice_name (o apelido), voice_file (o arquivo .wav) e language. O language vem como en por padrão, então para português é obrigatório mandar pt. A resposta confirma o cadastro com o tamanho do arquivo e o idioma.De quantos segundos precisa a amostra de voz?
.wav bastam. O que importa mais que a duração é a limpeza: uma voz só, sem música ao fundo, sem eco e sem outra pessoa falando junto. O programa copia o que ouvir, então amostra suja gera voz clonada suja.Quanto tempo leva para gerar o áudio?
Por que a API recusa o idioma português e fala em inglês?
Only English (en) is supported when not using multilingual model engana: ela fala de idioma, mas a causa é o modelo ainda estar carregando. A validação só libera outros idiomas depois que o modelo termina de subir. Espere o /health responder "model_loaded": true e o mesmo comando funciona.A minha voz vai para a nuvem?
Dá para apagar e renomear voz sem entrar no servidor?
GET /voices lista, PUT /voices/{nome} renomeia (campo new_name), DELETE /voices/{nome} apaga e POST /voices/default define a voz padrão. Todo o ciclo de vida da voz é HTTP, sem editar arquivo de configuração à mão.Leia também
Texto em áudio por CURL, com IA local na sua VPS
Transforme texto em áudio com IA local, por CURL. O Open WebUI não tem TTS embutido: instale o motor, baixe a voz brasileira e ligue os dois.
Áudio em texto por CURL, com IA local na sua VPS
Transcreva áudio com IA local, no seu servidor, por CURL. O áudio não sai da máquina, e as duas armadilhas que devolvem 400 e texto em latim.
Ollama e Open WebUI: sua própria IA numa VPS
Instale Ollama e Open WebUI numa VPS por SSH, baixe outros modelos, veja quais valem a pena sem GPU e gere a API Key para usar a API.