Pular para o conteúdo
Ollama

Clonar voz por API, com IA local na sua VPS

Ilustração colorida de um unicórnio de crina arco-íris cantando diante de um espelho mágico, com o reflexo repetindo a mesma canção em ondas sonoras luminosas e um pergaminho flutuante mostrando a forma de onda copiada

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ê querRota
Cadastrar uma vozPOST /voices
Ver as vozes cadastradasGET /voices
RenomearPUT /voices/{nome}
ApagarDELETE /voices/{nome}
Definir a voz padrãoPOST /voices/default
Gerar o áudioPOST /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 queQuanto
Áudio gerado4,4 s
Tempo de geração4 min 12 s
Memória usada5,1 GB
Proporçãoquase 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:

Painel de Áudio do Open WebUI com o Motor de Texto para Fala em OpenAI, a URL apontando para o endereço interno do Docker e a Voz TTS preenchida

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?
Com um 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?
De 6 a 30 segundos num arquivo .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?
Numa VPS de 4 vCPU sem placa de vídeo, uma frase que virou 4,4 segundos de áudio levou 4 minutos e 12 segundos para ficar pronta, ocupando 5,1 GB de memória. É quase 60 vezes o tempo real. Serve para gerar em lote e guardar o arquivo; não serve para responder na hora.
Por que a API recusa o idioma português e fala em inglês?
A mensagem 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?
Não. O arquivo fica gravado num volume do Docker no seu próprio servidor, e o programa lê dali. A porta do serviço fica publicada só na rede interna do Docker, então nem responde de fora. É a diferença inteira entre isto e os sites de clonagem online.
Dá para apagar e renomear voz sem entrar no servidor?
Dá, e é a vantagem desta escolha. 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