
Каждый из вас хоть раз ловил себя на мысли: «А почему бы не начать слушать книги вместо того, чтобы их читать?». Пока едешь в метро, стоишь в пробке, занимаешься домашней рутиной или вместо приевшейся музыки в спортзале — сценариев масса.
В сети полно литературы, но если вы эстет и ищете что-то глубже «Онегина» или модных бестселлеров, то наверняка сталкивались с проблемой: нужной книжки в аудио просто не существует.
Так вот, тут мы попадаем в ловушку. Технологий синтеза речи (TTS) сейчас море, а вменяемого инструмента, чтобы массово превращать текст в звук, нет.
Либо вы платите корпорациям за каждый символ через официальные API, превращая чтение в дорогую привычку, либо ковыряете софт, застрявший в эпохе Windows XP, который озвучивает файлы дольше, чем вы бы читали их вслух сами.
Я системный администратор. Моя работа — заставлять системы работать эффективно, и я не люблю ждать. Не люблю, когда мой домашний компьютер превращается в жужжащую печку, показывая 1% прогресса в час. Этот материал — не просто туториал, а технический разбор и своего рода «дневник» процесса разработки проекта «Прометей». Мы посмотрим, как превратить выделенный сервер в промышленную фабрику аудиокниг, способную выдавать 20 часов готового звука за 11 минут.
Протокол личного ада: почему «Балаболка» больше не тянет
Каждый, кто хоть раз задавался целью превратить увесистый FB2-файл в аудио, так или иначе приходил к такой программе, как «Балаболка». Для тех, кто видит это название впервые: это бесплатная утилита для чтения текстовых файлов вслух. Она работает как посредник: вы скачиваете сторонние голосовые движки, закидываете в программу книгу, а она прогоняет текст через эти голоса и сохраняет результат в MP3 или WAV.
Честно скажу: это великолепный софт, который годами спасал мои (и, уверен, ваши) уши. Но сегодня он упирается в системный потолок, а попытка использовать его для «промышленной» озвучки превращается в протокол личного ада.
Главный враг — линейность. Программа спотыкается, читая текст глава за главой, страница за страницей.
Когда вы подключаете к ней качественные нейронные голоса (например, Microsoft Neural), вы попадаете в ловушку ограничений API. Софт обращается к облаку в один-единственный поток. В итоге скорость генерации лишь немногим превышает скорость человеческой речи. Если книга рассчитана на 15 часов прослушивания, «Балаболка» будет ее обрабатывать те же 15 часов, а то и дольше.
Наконец, есть ресурсный голод и ограничения GUI. На длинных дистанциях интерфейсные приложения Windows часто демонстрируют утечки памяти. Интерфейс начинает подтормаживать, а любой системный сбой или случайная перезагрузка обрывают многочасовую запись без возможности восстановления прогресса.
Я ощутил этот «голод» физически, когда нужно было озвучить пласт научной литературы. Пока домашний десктоп шумел вентиляторами, а прогресс двигался крайне медленно, мой сервер в дата-центре простаивал без нагрузки.
Стало очевидно: озвучивать книгу объемом в миллион знаков через «окна» и кнопки — это в 10–15 раз медленнее, чем позволяет пропускная способность современных сетей. Мне нужно было решение, способное работать автономно и утилизировать гигабитный канал связи на 100%.

