Каждый из вас хоть раз ловил себя на мысли: «А почему бы не начать слушать книги вместо того, чтобы их читать?». Пока едешь в метро, стоишь в пробке, занимаешься домашней рутиной или вместо приевшейся музыки в спортзале — сценариев масса.
В сети полно литературы, но если вы эстет и ищете что-то глубже «Онегина» или модных бестселлеров, то наверняка сталкивались с проблемой: нужной книжки в аудио просто не существует.
Так вот, тут мы попадаем в ловушку. Технологий синтеза речи (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» — разделяй и властвуй. Вместо того чтобы просить нейросеть прочитать книгу целиком, мы рубим ее на куски (мелкие чанки) и запускаем армию виртуальных дикторов одновременно.
Облако Microsoft (Edge TTS) ограничивает скорость отдачи потока на одно соединение, но практически не ограничивает количество одновременных запросов с одного IP. То есть использование инструмента xargs с флагом -P (parallel) позволяет запустить 12–16 потоков одновременно.
В таком режиме мы заставляем облако работать на пике производительности, утилизируя доступный канал связи, а не ожидая своей очереди в однопоточном режиме. Это превращает процесс из изнурительного ожидания в высокоскоростную конвейерную сборку.
Первые тесты параллельной сборки выявили проблему. Кириллица в UTF-8 не так проста: каждый символ занимает два байта. Если резать файл как есть, по размеру (байтам), разрез обязательно попадает на середину буквы. В итоге вместо текста Python получает «мусорный» байт, вылетает с ошибкой «UnicodeDecodeError», и процесс сразу крашится.
Решение нашлось в классической утилите fold с флагом -s. Она умеет делать «мягкие» переносы строк, ориентируясь на пробелы. Это гарантирует, что каждый чанк текста останется валидным для Python-декодера, а слова не будут превращены в нечитаемый набор байтов. Теперь данные уходят в облако в идеальном состоянии.
Предрекаю ваш вопрос: «Почему не через виртуальное окружение Python?». Мой подход строится на принципе «одна задача — один сервер». Разворачивая «Прометей» на выделенном воркере, я превращаю его в узкоспециализированный вычислительный модуль.
Изоляция через venv здесь избыточна. Она лишь усложняет цепочку вызовов в Bash-скриптах и добавляет лишний слой абстракции там, где нужна прямая работа с системными бинарниками. Нам нужен максимально короткий путь от текста к звуку.
Многие админы по привычке используют /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):
Процессор i3-12100 (Alder Lake) вполне неплохо и стабильно управляет 12 потоками. Текущая вычислительная мощность используется не полностью, так что тут есть небольшой запас на разбег в случае необходимости — сохраняется запас производительности и низкое время отклика.
Нагрузка на CPU (top):
Слышу вопрос от эстетов: «А как же связность речи на стыках чанков?» Технически каждая нейронная сессия в 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}
Теперь создадим управляющий скрипт. Вам нужно создать файл в папке /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 часов эксклюзивного контента за один вечер просто потому, что могу. Теперь это можете сделать и вы. Не ждите, пока за вас решат, что и как вам слушать. Делайте это сами.
Источник


