Інтеграція OpenAI TTS для генерації мовлення в мобільному додатку
Мобільний додаток має озвучувати довгі тексти — новини, аудіокниги, голосові підказки. Без оптимізації користувач чекає 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. Гарантуємо стабільну роботу та прозору співпрацю.
Отримайте консультацію з інтеграції голосового синтезу у ваш додаток — зв'яжіться з нами.







