Início → Blog → Voz para texto em PHP: requisições, uploads e erros
Voz para texto em PHP: requisições, uploads e erros
O PHP ainda move boa parte da web, e a tarefa de receber uma gravação e devolver texto aparece o tempo todo. Nenhuma biblioteca especial é necessária: o cURL da instalação padrão basta. Segue o código que funciona e as armadilhas de sempre.
cURL puro
<?php
$ch = curl_init("https://voicesscribe.com/v1/audio/transcriptions");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("VS_KEY")],
CURLOPT_POSTFIELDS => [
"model" => "whisper-1",
"file" => new CURLFile("call.ogg", "audio/ogg", "call.ogg"),
],
]);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code !== 200) {
throw new RuntimeException("erro $code: $response");
}
echo json_decode($response, true)["text"];
A classe CURLFile é obrigatória: se você passar o caminho como string, o PHP moderno envia isso como campo de texto comum e o serviço responde 400.
A versão com Guzzle
$client = new GuzzleHttp\Client(["base_uri" => "https://voicesscribe.com/v1/"]);
$response = $client->post("audio/transcriptions", [
"headers" => ["Authorization" => "Bearer " . getenv("VS_KEY")],
"multipart" => [
["name" => "model", "contents" => "whisper-1"],
["name" => "file", "contents" => fopen("call.ogg", "r"), "filename" => "call.ogg"],
["name" => "response_format", "contents" => "verbose_json"],
],
]);
$data = json_decode((string) $response->getBody(), true);
A chave filename é tão obrigatória aqui quanto em qualquer lugar: sem ela o servidor não determina o formato.
Receber o upload do usuário
O formulário de upload deixa o arquivo num diretório temporário, e é dali que ele segue:
$upload = $_FILES["audio"] ?? null;
if (!$upload || $upload["error"] !== UPLOAD_ERR_OK) {
http_response_code(400);
exit("arquivo não enviado");
}
if ($upload["size"] > 25 * 1024 * 1024) {
http_response_code(413);
exit("arquivo maior que 25 MB");
}
$file = new CURLFile($upload["tmp_name"], $upload["type"], $upload["name"]);
Não esqueça upload_max_filesize e post_max_size na configuração do PHP: os padrões costumam ser menores que o necessário e o arquivo nem chega ao seu código.
Processamento em lote
Um laço resolve um arquivo, mas é lento para um acervo. Uma fila é melhor: guarde as tarefas numa tabela e deixe vários trabalhadores consumirem, cada um com sua política de retentativa para falhas temporárias.
O tempo limite padrão do cURL é curto demais para gravações longas — coloque CURLOPT_TIMEOUT em pelo menos 120 segundos, senão uma hora de áudio será cortada no meio do processamento.
Teste com as suas próprias gravações. O cadastro leva um minuto e os minutos gratuitos bastam para avaliar a qualidade.
Obter uma chave de API grátisPerguntas frequentes
Preciso de uma biblioteca específica para PHP?
Não. O cURL da instalação padrão é suficiente; o Guzzle apenas facilita envios concorrentes.
Por que recebo 400 ao enviar o arquivo?
Na maioria das vezes o arquivo foi passado como string em vez de CURLFile, ou a parte multipart não tem filename. O serviço precisa do nome para identificar o formato.
Como aumentar o limite de upload?
Por upload_max_filesize e post_max_size no php.ini. Do lado do serviço o teto é 25 MB por arquivo.
E gravações longas?
Comprima para opus e, se preciso, divida em partes, processando em paralelo e juntando o texto na ordem.
Leitura relacionada
- Voz para texto em Python: de um arquivo a um script que funciona — Transcrição em Python funcionando em dez minutos: instalação, a primeira requisição, formatos de resposta, tratamento de erros e os erros que mais custam tempo.
- Voz para texto em Node.js: código pronto e as armadilhas de sempre — Como transcrever áudio a partir do Node.js: o SDK oficial, streams e FormData, uploads no Express, timeouts e novas tentativas — com código pronto para colar.
- Erros da API de transcrição e o que eles realmente significam — Explicação dos códigos de status da API: por que aparecem 401, 400, 413, 429 e 502, como corrigir cada um e quais falhas vale a pena repetir.