Облачная инфраструктура для ваших проектов
Виртуальные машины в Москве, Санкт-Петербурге и Новосибирске с оплатой по потреблению.
Архитектура «Прометея»
Идея «Прометея» родилась из простого админского вопроса: «Зачем ждать одного диктора, если я могу нанять 16?». Если облако Microsoft (через edge-tts) ограничивает скорость на одно соединение, значит, нам нужно много соединений. Было решено применить принцип «Divide et impera» — разделяй и властвуй. Вместо того чтобы просить нейросеть прочитать книгу целиком, мы рубим ее на куски (мелкие чанки) и запускаем армию виртуальных дикторов одновременно.
Параллелизм на стероидах (xargs -P)
Облако Microsoft (Edge TTS) ограничивает скорость отдачи потока на одно соединение, но практически не ограничивает количество одновременных запросов с одного IP. То есть использование инструмента xargs с флагом -P (parallel) позволяет запустить 12–16 потоков одновременно.
В таком режиме мы заставляем облако работать на пике производительности, утилизируя доступный канал связи, а не ожидая своей очереди в однопоточном режиме. Это превращает процесс из изнурительного ожидания в высокоскоростную конвейерную сборку.
Проблема «битого символа» и fold -s
Первые тесты параллельной сборки выявили проблему. Кириллица в UTF-8 не так проста: каждый символ занимает два байта. Если резать файл как есть, по размеру (байтам), разрез обязательно попадает на середину буквы. В итоге вместо текста Python получает «мусорный» байт, вылетает с ошибкой «UnicodeDecodeError», и процесс сразу крашится.
Решение нашлось в классической утилите fold с флагом -s. Она умеет делать «мягкие» переносы строк, ориентируясь на пробелы. Это гарантирует, что каждый чанк текста останется валидным для Python-декодера, а слова не будут превращены в нечитаемый набор байтов. Теперь данные уходят в облако в идеальном состоянии.
Инфраструктурный минимализм
Предрекаю ваш вопрос: «Почему не через виртуальное окружение Python?». Мой подход строится на принципе «одна задача — один сервер». Разворачивая «Прометей» на выделенном воркере, я превращаю его в узкоспециализированный вычислительный модуль.
Изоляция через venv здесь избыточна. Она лишь усложняет цепочку вызовов в Bash-скриптах и добавляет лишний слой абстракции там, где нужна прямая работа с системными бинарниками. Нам нужен максимально короткий путь от текста к звуку.
Disk-First против RAM-First
Многие админы по привычке используют /tmp (tmpfs) для хранения временных данных. Однако при озвучке тяжелых книг на 170+ чанков объем промежуточных MP3-данных легко переваливает за 2 ГБ. На бюджетных инстансах это приведет к ошибке «No space left on device».
Чтобы не зависеть от объемов RAM, весь рабочий цикл «Прометея» перенесен на физический диск (NVMe). Это гарантирует стабильность на любых объемах: будь то короткая статья или многотомный архив научной литературы.
Бенчмарки и стресс-тест
Для испытаний был выбран выделенный сервер Selectel конфигурации CL13. Под капотом у него:
CPU: 12th Gen Intel Core i3-12100 (4 ядра / 8 потоков);
RAM: 16 ГБ DDR4;
Disk: Samsung 970 EVO Plus 500 ГБ (NVMe);
OS: Debian 12 Stable.
Именно его NVMe-шина должна была выдержать шквал одновременных записей. В качестве подопытного объекта я взял книгу Адама Хиггинботама «Чернобыль. История катастрофы». Почему именно ее? Это сложный текст с обилием технических терминов, фамилий и цифр — идеальный стресс-тест для интонаций нейронки.
В 13:50 мы запустили конвейер в 12 потоков. Книга объемом около 1,2 млн знаков была разбита на 172 чанка. К 13:57 система вышла на пик сетевой активности, показывая 91% готовности, а еще через минуту генерация всех чанков была завершена. Спустя еще три минуты, в 14:01, ffmpeg в режиме copy mode склеил их в один файл.
В итоге на 24 часа готового аудио ушло всего 11 минут. За это время я мог заварить себе чай, пока система выдает результат с коэффициентом ускорения x130. После этого возвращаться к «Балаболке», где тот же процесс растянулся бы на сутки ожидания, кажется просто бессмысленным.
Анализ системных метрик
Пока на экране мелькали проценты прогресса, мне было интересно заглянуть в систему изнутри и узнать, как сервер Selectel переваривает этот массив из 12 потоков озвучки.
Первым делом я проверил дисковую активность через iostat. При суммарной скорости записи около 21 МБ/с утилизация NVMe-накопителя составила всего 1,6%. Задержка записи (w_await) в 2,4 мс подтверждает: для современного диска такая нагрузка — это даже не разминка, он ее просто не замечает.
Нагрузка на диск (iostat):
Device w/s wkB/s w_await %util
nvme0n1 203.00 21540.00 2.44 1.60
Процессор i3-12100 (Alder Lake) вполне неплохо и стабильно управляет 12 потоками. Текущая вычислительная мощность используется не полностью, так что тут есть небольшой запас на разбег в случае необходимости — сохраняется запас производительности и низкое время отклика.
Нагрузка на CPU (top):
load average: 0.23, 0.08, 0.02
%Cpu(s): 2.3 us, 2.3 sy, 0.0 ni, 95.5 id
Вопросы «аудиофилов»
Слышу вопрос от эстетов: «А как же связность речи на стыках чанков?» Технически каждая нейронная сессия в edge-tts — это независимый акт генерации. Однако благодаря тому, что мы используем fold -s, разрез файла происходит строго на границах слов и предложений.
Нейросетевой движок Microsoft Neural достаточно умен: он имеет встроенные алгоритмы «вдоха» и «выдоха» в начале и конце каждой фразы. В итоге стыки чанков воспринимаются слушателем как естественные паузы диктора между абзацами. На скорости 1,2x с включенной функцией «Skip Silence» в плеере переходы становятся абсолютно бесшовными.
Инструкция по развертыванию
Я делюсь этой технологией по принципу «не жалко». Ресурс должен приносить пользу, а не гнить в приватных папках. Ниже — ваш пошаговый маршрут к созданию собственной системы генерации контента (или фабрики аудиокниг, кому как больше нравится) и детальный разбор того, как это работает изнутри.
Подготовка среды
Сначала необходимо зайти на сервер под пользователем root. Мы развернем базовый набор инструментов: Python для работы движка, FFmpeg для обработки звука, Pandoc для парсинга книг из FB2 и Aria2 для скоростной закачки моделей и данных.
Весь процесс подготовки занимает меньше минуты. Последовательно выполните следующие команды:
Установка системных пакетов и движка
apt update && apt install -y python3-pip ffmpeg pandoc aria2 pip install edge-tts --break-system-packages
Флаг --break-system-packages необходим в современных версиях Debian/Ubuntu для установки Python-пакетов глобально, минуя виртуальные окружения.
Создание структуры директорий
Чтобы файлы не перемешивались, создадим рабочую иерархию папок для текстов, готового аудио и временных файлов:
mkdir -p /root/books/{text,audio,tmp}
Скрипт prometheus.sh (v7.2.1 Master Edition)
Теперь создадим управляющий скрипт. Вам нужно создать файл в папке /root/, вставить в него код и разрешить системе его запуск (дать право на запуск) командой chmod +x. Для этого:
создайте файл: nano /root/prometheus.sh;
вставьте код скрипта;
сохраните (Ctrl+O, Enter) и выйдите (Ctrl+X);
сделайте файл исполняемым (код ниже).
Показать код скрипта (кликните, чтобы развернуть).
#!/bin/bash # ====================================================== # PROJECT PROMETHEUS v7.2.1 | MASTER EDITION # ====================================================== # КОНФИГУРАЦИЯ THREADS=12 # Оптимально для стабильности без бана по IP VOICE="ru-RU-DmitryNeural" # Эталонный мужской голос RATE="+15%" # Сжатие пауз и темп OUTPUT_BASE="/root/books/audio" TEMP_BASE="/root/books/tmp" # 1. ВВОД ДАННЫХ (Поддерживает автозаполнение через Tab) read -e -p "Путь к файлу (txt/fb2): " INPUT_PATH INPUT_PATH=$(echo "$INPUT_PATH" | sed -e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//") [ ! -f "$INPUT_PATH" ] && echo "ERR: Файл не найден!" && exit 1 # 2. ПОДГОТОВКА WORKDIR="${TEMP_BASE}/work_$(date +%s)" mkdir -p "$WORKDIR" "$OUTPUT_BASE" # 3. ПАРСИНГ МЕТАДАННЫХ (Вытаскиваем автора и название из FB2) FILE_EXT="${INPUT_PATH##*.}" ORIG_NAME=$(basename "$INPUT_PATH" ."$FILE_EXT") if [[ "$FILE_EXT" == "fb2" ]]; then F_NAME=$(grep -i -oP '(?<=<first-name>).*?(?=</first-name>)' "$INPUT_PATH" | head -1) L_NAME=$(grep -i -oP '(?<=<last-name>).*?(?=</last-name>)' "$INPUT_PATH" | head -1) TITLE=$(grep -i -oP '(?<=<book-title>).*?(?=</book-title>)' "$INPUT_PATH" | head -1) BOOK_NAME="${L_NAME}_${F_NAME}__${TITLE}" # Fallback если метаданные кривые [ ${#BOOK_NAME} -lt 10 ] && BOOK_NAME="$ORIG_NAME" pandoc -f fb2 -t plain "$INPUT_PATH" -o "$WORKDIR/raw.txt" else BOOK_NAME="$ORIG_NAME" cp "$INPUT_PATH" "$WORKDIR/raw.txt" fi # Санитизация имени файла (убираем мусорные символы) BOOK_NAME=$(echo "$BOOK_NAME" | sed 's/[[:space:]]/_/g' | sed 's/[\\/:"*?<>|]//g') FINAL_FILE="$OUTPUT_BASE/${BOOK_NAME}.mp3" echo -e ">>> ЗАПУСК ПРОТОКОЛА: ${BOOK_NAME}.mp3" # 4. ОБРАБОТКА ТЕКСТА И НАРЕЗКА sed '/^$/d' "$WORKDIR/raw.txt" > "$WORKDIR/source.txt" fold -s -w 2000 "$WORKDIR/source.txt" | tr -d '\r' > "$WORKDIR/formatted.txt" split -l 100 -d -a 4 "$WORKDIR/formatted.txt" "$WORKDIR/part_" TOTAL_PARTS=$(ls "$WORKDIR"/part_[0-9]* | wc -l) # 5. КОНВЕЙЕРНАЯ ОЗВУЧКА export VOICE WORKDIR RATE do_tts() { local file=$1 edge-tts --rate="$RATE" --voice "$VOICE" --file "$file" --write-media "$file.mp3" > /dev/null 2>&1 } export -f do_tts # Очередь через xargs (вот здесь живет скорость) ls "$WORKDIR"/part_[0-9]* | xargs -P $THREADS -I {} bash -c 'do_tts "{}"' #6. СКЛЕЙКА (БЕЗ ПОТЕРИ КАЧЕСТВА) ls "$WORKDIR"/part_*.mp3 | sort | xargs -I {} echo "file '{}'" > "$WORKDIR/list.txt" ffmpeg -f concat -safe 0 -i "$WORKDIR/list.txt" -c copy -y "$FINAL_FILE" > /dev/null 2>&1 rm -rf "$WORKDIR" echo "ГОТОВО! Файл: $FINAL_FILE"
Заключение
«Прометей» — это манифест эффективности. Пока корпорации строят заборы вокруг своих API, мы строим мосты из Bash-скриптов. Я озвучил более 40 часов эксклюзивного контента за один вечер просто потому, что могу. Теперь это можете сделать и вы. Не ждите, пока за вас решат, что и как вам слушать. Делайте это сами.
Комментарии (26)

