Интеграция OpenAI TTS для генерации речи в мобильном приложении
Голосовой синтез (text-to-speech) — технология преобразования текста в речь. Мобильное приложение озвучивает длинные тексты — новости, аудиокниги, голосовые подсказки. Без оптимизации пользователь ждёт 3–5 секунд перед началом воспроизведения. OpenAI TTS решает эту задачу, но только если правильно настроить стриминг и кэширование. Мы расскажем, как добиться задержки менее секунды на iOS и Android.
В этой статье разберём архитектуру интеграции: от простого REST-запроса до потокового воспроизведения с ExoPlayer и AVAudioPlayer. Покажем, как кэшировать синтезированное аудио и обрабатывать тексты длиннее 4096 символов. В результате — готовое решение, которое можно внедрить за 3–10 дней.
Какие проблемы решаем?
Мы решаем три ключевые проблемы. Во-первых, высокая задержка: без стриминга приходится ждать полной загрузки файла. Во-вторых, расходы: каждый повторный синтез одного и того же текста — лишние затраты на API. В-третьих, ограничение длины: OpenAI TTS принимает до 4096 символов, поэтому длинный текст нужно разбивать. Все эти проблемы мы устраняем с помощью кэша, стриминга и разбивки по предложениям.
Как устроен API OpenAI TTS?
POST https://api.openai.com/v1/audio/speech
Authorization: Bearer {api_key}
Content-Type: application/json
{
"model": "tts-1-hd",
"input": "Ваш текст здесь",
"voice": "nova",
"response_format": "mp3",
"speed": 1.0
}Согласно документации OpenAI, доступны две модели. tts-1 — быстрее, чуть хуже качество, дешевле ($15/млн символов). tts-1-hd — выше качество, медленнее на ~30%, дороже ($30/млн символов). Голоса: alloy (нейтральный), echo (мужской мягкий), fable (британский), onyx (мужской глубокий), nova (женский живой), shimmer (женский спокойный). Для русского языка nova и shimmer звучат наиболее естественно. Параметр speed от 0.25 до 4.0, дефолт 1.0; значения выше 1.3 начинают ломать просодию.
| Характеристика | tts-1 | tts-1-hd |
|---|---|---|
| Качество | Стандартное | Высокое |
| Задержка | Минимальная | Небольшая |
| Стоимость | Экономичная | Премиальная |
| Рекомендация | Короткие фразы | Длинные тексты |
| Голос | Пол | Стиль | Рекомендация для русского |
|---|---|---|---|
| alloy | нейтральный | умеренный | нет |
| echo | мужской | мягкий | да |
| fable | мужской | британский | нет |
| onyx | мужской | глубокий | да |
| nova | женский | живой | да (лучший) |
| shimmer | женский | спокойный | да |
Почему кэширование критично для UX?
Каждый запрос к API занимает время и стоит денег. Кэширование позволяет избежать повторных синтезов одного и того же текста. Для UI-фраз приложения (приветствие, подсказки) мы предгенерируем аудио при первом запуске и кэшируем навсегда. Оценка экономии: при активном использовании кэш позволяет сократить расходы на API до 40%.
// iOS: кэш синтезированного аудио
class TTSCache {
private let cacheURL: URL
init() {
cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
.appendingPathComponent("tts_cache")
try? FileManager.default.createDirectory(at: cacheURL, withIntermediateDirectories: true)
}
func key(text: String, voice: String) -> String {
let input = "\(text)|\(voice)"
return SHA256.hash(data: Data(input.utf8)).hexString
}
func get(_ key: String) -> Data? {
let url = cacheURL.appendingPathComponent(key + ".mp3")
return try? Data(contentsOf: url)
}
func set(_ key: String, data: Data) {
let url = cacheURL.appendingPathComponent(key + ".mp3")
try? data.write(to: url)
}
}Перед каждым TTS-запросом — проверка кэша. Попадание в кэш = мгновенное воспроизведение.
Реализация без стриминга (для коротких текстов)
// iOS: загрузка и воспроизведение
func speak(text: String, voice: String = "nova") async throws {
var request = URLRequest(url: URL(string: "https://api.openai.com/v1/audio/speech")!)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = TTSSpeechRequest(model: "tts-1", input: text, voice: voice, responseFormat: "mp3")
request.httpBody = try JSONEncoder().encode(body)
let (data, _) = try await URLSession.shared.data(for: request)
audioPlayer = try AVAudioPlayer(data: data)
audioPlayer?.play()
}Для коротких фраз (до 100 символов) на tts-1 задержка ~300–500 мс — приемлемо без стриминга. Для длинных текстов нужен стриминг.
Пример стримингового воспроизведения на Android (ExoPlayer)
class OpenAITTSStreamer(private val apiKey: String, private val context: Context) {
private val exoPlayer = ExoPlayer.Builder(context).build()
fun speak(text: String, voice: String = "nova") {
val requestBody = JSONObject().apply {
put("model", "tts-1")
put("input", text)
put("voice", voice)
put("response_format", "mp3")
}.toString().toRequestBody("application/json".toMediaType())
// Используем OkHttp как DataSource через кастомный MediaSource
val call = OkHttpClient().newCall(
Request.Builder()
.url("https://api.openai.com/v1/audio/speech")
.header("Authorization", "Bearer $apiKey")
.post(requestBody)
.build()
)
call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
// Пишем поток во временный файл, одновременно начинаем воспроизведение
val tempFile = File(context.cacheDir, "tts_${System.currentTimeMillis()}.mp3")
response.body!!.byteStream().use { input ->
tempFile.outputStream().use { output ->
val buffer = ByteArray(8192)
var bytes: Int
var firstChunk = true
while (input.read(buffer).also { bytes = it } != -1) {
output.write(buffer, 0, bytes)
if (firstChunk && tempFile.length() > 32768) {
firstChunk = false
// Начинаем воспроизведение после первых 32 KB
Handler(Looper.getMainLooper()).post {
exoPlayer.setMediaItem(MediaItem.fromUri(tempFile.toUri()))
exoPlayer.prepare()
exoPlayer.play()
}
}
}
}
}
}
override fun onFailure(call: Call, e: IOException) {
/* обработка ошибки */
}
})
}
}ExoPlayer поддерживает воспроизведение из файла, который ещё пишется — ProgressiveMediaSource читает данные по мере их поступления. Задержка до первого звука — 400–700 мс.
Как обрабатывать длинные тексты?
OpenAI TTS принимает до 4096 символов за запрос. Для длинных текстов — разбивка по предложениям:
func splitBySentences(_ text: String, maxLength: Int = 1000) -> [String] {
var chunks: [String] = []
var current = ""
for sentence in text.components(separatedBy: CharacterSet(charactersIn: ".!?\n")) {
let trimmed = sentence.trimmingCharacters(in: .whitespaces)
if trimmed.isEmpty {
continue
}
if current.count + trimmed.count > maxLength {
if !current.isEmpty {
chunks.append(current)
}
current = trimmed
} else {
current += (current.isEmpty ? "" : ". ") + trimmed
}
}
if !current.isEmpty {
chunks.append(current)
}
return chunks
}Куски синтезируем параллельно через TaskGroup, воспроизводим последовательно — так общая задержка меньше, чем при последовательной обработке.
Что входит в интеграцию
- Анализ требований и проектирование архитектуры
- Реализация REST- и стриминговых запросов к OpenAI TTS
- Настройка кэширования на устройстве (LRU-кэш с хешированием)
- Обработка длинных текстов (разбивка по предложениям)
- Интеграция плеера (AVAudioPlayer / ExoPlayer) с поддержкой фонового воспроизведения
- Учёт требований App Store Review Guidelines (Section 4.2) и настройка AVAudioSession для iOS
- Тестирование на реальных устройствах (iOS 15+ / Android 10+)
- Документация по эксплуатации и инструкция по получению API-ключа
- Поддержка в течение 2 недель после сдачи
Процесс работы
- Аналитика — изучаем ваше приложение, определяем места вызова TTS, замеряем текущие задержки.
- Прототипирование — создаём MVP на одном экране, показываем стриминг с кэшем.
- Интеграция — встраиваем готовые модули в вашу кодовую базу.
- Тестирование — проверяем на нагрузке, корректируем под ваши кейсы.
- Деплой — публикация в App Store / Google Play, мониторинг.
Сроки и стоимость
Базовая интеграция (REST + кэш) — 3–4 дня. Расширенная (стриминг + обработка длинных текстов + UI) — 7–10 дней. Точную стоимость рассчитываем после аудита вашего проекта — напишите нам, и мы оценим. Для точной оценки стоимости вашего проекта — свяжитесь с нами.
Опыт команды
Мы более 5 лет занимаемся мобильной разработкой. Реализовали 15+ проектов с интеграцией AI-сервисов, включая OpenAI, Google Cloud Speech и Yandex SpeechKit. Наши разработчики сертифицированы Apple и Google. Гарантируем стабильную работу и прозрачное сотрудничество.
Получите консультацию по интеграции голосового синтеза в ваше приложение — свяжитесь с нами.







