Голос диктора (references/voice.md)
Источник:
ds-internal/presentations/component-video-skill/references/voice.md— справочник скилла astra-component-video
Справочник к объясняющим роликам. Голос синтезируется локально, без внешних сервисов: тексты не уходят из компании, у ролика нет подписки и лимитов.
Какой движок
| Как звучит | живой голос, без акцента | быстро, но слышно «машинность» и акцент |
| Голос | по описанию: VoiceDesign создаёт эталон, Base читает им все фразы | пять готовых: baya, kseniya, xenia, aidar, eugene |
| Латиница | читает: React, Flutter, YAML — как есть | не читает: только кириллица, «Реакт», «Фигма» |
| Железо | видеокарта NVIDIA, 4,4 ГБ памяти | процессор |
| Скорость | минута голоса ≈ 5 минут | 25 фраз ≈ 10 секунд |
| Лицензия | Apache 2.0 — можно публиковать | CC BY-NC 4.0 — только внутренние ролики |
Автор роликов Silero забраковал: «ломанный, слышен акцент». Брать Qwen3. Silero — когда нет видеокарты и нужен черновик, чтобы проверить хронометраж.
Установка — один раз
Голосу нужно отдельное окружение Python с torch: в основное его не ставить. Путь к его
интерпретатору — в переменной ASTRA_TTS_PYTHON, по ней build.mjs запускает озвучку.
Qwen3-TTS:
python -m venv <папка>/qwen-tts-venv
<venv>/python -m pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu128
<venv>/python -m pip install qwen-tts soundfile numpy scipy
huggingface-cli download Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign --local-dir <модели>/Qwen3-TTS-12Hz-1.7B-VoiceDesign
huggingface-cli download Qwen/Qwen3-TTS-12Hz-1.7B-Base --local-dir <модели>/Qwen3-TTS-12Hz-1.7B-Base
huggingface-cli download Qwen/Qwen3-TTS-Tokenizer-12Hz --local-dir <модели>/Qwen3-TTS-Tokenizer-12Hz
Переменные: ASTRA_TTS_PYTHON=<venv>/python (в Windows — <venv>\Scripts\python.exe),
ASTRA_QWEN_DIR=<модели>. Около 9 ГБ моделей.
- Видеокарты RTX 50xx (Blackwell, sm_120) видит только torch со сборкой CUDA 12.8 (
cu128): старые сборки молча работают на процессоре или падают. - flash-attn под Windows не ставится —
voice.pyвключаетsdpa, это нормально. - Предупреждение SoX при импорте
qwen_tts— не мешает. - Проверено: torch 2.11 cu128, qwen-tts 0.1.1, transformers 4.57, RTX 5060 Ti.
Silero:
python -m venv <папка>/tts-venv
<venv>/python -m pip install torch numpy scipy
curl -sSL -o <модели>/v5_6_ru.pt https://models.silero.ai/models/tts/ru/v5_6_ru.pt
Переменные: ASTRA_TTS_PYTHON, ASTRA_TTS_MODEL=<модели>/v5_6_ru.pt (148 МБ).
Проверка Whisper'ом: pip install faster-whisper в любое из этих окружений. Модель small
(около 500 МБ) скачается при первом запуске.
Без окружения голоса ролик с уже озвученными фразами всё равно собирается: build.mjs видит,
что тексты не менялись, и модель не запускает. Так собирается образец design-contract-short.
Настройки в данных ролика
narrator: {
engine: "qwen3",
design: "A calm, confident male narrator in his mid-thirties. Warm, clear voice, native Russian speaker with natural pronunciation and no accent. Moderate pace, friendly explainer tone, like a professional documentary voice-over. Studio-quality recording, no background noise.",
sample: "Привет! Сегодня я расскажу, как дизайн и разработка договариваются о компоненте. Это займёт пару минут.",
tempo: 1.3,
},
voice: "Фраза на обложке.", // звучит на обложке
outroVoice: "Фраза на финале.", // звучит на финале, необязательно
slides: [{ …, voice: ["Фраза 1.", "Фраза 2."] }],
engine | qwen3 или silero (по умолчанию silero) |
design | описание голоса по-английски: пол, возраст, тембр, манера, «native Russian speaker … no accent», качество записи. Сверху — голос роликов Astra DS: брать его, пока автор не попросил другой |
sample | русская фраза-эталон, 15–20 слов в манере ролика: ею VoiceDesign задаёт голос |
tempo | во сколько раз быстрее синтеза: 1,3 — утверждённый темп. Ускоряет фильтр atempo ffmpeg, высота голоса не меняется; новый темп не требует нового синтеза |
speaker | голос Silero, по умолчанию baya (ноль ошибок распознавания на пробной фразе; у kseniya тоже) |
Смена design или sample — новый эталон и переозвучка всего ролика. Пробы двух голосов
(мужской и женский) перед выбором — короткий ролик на 3–4 фразы с тем же текстом.
Как голос ведёт картинку
- Фразы части встают подряд: 0,3 с до первой, 0,2 между, 0,5 после последней.
- Сцена идёт за голосом: кончается с последней фразой, а не досиживает анимацию.
Последнее действие на экране видно ещё секунду;
hold: 2.5у сцены — дольше, например для финальной мысли. beat: kу элемента сцены — элемент встаёт на k-й фразе (с нуля). Несколько элементов с однимbeatвстают равномерно по первым 70 % фразы. Безbeat— по своему ритму.focus.delayуchain— сдвиг выделения от начала фразы, если на ней же появляется последний шаг.- Обложка длится не меньше своей фразы; финал — не меньше
outroVoice.
Порядок сборки — голос раньше музыки: озвучка → метки и длина → музыка по меткам → сведение.
build.mjs проходит его сам. Вручную:
<ASTRA_TTS_PYTHON> -I -X utf8 tools/voice.py say videos/<ролик>.js
node tools/cues.mjs
python -I -X utf8 tools/synth_music.py videos/<ролик>.cues.json assets/audio/<ролик>-music.wav
python -I -X utf8 tools/voice.py mix videos/<ролик>.cues.json assets/audio/<ролик>-music.wav assets/audio/<ролик>.wav
node tools/cues.mjs
sayпишет фразы вassets/<ролик>/voice/(синтез — вraw/, с темпом — рядом), длительности — вvideos/<ролик>.voice.js. Этот файл создаёт толькоvoice.py: руками не править. Повторныйsayпереозвучивает только изменённые фразы.- В
index.htmlу ролика с голосом строка<script src="videos/<ролик>.voice.js">после файла данных;build.mjsставит и убирает её сам. mixвыравнивает фразы по громкости, приглушает музыку под рассказом на 9 дБ целиком и ещё на 7 дБ на самих фразах (в паузах не «качает»), выводит рассказ к −16 dBFS RMS, пик не выше −1 dBFS. Фраза, чья длина разошлась с метками, останавливает свод: метки устарели — снять заново.
Время на ролик в три минуты: озвучка Qwen3 — около 15 минут (только в первый раз; потом — изменённые фразы), музыка, сведение и снимки — около минуты, рендер — около 10 минут. Долгое — в фоне.
Как писать текст для голоса
Общие правила — references/infostyle.md, раздел 8. Для модели:
- фраза 8–15 слов, одна мысль; «но», «а», «поэтому» в начале — можно;
- числа — словами: «двести шестьдесят четыре», так вернее склонение (Silero цифры пропускает);
- «ИИ» модель читает как одно «и» — в голосе «нейросеть»;
- Silero: только кириллица, Figma — «Фигма», React — «Реакт»; ударение — плюсом перед гласной:
+оси стан+овятся. Qwen3 плюсы убирает сам; - короткие слова вроде «ось» модель проглатывает — фразу перестроить;
- имена собственные сливаются («Натан Кёртис» → «на танке Ортис» у Silero) — проверить распознаванием, при нужде перестроить;
- скорость — около 12 знаков в секунду при темпе 1: минута рассказа ≈ 700 знаков;
- на экране — то же, что звучит, только короче: голос «Мы берём компонент из Фигмы вместе с его описанием» → карточка «Figma · компонент и его описание».
Проверка без прослушивания
<python с faster-whisper> -I -X utf8 tools/voice_check.py <ролик>
Whisper распознаёт каждую фразу и сравнивает с текстом, около двух секунд на фразу. Выводит:
✗— слова разошлись: прослушать фразу, явную ошибку (слово пропало, слилось, другое ударение) исправить — перестроить фразу и переозвучить;~— разошлись только цифры или латиница: Whisper пишет «264» и «Skill», это не ошибка голоса.
Порог совпадения — 0,8 (--min). На ролике design-contract-v3 (58 фраз, 21.10.2026) отмечено 4
фразы ✗: «из Фигмы» прозвучало как «с фигмы» (дважды), имя «Кристин Валлор», «Скилл».
Лицензии
В отчёте назвать модель и лицензию: Qwen3-TTS — Apache 2.0; Silero v5_6_ru — CC BY-NC 4.0,
ролик только для внутреннего пользования. Голос по описанию синтетический — чужой голос
не клонируется; модели с клонированием по образцу (ESpeech-TTS, F5-TTS) автор брать не стал.