mikemdr
04.03.2026 10:25Полученную озвучку было невозможно слушать из-за того, первый попавшийся исходный fb2-файл был отформатирован в виде "80 символов на строку" вставкой в требуемых местах символа первода_строки (0x0A) вместо пробела (0x20).В результате - "чтец" делил единое предложение на несколько безсвязных фраз.

loveprod Автор
04.03.2026 10:25А можно пример файла или разметки?

mikemdr
04.03.2026 10:25Там что-то вроде этого:
Вздохнув, он дважды со злостью резко взмахнул битой, срезав с земли одуванчик и пучок травы, – и лишь после этого снова приготовился к удару по мячу.
mikemdr
04.03.2026 10:25Прошу прощения,проверил форматирование исходного файла - деления отсутстует. Я запускал преобразование из-под WSL2 - слушать невозможно из-за того, что "чтец" делит единое предложение на несколько безсвязных фраз как раз кусками по "80 символов на строку" как отображается при чтении с экран.
Мистика!
Как звучит: https://www.mediafire.com/file/7jvm871ghhxhz0j/part_0000.mp3/file

LLazy
04.03.2026 10:25Мне помогло
pandoc input.fb2 -o output.txt --wrap=none --from=fb2, и странные паузы исчезли.

mikemdr
04.03.2026 10:25Разобрался в этом "глюке" (WSL2 в Win10):
вот эта команда из скрипта автора
pandoc -f fb2 -t plain "$INPUT_PATH" -o "$WORKDIR/raw.txt"преобразует исходную строку ( одну!) из fb2-файла
<p>Вздохнув, он дважды со злостью резко взмахнул битой, срезав с земли одуванчик и пучок травы, – и лишь после этого снова приготовился к удару по мячу.</p>в такой набор из трёх строк в $WORKDIR/raw.txt
Вздохнув, он дважды со злостью резко взмахнул битой, срезав с земли одуванчик и пучок травы, – и лишь после этого снова приготовился к удару по мячу.вставляя Перевод_Строки (0x0A) после слов "земли" и "удару". В результате, при "озвучке" tts преобразует это одно предложение в три(!).
Для исправления достаточно добавить --wrap=preserve в команду
pandoc -f fb2 -t plain "$INPUT_PATH" --wrap=preserve -o "$WORKDIR/raw.txt"и "озвучка" нормализуется.

