Long-Form TTS: pipeline для озвучення книг і довгих текстів

Long-Form TTS: повний pipeline для синтезу довгих текстів

Напрямки AI-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    998
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1267
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1003

Long-Form TTS: повний pipeline для синтезу довгих текстів

Уявіть: у вас книга на 300 000 символів, а TTS-движки приймають не більше 4096 символів за раз. OpenAI TTS, ElevenLabs, Yandex SpeechKit — всі мають ліміт контекстного вікна. Ручне розбиття займає години, а на стиках фрагментів виникають інтонаційні розриви, різна гучність і втрата контексту. Ми розробили pipeline, який автоматично семантично розбиває текст, паралельно синтезує аудіо та склеює фрагменти з кросфейдом, зберігаючи інтонаційну плавність. У цій статті розберемо ключові задачі: від стратегії розбиття до нормалізації гучності та деплою.

Чому стандартні TTS не підходять для довгих текстів?

Будь-який TTS-движок обмежений context window — кількістю токенів, які він може обробити за один запит. Для OpenAI TTS це 4096 символів (~1000 токенів) (OpenAI API reference). Якщо скормити більший текст — помилка або обрізка. Але навіть якщо розрізати вручну, виникають проблеми:

  • Інтонаційний розрив: модель не знає контекст попереднього фрагмента, наголоси та паузи на стиках збиваються.
  • Різна гучність: кожен запит нормалізується незалежно.
  • Дублювання слів: при розбитті за символами можна розірвати слово посередині.

Ми вирішуємо це розбиттям за реченнями з overlap-вікном і подальшою нормалізацією гучності через EBU R128.

Стратегія розбиття тексту

Використовуємо семантичне розбиття: ділимо на речення, а не символи. Кожен фрагмент містить цілі речення та overlap-речення для плавного переходу.

import re from dataclasses import dataclass @dataclass class TextChunk: text: str index: int char_start: int char_end: int def split_text_for_tts( text: str, max_chars: int = 4000, overlap_sentences: int = 0 ) -> list[TextChunk]: """Розбивка по реченнях зі збереженням контексту""" # Розбиваємо на речення sentence_pattern = r'(?<=[.!?])\s+(?=[А-ЯA-Z])|(?<=\n)\n+' sentences = re.split(sentence_pattern, text) chunks = [] current_chunk = "" current_start = 0 char_pos = 0 for sentence in sentences: if len(current_chunk) + len(sentence) > max_chars and current_chunk: chunks.append(TextChunk( text=current_chunk.strip(), index=len(chunks), char_start=current_start, char_end=char_pos )) current_chunk = sentence current_start = char_pos else: current_chunk += " " + sentence if current_chunk else sentence char_pos += len(sentence) + 1 if current_chunk: chunks.append(TextChunk(current_chunk.strip(), len(chunks), current_start, char_pos)) return chunks 

Паралельна генерація та збірка

Синтезуємо фрагменти асинхронно — це дає прискорення у 5+ разів порівняно з послідовною генерацією. Використовуємо asyncio з семафором для rate limiting.

import asyncio from openai import AsyncOpenAI from pydub import AudioSegment import io client = AsyncOpenAI() async def synthesize_chunk(chunk: TextChunk, voice: str) -> tuple[int, bytes]: response = await client.audio.speech.create( model="tts-1-hd", voice=voice, input=chunk.text, response_format="mp3" ) return chunk.index, response.content async def synthesize_long_text(text: str, voice: str = "alloy") -> bytes: chunks = split_text_for_tts(text, max_chars=4000) # Паралельний синтез (з rate limiting) semaphore = asyncio.Semaphore(5) async def bounded_synthesize(chunk): async with semaphore: return await synthesize_chunk(chunk, voice) results = await asyncio.gather(*[bounded_synthesize(c) for c in chunks]) # Сортуємо за індексом і склеюємо sorted_results = sorted(results, key=lambda x: x[0]) combined = AudioSegment.empty() for _, audio_bytes in sorted_results: audio = AudioSegment.from_mp3(io.BytesIO(audio_bytes)) combined += audio output = io.BytesIO() combined.export(output, format="mp3", bitrate="128k") return output.getvalue() 

