BerandaBlog → Suara ke teks dengan Go: kode di atas pustaka standar

Suara ke teks dengan Go: kode di atas pustaka standar

Diterbitkan 2026-08-20 · 5 menit baca

Go tidak butuh SDK maupun paket pihak ketiga untuk mengunggah audio: permintaan multipart cukup dua puluh baris pustaka standar. Berikut fungsi lengkapnya, penanganan galat yang masuk akal, dan kolam pekerja untuk melahap arsip rekaman.

Fungsi pengunggah

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
}

Perhatikan batas waktu klien: bawaannya tidak ada sama sekali, sehingga permintaan pada rekaman panjang bisa menggantung selamanya.

Menangani galat

Jawaban galat datang dalam bentuk yang biasa — objek error dengan bidang message. Pisahkan kegagalan jadi dua: permanen (400, 401, 413) dan sementara (429, 502, koneksi putus). Yang pertama percuma diulang, yang kedua pantas diulang dengan jeda yang membesar.

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
}

Kolam pekerja untuk arsip

Di sinilah Go bersinar: kolam terbatas hanya beberapa baris, dan batas itu melindungi Anda dari penolakan karena batas laju.

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)
		}
	}()
}

Ukuran kolam mengikuti batas permintaan per detik paket Anda — menjalankan seratus goroutine hanya menghasilkan seratus penolakan.

Catatan untuk produksi

Coba dengan rekaman Anda sendiri. Pendaftaran memakan waktu satu menit, dan menit gratisnya cukup untuk menilai kualitasnya.

Ambil kunci API gratis

Pertanyaan yang sering diajukan

Apakah ada SDK untuk Go?

Tidak diperlukan. Permintaan multipart dengan pustaka standar sudah mencakup seluruh antarmuka yang dipakai di sini.

Kenapa unggahan panjang terputus?

http.Client tidak punya batas waktu bawaan, tapi proxy dan penyeimbang beban punya. Setel batas waktu sendiri sekitar dua tiga menit.

Bagaimana mengirim bahasa atau prompt?

Sebagai bidang formulir tambahan: language dan prompt di samping bidang model.

Berapa goroutine yang sebaiknya dijalankan?

Sebanyak yang diizinkan batas laju paket Anda. Melebihinya berbuah 429 dan pekerjaan terulang.

Bacaan terkait