Вы записываете аудио в мобильном приложении, отправляете на OpenAI Whisper API — и получаете ошибку 413 Request Entity Too Large или SocketTimeoutException из-за лимита 25 МБ и долгой обработки. Решение — чанкование и правильная настройка параметров. Наши инженеры, имеющие сертификаты Apple и Google, за 5 лет и более 50 проектов отладили процесс для iOS (Swift) и Android (Kotlin): от нарезки аудио до мультиязычной транскрипции с временными метками. Whisper API — Whisper (речевая система) — открытая модель OpenAI, доступная через REST API. Её точность на русском языке достигает 94% (WER ~6%), что близко к человеку. Однако интеграция требует учёта ограничений и специфики платформ: работа с аудиопотоками, форматами и фоновыми задачами — основа.
Обход лимита 25 МБ
Лимит POST /v1/audio/transcriptions — 25 МБ. Минута MP3 в 128 kbps занимает ~1 МБ, поэтому фрагмент до 25 минут. Для более длинных записей нужна нарезка. На прошлом проекте с аудиозаписями лекций чанкование сократило общее время транскрипции с 15 до 4 минут.
iOS: AVAssetExportSession с timeRange. Пример:
let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) exportSession?.timeRange = CMTimeRange(start: startTime, duration: chunkDuration) Android: MediaExtractor + MediaMuxer — нарезка без перекодирования, если исходный кодек совместим (AAC в MP4). Для других кодеков — конвертация через MediaCodec в PCM → WAV.
Whisper API возвращает 503 при перегрузке. Экспоненциальный backoff с 3 попытками решает проблему в 99% случаев. На Android используйте OkHttp с перехватчиком retry, на iOS — URLSession с делегатом.
Форматы аудио и конвертация
Оптимальны MP3 и M4A (AAC). Убедитесь, что кодек внутри контейнера поддерживается: после AVAssetExportSession с пресетом AppleM4A всегда AAC, на Android безопаснее конвертировать в WAV. Параметр response_format=verbose_json возвращает текст с временными метками — это необходимо для синхронизации.
Какие параметры улучшают точность?
| Параметр | Рекомендация | Эффект |
|---|---|---|
| prompt | до 224 токенов контекста (например, термины предметной области) | Снижает WER на специализированных словах |
| temperature | 0 | Детерминированный вывод |
| language | явно указывать (например, "ru") | Ускоряет обработку |
Сравнение с альтернативами: Whisper API в 3 раза дешевле in-house модели при сопоставимом качестве, а по сравнению с Google Speech-to-Text экономит до 40% на облачных расходах.
Почему чанкование критично для мобильной транскрипции?
Без чанкования невозможно обработать длинные записи — лекции, интервью, диктофонные заметки. Нарезка на фрагменты по 25 МБ с перекрытием (overlap) в 1–2 секунды гарантирует, что на стыке не потеряются слова. Мы используем параллельную отправку фрагментов с помощью DispatchGroup на iOS и CoroutineScope на Android, что сокращает общее время транскрипции на 30%.
| Платформа | Инструмент нарезки | Перекрытие |
|---|---|---|
| iOS | AVAssetExportSession с timeRange | 1 секунда |
| Android | MediaExtractor + MediaMuxer | 2 секунды (зависит от кодека) |
Что входит в интеграцию
- Проектирование архитектуры записи и отправки
- Реализация на iOS (Swift) и Android (Kotlin)
- Обработка ошибок, ретраи, чанкование
- Настройка языка, промптов, формата verbose_json
- Документация и код-ревью
- Тестирование под нагрузкой
Этапы работы
- Анализ требований — определяем сценарии использования, частоту транскрипций, размер аудио.
- Прототип — реализуем базовую интеграцию на одной платформе за 2–3 дня.
- Интеграция и тестирование — добавляем чанкование, ретраи, обработку ошибок, мультиязычность.
- Деплой и мониторинг — настраиваем логирование, алерты при падении точности, обновляем промпты.
Реализация на iOS (Swift)
struct WhisperService { private let apiKey: String private let session = URLSession.shared func transcribe(audioURL: URL, language: String = "ru") async throws -> String { var request = URLRequest(url: URL(string: "https://api.openai.com/v1/audio/transcriptions")!) request.httpMethod = "POST" request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") let boundary = UUID().uuidString request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") var body = Data() body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"file\"; filename=\"audio.m4a\"\r\n".data(using: .utf8)!) body.append("Content-Type: audio/m4a\r\n\r\n".data(using: .utf8)!) body.append(try Data(contentsOf: audioURL)) body.append("\r\n".data(using: .utf8)!) body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"model\"\r\n\r\nwhisper-1\r\n".data(using: .utf8)!) body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"language\"\r\n\r\n\(language)\r\n".data(using: .utf8)!) body.append("--\(boundary)--\r\n".data(using: .utf8)!) request.httpBody = body let (data, _) = try await session.data(for: request) let response = try JSONDecoder().decode(TranscriptionResponse.self, from: data) return response.text } } Реализация на Android (Kotlin)
suspend fun transcribe(file: File, language: String = "ru"): String { val client = OkHttpClient.Builder() .readTimeout(120, TimeUnit.SECONDS) .build() val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("file", file.name, file.asRequestBody("audio/mp4".toMediaType())) .addFormDataPart("model", "whisper-1") .addFormDataPart("language", language) .build() val request = Request.Builder() .url("https://api.openai.com/v1/audio/transcriptions") .header("Authorization", "Bearer $apiKey") .post(requestBody) .build() return withContext(Dispatchers.IO) { client.newCall(request).execute().use { response -> val json = response.body!!.string() JSONObject(json).getString("text") } } } Типичные ошибки при интеграции
Загрузка Data(contentsOf:) целиком в память — на 100 МБ файле это OOM на бюджетных Android. Используйте file.asRequestBody() в OkHttp или InputStream-based upload в iOS. Отсутствие retry-логики: Whisper API периодически возвращает 503 — экспоненциальный backoff с 3 попытками решает проблему. Хранение API-ключа в клиенте — ключ должен передаваться через бэкенд.
Сроки и процесс
Базовая интеграция на одной платформе — 3–5 дней. С чанкованием, verbose_json и retry — 8–13 дней. Мультиязычность — отдельный этап. Свяжитесь с нами для оценки вашего проекта — подберём оптимальную архитектуру за 1 день. Получите консультацию по интеграции Whisper API уже сегодня.
Обработка аудио в фоне
Для длительных записей важно выполнять транскрипцию в фоновом режиме. На iOS используйте BGTaskScheduler, на Android — ForegroundService. Это позволяет пользователю сворачивать приложение без потери данных. Мы гарантируем стабильную работу даже при слабом интернете — если запрос не удался, мы автоматически повторяем его с экспоненциальной задержкой и уведомляем пользователя о прогрессе. Для запуска пилота свяжитесь с нами — предоставим тестовый доступ к API и поможем настроить архитектуру под ваш сценарий.







