firered-tts
FireRedTTS3 — багатомовний TTS (24 мови, вкл. українську)
Локальний сервіс синтезу мовлення на FireRedTTS3 з HTTP-API і MCP-сервером, на порту :8020.
Модель вийшла 13.08.2026, ліцензія Apache 2.0, ваги публічні.
Що варто знати до старту
Пресетних голосів немає. Порожня бібліотека = синтезувати нічим. Спершу
заводиш голос із будь-якого запису мовлення (add_firered_voice), далі
вживаєш його за іменем. Модель клонує zero-shot прямо під час синтезу.
Потрібен транскрипт референсу. Моделі мало самого аудіо — треба ще текст того, що в ньому звучить. Не передаси — розпізнаємо Whisper'ом, але свій текст завжди точніший.
Наголосів немає. Ні словника, ні ByT5-фолбека, ні ручного Му+дрого.
Наголоси модель ставить сама з контексту й на омографах (за́мок/замо́к)
плутатиме. Це принципове обмеження багатомовної моделі.
Встановлення
cd /Users/admin/Projects/firered-tts
./setup.sh # venv + залежності + апстрім + патч + вагиsetup.sh робить чотири речі: піднімає .venv з Python 3.11 і torch 2.8.0
під MPS/CPU, клонує апстрім у vendor/FireRedTTS3 на запиненому комміті
00570ad, патчить його під Apple Silicon (див. нижче) і тягне ваги
base+redae (~11.4 ГБ) у pretrained_models/.
Ваги окремо (довго — краще detached):
nohup ./download-weights.sh base > data/download.log 2>&1 &
./download-weights.sh instruct # +7.9 ГБ, для дизайну голосу й редагуванняНавіщо патч
Апстрім написаний виключно під NVIDIA і на Mac не запускається взагалі:
flash_attn на Metal не збирається в принципі, пристрій зашитий як cuda,
autocast прибитий цвяхами до CUDA. Патч замінює flash_attention_2 на sdpa
(працює скрізь, у т.ч. на NVIDIA), робить пристрій динамічним і додає
оптимізації з розділу про швидкість. Повний список — у шапці
src/patch_upstream.py.
Патч ідемпотентний і падає, якщо заміна не влучила — якщо апстрім змінився, ти дізнаєшся про це одразу, а не CUDA-помилкою на першому синтезі.
Запуск
./run.sh # http://localhost:8020Окремо запускати не обов'язково — MCP-сервер підніме бекенд сам. Бекенд вимикається після простою і звільняє пам'ять.
HTTP API
Метод | Ендпойнт | Що робить |
|
| статус, пристрій, яка модель у пам'яті |
|
| імена голосів (фільтри |
|
| 24 мови + 21 діалект |
|
| референс + транскрипт → голос |
|
| видалити голос (оригінал запису не чіпається) |
|
| текст → аудіо-байти у відповіді |
|
| текст → файл у |
|
| опис голосу → аудіо (instruct) |
|
| правка запису: |
# 1) завести голос
curl -X POST localhost:8020/clone_voice -H 'Content-Type: application/json' -d '{
"audio": "prompts/зразок.wav", "name": "Богдан",
"prompt_text": "Це зразок мого голосу для клонування.",
"language": "Ukrainian", "gender": "male"}'
# 2) озвучити
curl -X POST localhost:8020/tts -H 'Content-Type: application/json' -d '{
"text": "Сьогодні чудова погода, ходімо гуляти в парк.",
"voice": "Богдан", "format": "mp3"}' -o out.mp3
# Або one-shot — без реєстрації голосу: передай reference_audio замість voice,
# транскрипт зробить Whisper (перший виклик +~30с, далі кешується)
curl -X POST localhost:8020/tts -H 'Content-Type: application/json' -d '{
"text": "Сьогодні чудова погода.", "reference_audio": "prompts/зразок.mp3",
"format": "mp3"}' -o out.mp3MCP
Див. mcp_server/README.md. Коротко:
claude mcp add firered-tts -- /Users/admin/Projects/firered-tts/.venv/bin/python \
/Users/admin/Projects/firered-tts/mcp_server/server.pyІнструменти: firered_backend_status, list_firered_voices,
add_firered_voice, delete_firered_voice, synthesize_firered_speech,
design_firered_voice, edit_firered_speech.
Пам'ять
Mac mini M4, 16 ГБ. Ваги на диску: base (7.9) + redae (3.5) = 11.4 ГБ.
У пам'яті менше — LLM-бекбон живе у half (4.2 замість 8.4 ГБ), — але на
16 ГБ це все одно впритул. Наслідки, закладені в код:
у пам'яті живе рівно одна модель —
baseабоinstruct; перемикання = повне перезавантаження (хвилини, голосно логується);синтез серіалізований глобальним локом — два паралельні запити на 16 ГБ дають OOM, а не прискорення;
автозупинка за простоєм 1800с — довга навмисно: рестарт коштує ~40с компіляції шейдерів, тож тримати процес живим вигідніше;
Whisper для автотранскрипту —
int8на CPU, вивантажується одразу після розпізнавання.
Швидкість і чотири оптимізації
Наївний запуск апстріму на M4 давав ×186 реального часу — 3 секунди
української рахувались 9 хвилин. Після чотирьох виправлень стало ×3.0,
тобто у ~60 разів швидше. Що саме було не так (усе заміряно
tools/profile_steps.py):
1. Autocast на кроці AR-циклу — головна біда. Апстрім вішає
@torch.autocast декоратором на _backbone_one_step, тобто регіон
відкривається й закривається на КОЖНОМУ кроці авторегресії. Кеш перекастів ваг
у torch живе рівно всередині регіону, тож 1.7B параметрів fp32 переганялись у
half щокроку. Крок бекбону: 19000 → 2710 мс. Тепер autocast вимкнений, а
каст робиться явно на межі бекбону.
2. Бекбон у fp32. Ваги збережені у float32 (3.0B параметрів), що на 16 ГБ означає своп. Переводимо в half лише LLM-бекбон (4.2 ГБ замість 8.4), а redae і flow-декодер лишаємо fp32 — half ламає там MPS-matmul. Крок: 2710 → 1387 мс.
3. Референс кодувався заново на кожне речення. generate() викликається
на кожне речення тексту, і кожен виклик проганяв redae-енкодер по тому самому
референсному запису: 5.6с щоразу, незалежно від довжини тексту. Тепер
кеш із ключем за вмістом аудіо. На 6.6 хв аудіо — 30 влучань проти 2
промахів, ~11% часу прогону.
4. Компіляція Metal-шейдерів. Найбільша частина «повільності» виявилась
разовою: Metal компілює ядра при першому виконанні. Поштучні заміри кроку
бекбону: 9873, 2104, 120, 93, 96, 97… мс. Тому сервіс робить прогрів на
старті (FIRERED_WARMUP=1) і має довгий таймаут простою.
Заміряно на Mac mini M4 / 16 ГБ, 3.0с української, прогріта модель:
n_timesteps | Час | ×реального часу | Якість |
10 (дефолт) | 12 с | ×4.0 | еталон |
6 | 10 с | ×3.0 | різниця ледь чутна |
4 | 7 с | ×2.3 | помітно грубіше |
2 | 6 с | ×1.9 | помітні артефакти |
Профіль прогрітої генерації: flow-декодер 57%, бекбон 18%, redae 11% —
найдієвіший важіль саме n_timesteps. Real-time немає, але це вже робочий
інструмент, а не «запусти на ніч».
Text normalization
Вбудований TN (wetext) знає лише китайську й англійську, тож для
української він марний і ми його не ставимо. 19:30, 250 грн, 2026 р.
модель озвучить як вийде. Два виходи: писати текст одразу словами, або
увімкнути LLM-TN — FIRERED_TN_API_URL / _API_KEY / _MODEL у .env.
Годиться будь-який OpenAI-сумісний ендпойнт, включно з локальним
(llama.cpp / vLLM / Ollama) — тоді все лишається офлайн.
Ліцензія
Код і ваги — Apache 2.0. У README апстріму окремо написано, що zero-shot клонування «solely for academic research purposes» — це суперечить Apache 2.0 і на комерційне використання клонованих голосів дивись обережно. Для домашнього використання питання не стоїть.