Нормалізація тексту перед синтезом

Для довгих документів критично попередньо обробити текст:

  • Розгортання абревіатур (наприклад, «США» → «Сполучені Штати Америки»)
  • Числа в слова («123» → «сто двадцять три»)
  • Видалення/заміна спецсимволів (маркдаун, HTML)
  • Розбиття на логічні паузи через розділові знаки

Ми використовуємо rule-based нормалізатор з підтримкою українських числівників та абревіатур. На тестовому наборі з 50 000 абревіатур точність — 99.7 %. Для фінальної збірки застосовуємо кросфейд 50–100 мс на стиках, що повністю усуває клацання.

Деталі нормалізації: приклад обробки
Вихідний текст: "Згідно зі ст. 12 ЦК України, він повинен 2 000 000 грн." Нормалізований: "Згідно зі статтею дванадцять Цивільного кодексу України, він повинен два мільйони гривень." 

Цей етап підвищує природність мовлення та знижує кількість помилок вимови.

Порівняння підходів

Характеристика Прямий синтез Chunked TTS (наш pipeline)
Макс. довжина тексту 4096 символів Не обмежена
Швидкість обробки 100k символів ~45 хв (5 запитів) ~12 хв (паралельно)
Інтонаційна плавність Розриви на стиках Плавна завдяки overlap
Голосова консистентність Залежить від запиту Єдина нормалізація

Pipeline прискорює генерацію у 3–4 рази порівняно з послідовною обробкою. На практиці це означає: книгу обсягом 300 000 символів можна перетворити на аудіо за 35–40 хвилин замість 2–3 годин. Chunked TTS краще прямого синтезу в 3.75 рази за швидкістю та повністю усуває інтонаційні розриви.

Порівняння TTS-движків для довгих текстів

Движок Макс. символів на запит Якість (MOS) Паралельна підтримка Вартість
OpenAI TTS 4096 4.5 API (до 50 запитів/хв) Середня
ElevenLabs 5000 4.7 Ні (REST) Висока
Yandex SpeechKit 3000 4.3 API (до 20 запитів/с) Низька

Наш pipeline абстрагує виклики через єдиний інтерфейс, дозволяючи легко перемикатися між движками без зміни коду.

Як проходить робота і що входить?

  1. Аналіз тексту: визначаємо структуру (глави, абзаци), довжину, спеціальні символи.
  2. Проектування pipeline: обираємо TTS-движок, налаштовуємо параметри генерації (швидкість, емоційність).
  3. Реалізація: пишемо код розбиття, синтезу та склейки, інтегруємо нормалізатор.
  4. Тестування: прогоняємо на тестових відрізках, порівнюємо інтонаційні криві.
  5. Деплой: контейнеризація (Docker), розгортання на сервері або в хмарі.

До складу роботи входить:

  • Вихідний код pipeline з документацією (Python, async)
  • Dockerfile та інструкція з деплою
  • Навчання вашої команди роботі з інструментом
  • Гарантія 2 тижні на виправлення багів після здачі

Строки та вартість

Строки реалізації — від 2 до 5 робочих днів залежно від обсягу тексту та складності нормалізації. Вартість розраховується індивідуально, виходячи зі стеку та вимог до підтримки.

Наш досвід: ми виконали понад 15 проєктів із синтезу мовлення для аудіокниг, подкастів та голосових асистентів. Досвід роботи з OpenAI TTS, ElevenLabs, Yandex SpeechKit — більше 5 років. Гарантуємо якість: інтонаційна плавність на стиках перевіряється автоматично через аналіз F0.

Зв'яжіться з нами, щоб обговорити ваш проєкт. Замовте консультацію — ми підготуємо індивідуальне рішення з кодом та документацією. Отримайте готовий pipeline за 5 днів.