Ви записуєте аудіо в мобільному додатку, надсилаєте на 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 | явно вказувати (наприклад, "uk") | Прискорює обробку |
Порівняння з альтернативами: 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 = "uk") 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 = "uk"): 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 та допоможемо налаштувати архітектуру під ваш сценарій.







