Интеграция ElevenLabs для генерации речи в мобильном приложении

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Интеграция ElevenLabs для генерации речи в мобильном приложении
Простая
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1054
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Интеграция ElevenLabs для генерации речи в мобильном приложении

ElevenLabs — один из двух провайдеров с по-настоящему естественно звучащей мультиязычной речью (второй — OpenAI TTS). Для русского языка ElevenLabs с моделью eleven_multilingual_v2 выдаёт результат, который люди регулярно принимают за живую речь. Интеграция нетривиальна: у API есть нюансы с форматами, стримингом и управлением символьной квотой.

Базовая интеграция: REST

Минимальный запрос на синтез:

POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id}
xi-api-key: YOUR_KEY
Content-Type: application/json

{
  "text": "Привет, это тестовый текст",
  "model_id": "eleven_multilingual_v2",
  "voice_settings": {
    "stability": 0.5,
    "similarity_boost": 0.75,
    "style": 0.0,
    "use_speaker_boost": true
  }
}

Ответ — бинарный аудиофайл. По умолчанию mp3_44100_128, можно изменить через query-параметр output_format: pcm_16000, pcm_22050, pcm_24000, pcm_44100, mp3_22050_32, mp3_44100_64, mp3_44100_128, mp3_44100_192.

Для воспроизведения в мобильном приложении — mp3_44100_128. Для on-the-fly воспроизведения без сохранения — pcm_16000 с немедленной подачей в AudioTrack / AVAudioPlayerNode.

Стриминг: WebSocket API

ElevenLabs поддерживает два вида стриминга: через streaming HTTP (/v1/text-to-speech/{voice_id}/stream) и через WebSocket (/v1/text-to-speech/{voice_id}/stream-input).

WebSocket — для диалоговых приложений, где текст генерируется по мере ответа LLM:

// iOS: стриминг через URLSessionWebSocketTask
class ElevenLabsStreamPlayer {
    private var webSocket: URLSessionWebSocketTask?
    private var audioEngine = AVAudioEngine()
    private var playerNode = AVAudioPlayerNode()

    func connect(voiceId: String) {
        let url = URL(string: "wss://api.elevenlabs.io/v1/text-to-speech/\(voiceId)/stream-input?model_id=eleven_multilingual_v2&output_format=pcm_16000")!
        var request = URLRequest(url: url)
        request.setValue(apiKey, forHTTPHeaderField: "xi-api-key")
        webSocket = URLSession.shared.webSocketTask(with: request)
        webSocket?.resume()

        // Инициализация потока
        let initMsg = #"{"text":" ","voice_settings":{"stability":0.5,"similarity_boost":0.75}}"#
        webSocket?.send(.string(initMsg)) { _ in }

        audioEngine.attach(playerNode)
        audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: nil)
        try? audioEngine.start()

        receiveAudio()
    }

    func sendText(_ chunk: String) {
        let msg = "{\"text\":\"\(chunk)\"}"
        webSocket?.send(.string(msg)) { _ in }
    }

    func flush() {
        webSocket?.send(.string("{\"text\":\"\"}")) { _ in }
    }

    private func receiveAudio() {
        webSocket?.receive { [weak self] result in
            if case .success(.string(let text)) = result,
               let data = text.data(using: .utf8),
               let json = try? JSONDecoder().decode(AudioChunk.self, from: data),
               let audioB64 = json.audio,
               let audioData = Data(base64Encoded: audioB64) {
                self?.enqueueAudio(audioData)
            }
            self?.receiveAudio()
        }
    }

    private func enqueueAudio(_ data: Data) {
        // PCM 16000 Hz, int16 → AVAudioPCMBuffer
        let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 16000, channels: 1, interleaved: false)!
        let frameCount = AVAudioFrameCount(data.count / 2)
        guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: frameCount) else { return }
        buffer.frameLength = frameCount
        data.withUnsafeBytes { ptr in
            buffer.int16ChannelData?[0].update(from: ptr.bindMemory(to: Int16.self).baseAddress!, count: Int(frameCount))
        }
        playerNode.scheduleBuffer(buffer, completionHandler: nil)
        if !playerNode.isPlaying { playerNode.play() }
    }
}

Паттерн использования в диалоговом ассистенте: по мере получения токенов от GPT — sendText(token), по завершению ответа — flush(). Задержка до первого звука — 200–400 мс.

Настройки голоса

stability (0–1): чем выше, тем более монотонно. 0.3–0.5 для живой речи, 0.8–1.0 для дикторского чтения.

similarity_boost (0–1): насколько точно воспроизводится оригинальный тембр клонированного голоса. Слишком высокое значение (>0.9) может добавить артефакты.

style (0–1): только для eleven_multilingual_v2 и eleven_turbo_v2_5. Усиливает эмоциональность. 0 для нейтральной речи.

use_speaker_boost: true — улучшает четкость для синтезированных голосов (не клонов). Включай по умолчанию.

Мониторинг квоты

ElevenLabs считает символы. GET /v1/user/subscription возвращает character_count и character_limit. Добавляй проверку перед каждым запросом — если квота < длины текста, показывай ошибку или предлагай апгрейд.

suspend fun checkQuota(textLength: Int): Boolean {
    val response = httpClient.get("https://api.elevenlabs.io/v1/user/subscription") {
        header("xi-api-key", apiKey)
    }.body<SubscriptionInfo>()
    return (response.characterLimit - response.characterCount) >= textLength
}

Кэширование

Одна и та же фраза с теми же настройками голоса должна синтезироваться один раз. Ключ кэша: sha256(text + voice_id + stability + similarity_boost + model_id). Файлы храни во внутреннем хранилище приложения с TTL 30 дней, LRU-выбросом при превышении 100 МБ.

Сроки

Базовая интеграция REST + воспроизведение — 2–3 дня. Стриминговый WebSocket с подачей токенов от LLM — 5–7 дней. Полный UI выбора голоса + кэш + мониторинг квоты — 10–14 дней.