Главная → Блог → Распознавание речи в PHP: код, загрузка файлов и ошибки
Распознавание речи в PHP: код, загрузка файлов и ошибки
PHP по-прежнему держит львиную долю сайтов, и задача «принять запись от пользователя и вернуть текст» встречается постоянно. Отдельная библиотека для этого не нужна: хватает cURL из коробки. Ниже рабочий код и типовые грабли.
Запрос на чистом cURL
<?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("ошибка $code: $response");
}
echo json_decode($response, true)["text"];
Класс CURLFile обязателен: если передать просто путь строкой, современный PHP отправит его как обычное текстовое поле, и сервис ответит ошибкой 400.
То же самое через 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);
Ключ filename здесь так же обязателен, как имя файла в других языках: без него сервер не определит формат.
Приём файла от пользователя
Форма загрузки на сайте отдаёт файл во временный каталог, оттуда его и отправляем:
$upload = $_FILES["audio"] ?? null;
if (!$upload || $upload["error"] !== UPLOAD_ERR_OK) {
http_response_code(400);
exit("файл не загружен");
}
if ($upload["size"] > 25 * 1024 * 1024) {
http_response_code(413);
exit("файл больше 25 МБ");
}
$file = new CURLFile($upload["tmp_name"], $upload["type"], $upload["name"]);
Не забудьте про upload_max_filesize и post_max_size в конфигурации PHP: по умолчанию они часто меньше нужного, и файл до кода просто не доходит.
Пакетная обработка
Для архива записей запрос в цикле работает, но медленно. Быстрее очередь: складываем задания в таблицу и разбираем их несколькими воркерами, каждый со своим повтором на временные ошибки.
Тайм-аут cURL по умолчанию слишком мал для длинных записей — ставьте CURLOPT_TIMEOUT не меньше 120 секунд, иначе час аудио оборвётся на середине обработки.
Попробуйте на своих записях. Регистрация занимает минуту, бесплатных минут хватает, чтобы оценить качество.
Получить ключ бесплатноЧастые вопросы
Нужна ли специальная библиотека для PHP?
Нет. Достаточно cURL из стандартной поставки; Guzzle просто удобнее для многопоточной отправки.
Почему приходит 400 при отправке файла?
Чаще всего файл передан строкой вместо CURLFile или без имени в multipart. Сервису нужно имя файла, чтобы определить формат.
Как увеличить лимит загрузки?
Через upload_max_filesize и post_max_size в php.ini. Со стороны сервиса ограничение — 25 МБ на файл.
Что делать с длинными записями?
Сжимать в opus и при необходимости резать на части, обрабатывая их параллельно и склеивая текст по порядку.
Читайте также
- Распознавание речи на Python: от одного файла до рабочего скрипта — Рабочая расшифровка аудио на Python за десять минут: установка, первый запрос, форматы ответа, обработка ошибок и приёмы, которые экономят больше всего времени.
- Распознавание речи в Node.js: рабочий код и привычные грабли — Как расшифровывать аудио из Node.js: официальный SDK, потоки и FormData, приём загрузок в Express, таймауты и повторные попытки — с кодом, который можно вставить.
- Ошибки API распознавания речи и что они означают — Разбор кодов ответа API транскрибации: почему приходит 401, 400, 413, 429 и 502, как это чинить и как правильно повторять неудачные запросы.