首页 → 博客 → Go 里的语音转文字:只用标准库的可用代码
Go 里的语音转文字:只用标准库的可用代码
在 Go 里上传音频既不需要 SDK 也不需要第三方包:一个 multipart 请求用标准库二十行就写完。下面是完整函数、合理的错误处理,以及啃完整个录音归档的工作池。
上传函数
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("状态 %d: %s", resp.StatusCode, out.Error.Message)
}
return out.Text, nil
}
注意客户端超时:默认是没有超时的,长录音的请求可能一直挂着。
错误处理
错误响应是常见结构——带 message 字段的 error 对象。把失败分成两类:永久性的(400、401、413)和临时性的(429、502、网络中断)。前者重试没有意义,后者应当带递增等待重试。
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
}归档用的工作池
Go 的强项正在这里:有界的工作池只有几行,而这个上界能保护你不撞频率限制。
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)
}
}()
}
池子大小按套餐的每秒请求上限来定,开一百个 goroutine 只会换来一百个拒绝。
上线前注意
- 内存。示例把整个请求体放进缓冲区;大文件请改用 io.Pipe 流式发送。
- 文件名。CreateFormFile 必须收到带扩展名的名字,否则判断不出格式。
- 超时。对贴近体积上限的文件,三分钟是合理余量。
- 密钥。放环境变量,别写进源码。
用你自己的录音试一试。 注册只需一分钟,免费额度足够判断识别质量。
免费获取 API 密钥常见问题
Go 有 SDK 吗?
不需要。标准库拼一个 multipart 请求就覆盖了这里用到的全部接口。
长文件为什么会被掐断?
http.Client 默认没有超时,但代理和负载均衡有。自己设一个两三分钟的超时。
怎么传语言和提示词?
作为额外的表单字段:language 和 prompt,与 model 并列。
该开多少个 goroutine?
以套餐的每秒请求上限为准。超了会收到 429,还得重做。
相关阅读
- Python 语音转文字:从一个文件到可用脚本 — 十分钟搭好 Python 语音转文字:安装、第一个请求、响应格式怎么选、错误处理与并发加速,以及最浪费时间的几个坑。
- 如何为音频存档搭建批量转录流水线 — 转录上万条录音而不丢失任何一条:任务队列、并发控制、重试策略、崩溃后续跑,以及如何把账单控制在预期之内。
- 转录 API 的报错分别代表什么 — 逐个解释转录接口的状态码:401、400、413、429、502 各自的原因和修法,以及哪些失败值得自动重试。