loveprod Автор
04.03.2026 10:25На тестах с такими файлами не сталкивался, поэтому пропустил. Обязательно поправлю в логике очистки текста. Спасибо, что подсветили этот момент!

StriganovSergey
04.03.2026 10:25Тоже такую штуку собираюсь сделать, но использовать голоса rhvoice.
Они приятные, и хорошая управляемость ими.
При помощи llm можно было бы сделать раскладку на роли ( мужские, женские, авторский текст и т.д.)

diffnotes-tech
04.03.2026 10:25"CPU 2.3%, диск 1.6%" - выделенный сервер тут загружен примерно никак, всё упирается в edge-tts. С домашнего компа результат будет тот же)

mikemdr
04.03.2026 10:25А у меня на компе edge-tts отрабатывает моментально, а вот склейка
ffmpeg'ом работаетОООООООООЧЕНЬдолго...

dyadyaSerezha
04.03.2026 10:25Два вопроса.
(1) Где фрагмент (1-2 параграфа) нагенеренного звука? Или ссылка на аудио-книгу.
(2) Некоторые читалки на Андроиде умеют сами читать голосом, тогда ничего генерить вообще не надо. Но, конечно, голос, интонация и некоторые ударения и паузы всё ещё довольно далеки от идеала.

loveprod Автор
04.03.2026 10:25Мне был нужен именно архив с книгами в MP3. для максимальной надежности и автономности. Читалки, генерирующие звук «на лету», имеют неприятное свойство терять позицию воспроизведения при сбоях или вылетать в фоне, особенно на длинных книгах.
Готовый файл в связке с Smart AudioBook Player — это гарантия того, что я продолжу слушать с той же секунды даже спустя неделю, не завися от капризов софта, наличия интернета или заряда батареи (рендеринг на сервере экономит ресурс смартфона). Фрагменты не выкладываю, но если хотите оценить качество — запустите скрипт у себя или просто нажмите «Прочесть вслух» в браузере Microsoft Edge. Это тот же самый движок

