首页博客 → Go 里的语音转文字:只用标准库的可用代码

Go 里的语音转文字:只用标准库的可用代码

发布于 2026-08-20 · 5 分钟阅读

在 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 只会换来一百个拒绝。

上线前注意

用你自己的录音试一试。 注册只需一分钟,免费额度足够判断识别质量。

免费获取 API 密钥

常见问题

Go 有 SDK 吗?

不需要。标准库拼一个 multipart 请求就覆盖了这里用到的全部接口。

长文件为什么会被掐断?

http.Client 默认没有超时,但代理和负载均衡有。自己设一个两三分钟的超时。

怎么传语言和提示词?

作为额外的表单字段:language 和 prompt,与 model 并列。

该开多少个 goroutine?

以套餐的每秒请求上限为准。超了会收到 429,还得重做。

相关阅读