Início → Blog → Voz para texto em Go: código só com a biblioteca padrão
Voz para texto em Go: código só com a biblioteca padrão
Go não precisa de SDK nem de pacotes de terceiros para enviar áudio: uma requisição multipart sai em vinte linhas de biblioteca padrão. Abaixo, a função completa, tratamento de erros sensato e um pool de workers para varrer um acervo de gravações.
A função de envio
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"time"
)
func transcribe(path, key string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
var body bytes.Buffer
w := multipart.NewWriter(&body)
part, _ := w.CreateFormFile("file", f.Name())
if _, err := io.Copy(part, f); err != nil {
return "", err
}
w.WriteField("model", "whisper-1")
w.Close()
req, _ := http.NewRequest("POST", "https://voicesscribe.com/v1/audio/transcriptions", &body)
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{Timeout: 3 * time.Minute}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
var out struct {
Text string
Error struct{ Message string }
}
json.NewDecoder(resp.Body).Decode(&out)
if resp.StatusCode != 200 {
return "", fmt.Errorf("status %d: %s", resp.StatusCode, out.Error.Message)
}
return out.Text, nil
}
Repare no tempo limite do cliente: o padrão é não haver nenhum, então uma requisição sobre gravação longa pode ficar pendurada para sempre.
Tratando erros
As respostas de erro chegam no formato conhecido — objeto error com campo message. Separe as falhas em dois grupos: permanentes (400, 401, 413) e temporárias (429, 502, queda de rede). Repetir o primeiro grupo é inútil; o segundo merece retentativa com pausa crescente.
func withRetry(path, key string) (string, error) {
delay := 2 * time.Second
var last error
for i := 0; i < 4; i++ {
text, err := transcribe(path, key)
if err == nil {
return text, nil
}
last = err
if !temporary(err) {
break
}
time.Sleep(delay)
delay *= 2
}
return "", last
}Pool de workers para acervos
É aqui que Go brilha: um pool limitado sai em poucas linhas, e o limite protege você das rejeições por excesso de requisições.
files := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for path := range files {
text, err := withRetry(path, key)
if err != nil {
log.Println(path, err)
continue
}
os.WriteFile(path+".txt", []byte(text), 0o644)
}
}()
}
Dimensione o pool pelo limite de requisições por segundo do seu plano — subir cem goroutines só produz cem rejeições.
Notas para produção
- Memória. O exemplo monta o corpo inteiro em buffer; para arquivos grandes use io.Pipe e transmita em fluxo.
- Nome do arquivo. CreateFormFile precisa receber um nome com extensão, senão o formato não é detectado.
- Tempo limite. Três minutos é uma folga razoável para arquivos no limite de tamanho.
- Segredos. Guarde a chave no ambiente, nunca no código.
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
Existe SDK para Go?
Não é necessário. Uma requisição multipart com a biblioteca padrão cobre toda a superfície usada aqui.
Por que envios longos são cortados?
http.Client não tem tempo limite padrão, mas proxies e balanceadores têm. Defina o seu, na casa de dois a três minutos.
Como enviar idioma ou prompt?
Como campos extras do formulário: language e prompt ao lado do campo model.
Quantas goroutines devo usar?
Tantas quantas o limite de taxa do seu plano permitir. Ultrapassar devolve 429 e obriga a refazer o trabalho.
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.
- Como montar um pipeline de transcrição para um acervo de áudio — Transcrever milhares de gravações sem perder nenhuma: fila de trabalho, concorrência, novas tentativas, retomada após uma queda e controle do valor da fatura.
- 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.