nebularia
04.03.2026 10:25В сети полно литературы, но если вы эстет и ищете что-то глубже «Онегина» или модных бестселлеров, то наверняка сталкивались с проблемой: нужной книжки в аудио просто не существует.
А можно и с другой стороны пойти, например мой вкус в литературе в значительной степени сформировал любимый чтец (он сам выбирает то, что читает, а не всё подряд по контракту с условным Литресом)

Azamat_Safarov
04.03.2026 10:25А почему именно 2000 символов и 100 строк на чанк? Пробовали ли делать чанки крупнее -скажем, 5000 символов - чтобы уменьшить количество стыков?

Newbilius
04.03.2026 10:25По хорошему ещё по границе абзаца или хотя бы на знаке препинания делать (но не запятых), чтоб стык был бы на естественном месте. Т.е. иногда сделать чанк даже меньше лимита, но лучше.

loveprod Автор
04.03.2026 10:252000 символов — это «безопасный пакет», при котором облако Microsoft гарантированно не обрывает соединение по таймауту: на тестах выяснилось, что при 16 потоках более тяжелые куски (5к–10к) часто приводили к ошибкам связи и «захлебыванию» конвейера.

xJasz
04.03.2026 10:25извиняюсь, что не в тему, но я один подумал, что в названии статьи речь про другую библиотеку?

