Detecção automática do idioma falado com cURL e código aberto
Detecte o idioma falado diretamente no áudio com um modelo Whisper multilíngue, servido localmente pelo whisper.cpp. O cURL envia a gravação ao endpoint HTTP, que retorna um idioma candidato e uma transcrição para comparar com a gravação. Depois que o software e o modelo forem baixados, a inferência será executada no seu computador sem uma conta ou API na nuvem.
Requisitos do sistema
Use Linux com Bash, um shell POSIX (sh), um compilador C++17, Make, CMake, cURL, FFmpeg,
Python 3 e os comandos usuais tar, gzip, dirname, grep, mktemp e rm. Primeiro, instale
as ferramentas que faltarem pelo gerenciador de pacotes da sua distribuição. O Python lê a resposta
JSON usando apenas sua biblioteca padrão.
Este tutorial para CPU usa a versão fixa v1.8.7 do whisper.cpp e foi elaborado para um ambiente Debian 13 com
Bash 5.2, GCC 14.2, Make 4.4, CMake 3.31, cURL 8.14, FFmpeg 7.1 e Python 3.12.
Outras plataformas e conjuntos de ferramentas mais antigos estão fora do escopo deste tutorial.
O modelo multilíngue tiny ocupa cerca de 75 MiB em disco. Reserve espaço adicional
em disco para o código-fonte e a compilação, além de várias centenas de megabytes de memória livre
para a inferência.
Instalação
Em um novo diretório de trabalho, baixe a versão fixa, compile seu servidor e baixe o
modelo multilíngue. Escolha tiny, em vez do modelo tiny.en, exclusivo para inglês. Os parênteses
mantêm as opções do shell e as mudanças de diretório dentro de um subshell:
(
set -e
for tool in curl tar gzip cmake make c++ ffmpeg python3 sh dirname grep mktemp rm; do
command -v "$tool" >/dev/null || { printf 'Missing tool: %s\n' "$tool" >&2; exit 1; }
done
if [ -e whisper-v1.8.7.tar.gz ] || [ -e whisper.cpp-1.8.7 ]; then
printf 'Use a fresh directory; existing download or source found.\n' >&2
exit 1
fi
curl -q --fail --location --output whisper-v1.8.7.tar.gz \
https://github.com/ggml-org/whisper.cpp/archive/refs/tags/v1.8.7.tar.gz
tar -xzf whisper-v1.8.7.tar.gz
cd whisper.cpp-1.8.7
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DGGML_METAL=OFF -DWHISPER_BUILD_SERVER=ON
cmake --build build --config Release --target whisper-server -j 4
sh ./models/download-ggml-model.sh tiny
)
Configurar o servidor de transcrição
Depois que a instalação for concluída com sucesso, inicie o servidor HTTP no mesmo diretório de trabalho:
(
cd whisper.cpp-1.8.7 &&
./build/bin/whisper-server --model models/ggml-tiny.bin \
--host 127.0.0.1 --port 8080 --language auto --no-gpu
)
Aguarde a mensagem que indica que o servidor está escutando e deixe este terminal aberto. O servidor do exemplo não tem autenticação, então mantenha-o vinculado à interface de loopback e use gravações locais confiáveis. Encerre-o com Ctrl+C quando terminar.
Transcrever áudio com cURL
Em um segundo terminal, trabalhe em um diretório que contenha uma gravação de fala chamada input.mp3.
Use um trecho confiável que comece com fala clara em um único idioma. Converta-o para WAV PCM mono,
com 16 kHz e 16 bits. O bloco rejeita um audio.wav existente antes da conversão, e
-n também impede que o FFmpeg o sobrescreva. Escolha um novo diretório para cada gravação;
o FFmpeg 7.1 pode informar que se recusou a sobrescrever o arquivo e ainda retornar um código de
saída zero, por isso a verificação explícita é importante.
(
if [ -e audio.wav ]; then
printf 'Existing audio.wav; use a fresh directory.\n' >&2
exit 1
fi
ffmpeg -nostdin -n -i input.mp3 -vn -ar 16000 -ac 1 -c:a pcm_s16le audio.wav
)
Ouça audio.wav e confira se ele contém a fala desejada antes de fazer o upload. O FFmpeg
pode recuperar partes de gravações danificadas e ainda retornar sucesso; a conversão por si só
não comprova que o arquivo de entrada estava intacto.
Detecção de idioma
Salve isto como read_language.py no mesmo diretório de audio.wav. O script lê o idioma inferido a partir do áudio
e imprime a transcrição para revisão. Ele rejeita texto vazio e texto composto apenas de marcadores
entre colchetes que indicam ausência de fala, incluindo resultados [BLANK_AUDIO] repetidos:
import json
import re
import sys
def read_language(path):
with open(path, encoding="utf-8") as handle:
data = json.load(handle)
if not isinstance(data, dict):
raise ValueError("Expected a JSON object")
language = data.get("language")
text = data.get("text")
if not isinstance(language, str) or not language.strip():
raise ValueError("Response has no detected language")
if not isinstance(text, str) or not re.sub(r"\[[^\]]*\]", "", text).strip():
raise ValueError("No speech transcript; language result is inconclusive")
return language.strip(), " ".join(text.split())
def main():
if len(sys.argv) != 2:
raise ValueError("Usage: python3 read_language.py response.json")
language, text = read_language(sys.argv[1])
print(f"Language candidate: {language}")
print(f"Transcript: {text}")
if __name__ == "__main__":
try:
main()
except (OSError, ValueError) as error:
print(f"Cannot read language result: {error}", file=sys.stderr)
sys.exit(1)
Depois que a conversão for concluída com sucesso e o script de leitura estiver salvo, cole este bloco de requisição. Ele cria um arquivo temporário de resposta para cada requisição e só o lê se o cURL tiver sucesso. O arquivo é removido quando o bloco termina, inclusive em caso de falha, para que uma resposta anterior não possa se tornar o resultado desta requisição. A requisição permite um total de 60 segundos, incluindo upload e inferência; uma CPU ocupada ou uma gravação mais longa pode ultrapassar esse prazo. Aumente-o de forma deliberada, se necessário.
(
set -e
response=$(mktemp ./language-response.XXXXXX)
trap 'rm -f "$response"' EXIT
curl -q --fail --silent --show-error --max-time 60 \
http://127.0.0.1:8080/inference \
--form 'file=@audio.wav;type=audio/wav' \
--form 'language=auto' \
--form 'response_format=verbose_json' \
--form 'no_language_probabilities=true' \
--output "$response" &&
python3 read_language.py "$response"
)
language=auto solicita a detecção de idioma. A
resposta verbose_json do servidor
inclui language e text; o formato simples json omite o idioma. A tradução está desativada, e
no_language_probabilities=true ignora uma segunda passagem opcional de detecção.
Para fala em inglês, espere Language candidate: english;
para espanhol, o nome usado pelo servidor é spanish. Esses são nomes de idiomas, não códigos ISO.
Compare a transcrição impressa com o que você ouve. A verificação dos marcadores é apenas uma
checagem básica: o Whisper pode inventar palavras,
e uma transcrição não vazia não confirma a presença de fala nem a identificação correta do idioma.
Otimização de desempenho
Mantenha o servidor em execução entre as requisições para que ele possa reutilizar o modelo
carregado. tiny mantém o download pequeno para experimentos locais, mas sua transcrição
pode conter erros consideráveis. Teste-o com gravações conhecidas antes de usar o idioma candidato
para direcionar outros trabalhos.
Nesta versão, a detecção automática de idioma começa na posição zero e usa a janela inicial da gravação, de aproximadamente 30 segundos, em vez de reclassificar cada segmento posterior. Assim, um longo silêncio inicial pode resultar na identificação incorreta do idioma, mesmo quando há fala mais adiante. Use um trecho que comece com fala; para mudanças de idioma, avalie trechos separados. Um resultado para o arquivo inteiro não é uma linha do tempo de todos os idiomas falados.
Tratamento de erros
Se a instalação falhar, examine seus arquivos parciais, corrija o pré-requisito que falta e tente
novamente em um novo diretório de trabalho. Os downloads existentes e os arquivos de código-fonte
extraídos são mantidos intactos deliberadamente.
Se a conversão falhar, examine qualquer audio.wav parcial antes de removê-lo ou escolher outro diretório.
O cURL termina com um código de saída diferente de zero em caso de erros HTTP, falhas de conexão
ou tempos limite excedidos. Nesse caso, o bloco de requisição ignora o script de leitura e remove
sua resposta temporária. Mantenha um audio.wav convertido com sucesso
e execute novamente apenas o bloco de requisição depois de resolver a falha. JSON inválido, campos
ausentes, transcrições vazias ou compostas apenas de marcadores e arquivos ilegíveis fazem o script
de leitura encerrar com código de saída 1.
Se a inicialização falhar, verifique o caminho do modelo e se a porta 8080 já está ocupada. Se um upload falhar, examine o terminal do servidor local e confirme que a conversão para WAV foi concluída com sucesso. Não trate um idioma estimado a partir de silêncio, música ou uma fala muito curta como uma classificação confiável.
Para transcrição em um serviço hospedado dentro de um fluxo de trabalho de processamento de arquivos, consulte nosso Speech Robot.
