Интеграция Whisper API для транскрибации в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Интеграция Whisper API для транскрибации в мобильном приложении
Простой
от 1 дня до 3 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Интеграция Whisper API для транскрибации в мобильном приложении

Whisper — не просто «отправь аудио, получи текст». У API есть конкретные ограничения, которые требуют подготовки на стороне клиента: 25 МБ на файл, поддержка только определённых кодеков, отсутствие стриминга, синхронный ответ. Если не учесть эти детали на этапе архитектуры, интеграция превращается в серию хотфиксов.

Лимиты и как с ними жить

25 МБ — жёсткий лимит эндпоинта POST /v1/audio/transcriptions. Минута MP3 в 128 кbps занимает ~1 МБ, значит лимит — примерно 25 минут. Для большинства голосовых заметок хватает, для записей встреч — нет.

Решение: нарезка на клиенте. На iOS — AVAssetExportSession с временным диапазоном через AVAssetExportSession.timeRange. На Android — MediaExtractor + MediaMuxer для точной нарезки без перекодирования, если исходный кодек уже совместим (AAC в MP4 — обычно да).

Кодек. API принимает mp3, mp4, mpeg, mpga, m4a, wav, webm. Важно: контейнер, а не кодек внутри. .m4a с AAC — проходит. .m4a с ALAC — нет, получите 400. На iOS после AVAssetExportSession с пресетом AVAssetExportPresetAppleM4A всегда будет AAC. На Android безопаснее конвертировать через MediaCodec в PCM → WAV, если не уверен в источнике.

Язык. Параметр language в формате ISO-639-1 (ru, en, uk) ускоряет транскрипцию и снижает количество ошибок. Без него Whisper тратит время на детекцию языка и иногда ошибается на коротких фрагментах.

Реализация на 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()
        // Append file
        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)!)
        // Append model and language
        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
    }
}

Для файлов крупнее 25 МБ — перед вызовом transcribe запускаем AudioChunker.split(url:maxBytes:), получаем массив URL, запускаем transcribe параллельно через TaskGroup, мержим по порядку индексов.

Реализация на 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")
        }
    }
}

Обрати внимание: readTimeout — 120 секунд минимум. Whisper на длинном файле отвечает долго. Дефолтные 10 секунд OkHttp гарантированно дадут SocketTimeoutException.

Параметры, которые часто игнорируют

response_format: verbose_json — возвращает не просто текст, а сегменты с start, end, text. Это нужно для синхронизации аудио с текстом, поиска по времени, субтитров.

prompt — до 224 токенов контекста, который подсказывает модели стиль и специфичные слова. Передавай терминологию предметной области: «ТЗ, MVP, бэклог, Jira» для IT-митингов, «ЭКГ, АД, анамнез» для медицины. Это реально снижает количество ошибок в специфичных терминах.

temperature: 0 — детерминированный вывод. Для продакшена лучше, чем дефолт.

Типичные ошибки при интеграции

Загрузка Data(contentsOf:) целиком в память перед отправкой — на 100 МБ файле это OOM на бюджетных Android. Используй file.asRequestBody() в OkHttp или InputStream-based upload в iOS через URLSession.uploadTask(withStreamedRequest:).

Отсутствие retry-логики. Whisper API периодически возвращает 503 Service Unavailable при нагрузке. Экспоненциальный backoff с 3 попытками закрывает 99% случаев.

Хранение API-ключа в коде или BuildConfig. Ключ должен идти через бэкенд — мобильный клиент не должен иметь прямого доступа к OpenAI API в продакшене.

Сроки и процесс

Базовая интеграция Whisper API (запись → транскрипция → вывод текста) на одной платформе — 3–5 дней. Добавление чанкования, verbose_json с метками времени, retry-логики, фоновой обработки через WorkManager/BackgroundTasks — ещё 5–8 дней. Мультиязычность и UI синхронизации текста с аудио — отдельный этап.