ГлавнаяБлог → Распознавание речи на Java: код на стандартном HttpClient

Распознавание речи на Java: код на стандартном HttpClient

Опубликовано 2026-08-20 · 5 мин чтения

В Java начиная с одиннадцатой версии есть встроенный HTTP-клиент, и этого достаточно: сторонние библиотеки для отправки аудио не нужны. Единственная неприятность — multipart тело придётся собрать руками. Ниже готовый код.

Сборка multipart-запроса

import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.io.ByteArrayOutputStream;

String boundary = "----vs" + System.nanoTime();
Path audio = Path.of("call.ogg");

var body = new ByteArrayOutputStream();
body.write(("--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"model\"\r\n\r\nwhisper-1\r\n"
    + "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"file\"; filename=\"" + audio.getFileName() + "\"\r\n"
    + "Content-Type: audio/ogg\r\n\r\n").getBytes());
body.write(Files.readAllBytes(audio));
body.write(("\r\n--" + boundary + "--\r\n").getBytes());

var request = HttpRequest.newBuilder(URI.create("https://voicesscribe.com/v1/audio/transcriptions"))
    .header("Authorization", "Bearer " + System.getenv("VS_KEY"))
    .header("Content-Type", "multipart/form-data; boundary=" + boundary)
    .timeout(java.time.Duration.ofMinutes(3))
    .POST(HttpRequest.BodyPublishers.ofByteArray(body.toByteArray()))
    .build();

var client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());

if (response.statusCode() != 200) {
    throw new IllegalStateException("ошибка " + response.statusCode() + ": " + response.body());
}
System.out.println(response.body());

Переводы строк в разделителях обязаны быть именно парой возврат каретки и перевод строки: с одиночным символом сервер не разберёт тело.

Разбор ответа

Ответ приходит в JSON с полем text. Любая привычная библиотека разбора подойдёт — Jackson, Gson или встроенные средства фреймворка:

record Transcription(String text) {}

var mapper = new com.fasterxml.jackson.databind.ObjectMapper();
var result = mapper.readValue(response.body(), Transcription.class);
System.out.println(result.text());

Если запрошен формат srt или vtt, ответ придёт не в JSON, а готовым текстом субтитров — разбирать его не нужно.

В сервисе под нагрузкой

Три вещи, которые стоит сделать сразу:

  1. Держать один экземпляр HttpClient на приложение — он потокобезопасен и переиспользует соединения.
  2. Не читать файл целиком в память для больших записей: BodyPublishers.ofFile отдаёт его потоком.
  3. Ограничить параллельность пулом фиксированного размера, подобранным под лимит запросов вашего тарифа.

Типовые ошибки

СимптомПричина
400 на корректном файленет filename в части формы или неверный boundary
401ключ не подставился из переменной окружения
413файл больше 25 МБ, нужно сжать или разрезать
Обрыв на длинных записяхне задан timeout у запроса

Попробуйте на своих записях. Регистрация занимает минуту, бесплатных минут хватает, чтобы оценить качество.

Получить ключ бесплатно

Частые вопросы

Нужна ли библиотека вроде OkHttp?

Не обязательно: встроенного HttpClient достаточно. OkHttp удобнее тем, что собирает multipart за вас.

Работает ли пример на Java 8?

Нет, встроенный HttpClient появился в одиннадцатой версии. На восьмой используйте OkHttp или Apache HttpClient.

Как передать язык записи?

Добавьте ещё одну часть формы с именем language и кодом языка, например ru.

Можно ли отправлять файл потоком?

Да, BodyPublishers.ofFile передаёт файл без загрузки в память — это важно для записей у верхней границы лимита.

Читайте также