loveprod Автор
04.03.2026 10:25Вдохновлялся советским неймингом, там любили давать проектам такие монументальные имена. Плюс сама суть мифа: Прометей принес огонь, а мой скрипт «дает голос» немым текстовым архивам.
Название выбрал скорее для красивого словца.

Akr0n
04.03.2026 10:25В сети абсолютно конечное количество книг, не имеющих аудиоверсий. Для них уже тысячи умников и красноглазиков разными способами нагенерили разного качества аудио (часто платного и очень качественного). Почему бы все это не выложить просто в сеть чтобы мы тут больше не мучились..? На тех же трекерах легко выкладывают официальные озвучки, что уж точно более незаконно, чем аудиосамиздат. При этом, такие самостоятельные озвучки в сети встречаются крайне редко.

kefiiir
04.03.2026 10:25В свое время для этих целей пользовался silero_tts_standalone и был доволен, для нехудожественных произведений отлично от квантовой механики до здоровья третей чакры. Обзоров на них на хабре много. Вроде бы потом они ухудшили качество бесплатной версии чтоб не конкурировать со своим же комерческим продуктом, а так отлично в одну команду само нарезает, само расставляет ударения, работает быстро и локально. Модели доступны тут https://github.com/snakers4/silero-models

delicious
04.03.2026 10:25>Я системный администратор. Моя работа — заставлять системы работать эффективно, и я не люблю ждать. Не люблю, когда мой домашний компьютер превращается в жужжащую печку, показывая 1% прогресса в час.
AI;DR! КГ/АМ!

rvs2016
04.03.2026 10:25edge-tts в 2026-м году работает у кого-нибудь?
В 2025-м году установил себе edge-tts, он работал нормально, но вот месяца 2-3 не работает уж.
Запускаю из командной строки edge-tts с ранее работавшими аргументами и работа этой программы завершается ошибкой такой:
File "/usr/local/lib/python3.11/site-packages/aiohttp/client.py", line 707, in request raise ConnectionTimeoutError( aiohttp.clientexceptions.ConnectionTimeoutError: Connection timeout to host wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken= ... &Sec-MS-GEC= ... &Sec-MS-GEC-Version=1-130.0.2849.68&ConnectionId= ...
(ненужные коды я тут заменил на многоточия)
Ну и словами типа Connection timeout to host в этой ошибке намекают на то, что программа не может некоторое время подключиться по указанному в тексте ошибки адресу wss://...
Захожу в браузере руками на speech.platform.bing.com (доменное имя из адреса в тексте ошибки), а там пишут постоянно:
Our services aren't available right now
We're working to restore all services as soon as possible. Please check back soon.
Ну и тут ещё код какой-то.И так очень давно, месяца 2-3 уж.
Это как-то можно исправить?
Anselm_nn
пробовал делать озвучку, microsoft дает не очень естественный результат. gemini намного лучше, но квота на него в ai studio крайне скромна. повозился еще и понял, что особо с теми квотами ничего путного не получится
gemini, который чат, сам предложил наплодить ключей и их ротировать или открыть триальный аакаунт на гугл клауде и там дадут 200 баксов, их хватит нагенерить книг
может есть какие-то другие пути? речь именно не про озвучку механическую, как ютуб завалили, а естественную, это только gemini, насколько я понял
loveprod Автор
Тут честно не подскажу. Сам в поиске чего-то лучше, чем ms
WhiteBehemoth
Если есть немного ресурсов на компе, стоит посмотреть на локальные варианты. Вот не так давно обзор был https://habr.com/ru/companies/raft/articles/991844/ там в серёдке упоминается проект на f5 tts который даёт результат, на мой взгляд, лучше, чем "Дмитрий" от microfoft (кстати я у них пробовал "интернациональные" голоса, они живее четырёх "русских", и на некоторых из DragonHDLatestNeural акцента почти не было).
Если решитесь на локальный вариант, посмотрите обсуждения на 4pda https://4pda.to/forum/index.php?showtopic=1110815 - это живая тема от автора "русификатора для F5 TTS.
Этот F5 чем хорош? - позволяет ставить ударения через знак "+". А если загонять через Azure voice AI - там только SSML разметка с указанием IPA транскрипции.