BerandaBlog → Suara ke teks dengan PHP: permintaan, unggahan, dan galat

Suara ke teks dengan PHP: permintaan, unggahan, dan galat

Diterbitkan 2026-08-20 · 5 menit baca

PHP masih menjalankan sebagian besar web, dan kebutuhan menerima rekaman lalu mengembalikan teks muncul terus-menerus. Pustaka khusus tidak diperlukan: cURL dari paket standar sudah cukup. Berikut kode yang bekerja dan jebakan yang biasa.

cURL polos

<?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("galat $code: $response");
}
echo json_decode($response, true)["text"];

CURLFile wajib: kalau path diberikan sebagai string biasa, PHP modern mengirimnya sebagai bidang teks dan layanan menolak dengan 400.

Versi 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);

Kunci filename di sini sama wajibnya: tanpa itu server tidak bisa menentukan formatnya.

Menerima unggahan pengguna

Formulir unggah menaruh berkas di direktori sementara, dari sanalah ia dikirim:

$upload = $_FILES["audio"] ?? null;
if (!$upload || $upload["error"] !== UPLOAD_ERR_OK) {
    http_response_code(400);
    exit("berkas tidak terunggah");
}
if ($upload["size"] > 25 * 1024 * 1024) {
    http_response_code(413);
    exit("berkas lebih dari 25 MB");
}
$file = new CURLFile($upload["tmp_name"], $upload["type"], $upload["name"]);

Jangan lupa upload_max_filesize dan post_max_size di konfigurasi PHP: nilai bawaannya sering lebih kecil dari kebutuhan, dan berkasnya tidak pernah sampai ke kode Anda.

Pemrosesan massal

Perulangan bekerja untuk sebuah arsip tapi lambat. Antrean lebih baik: simpan pekerjaan di tabel dan biarkan beberapa pekerja menghabiskannya, masing-masing dengan kebijakan coba ulang untuk kegagalan sementara.

Batas waktu bawaan cURL terlalu pendek untuk rekaman panjang — setel CURLOPT_TIMEOUT setidaknya 120 detik, kalau tidak satu jam audio akan terpotong di tengah pemrosesan.

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

Perlukah pustaka khusus untuk PHP?

Tidak. cURL dari paket standar sudah cukup; Guzzle hanya lebih nyaman untuk unggahan paralel.

Kenapa muncul 400 saat mengirim berkas?

Paling sering berkas dikirim sebagai string alih-alih CURLFile, atau bagian multipart tanpa filename. Layanan butuh nama untuk mengenali format.

Bagaimana menaikkan batas unggahan?

Lewat upload_max_filesize dan post_max_size di php.ini. Di sisi layanan batasnya 25 MB per berkas.

Bagaimana dengan rekaman panjang?

Kompres ke opus dan bila perlu potong menjadi bagian, proses paralel, lalu sambung teksnya berurutan.

Bacaan terkait