Skip to main content
Glama

FireRedTTS3 — mehrsprachiges TTS (24 Sprachen, inkl. Ukrainisch)

Lokaler Sprachsynthese-Dienst auf FireRedTTS3 mit HTTP-API und MCP-Server, auf Port :8020.

Das Modell erschien am 13.08.2026, Lizenz Apache 2.0, Gewichte sind öffentlich.

Was du vor dem Start wissen solltest

Es gibt keine Preset-Stimmen. Leere Bibliothek = nichts zu synthetisieren. Zuerst legst du eine Stimme aus einer beliebigen Sprachaufnahme an (add_firered_voice), danach verwendest du sie unter ihrem Namen. Das Modell klont zero-shot direkt während der Synthese.

Ein Transkript der Referenz ist erforderlich. Dem Modell reicht das Audio allein nicht — es braucht auch den Text dessen, was darin zu hören ist. Übergibst du keinen, erkennen wir es mit Whisper, aber dein eigener Text ist immer genauer.

Es gibt keine Betonungen. Weder Wörterbuch, noch ByT5-Fallback, noch manuelles Му+дрого. Betonungen setzt das Modell selbst aus dem Kontext und bei Homografen (за́мок/замо́к) wird es sich vertun. Das ist eine prinzipielle Einschränkung des mehrsprachigen Modells.

Related MCP server: STT2TTS MCP

Installation

cd /Users/admin/Projects/firered-tts
./setup.sh                    # venv + залежності + апстрім + патч + ваги

setup.sh erledigt vier Dinge: es richtet .venv mit Python 3.11 und torch 2.8.0 unter MPS/CPU ein, klont das Upstream in vendor/FireRedTTS3 auf dem festgepinnten Commit 00570ad, patcht es für Apple Silicon (siehe unten) und zieht die Gewichte base+redae (~11,4 GB) in pretrained_models/.

Gewichte separat (dauert lange — besser detached):

nohup ./download-weights.sh base > data/download.log 2>&1 &
./download-weights.sh instruct   # +7.9 ГБ, для дизайну голосу й редагування

Wozu der Patch

Das Upstream ist ausschließlich für NVIDIA geschrieben und startet auf dem Mac überhaupt nicht: flash_attn lässt sich auf Metal prinzipbedingt nicht bauen, das Gerät ist als cuda fest verdrahtet, autocast ist mit Nägeln an CUDA festgenagelt. Der Patch ersetzt flash_attention_2 durch sdpa (funktioniert überall, auch auf NVIDIA), macht das Gerät dynamisch und fügt Optimierungen aus dem Abschnitt zur Geschwindigkeit hinzu. Die vollständige Liste steht im Kopf von src/patch_upstream.py.

Der Patch ist idempotent und schlägt fehl, wenn die Ersetzung nicht greift — wenn sich das Upstream geändert hat, erfährst du das sofort und nicht durch einen CUDA-Fehler bei der ersten Synthese.

Start

./run.sh                      # http://localhost:8020

Separat starten ist nicht nötig — der MCP-Server startet das Backend selbst. Das Backend fährt nach Leerlauf herunter und gibt den Speicher frei.

HTTP-API

Methode

Endpunkt

Funktion

GET

/health

Status, Gerät, welches Modell im Speicher liegt

GET

/voices

Stimmnamen (Filter gender, language; full=1 → mit Metadaten)

GET

/languages

24 Sprachen + 21 Dialekte

POST

/clone_voice

Referenz + Transkript → Stimme

DELETE

/voices/{name}

Stimme löschen (die Originalaufnahme wird nicht angefasst)

POST

/tts

Text → Audio-Bytes in der Antwort

POST

/synthesize

Text → Datei in DATA_DIR, JSON mit Pfad

POST

/voice_design

Stimmbeschreibung → Audio (instruct)

POST

/edit

Bearbeitung der Aufnahme: semantic | acoustic (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.mp3

MCP

Siehe mcp_server/README.md. Kurz:

claude mcp add firered-tts -- /Users/admin/Projects/firered-tts/.venv/bin/python \
  /Users/admin/Projects/firered-tts/mcp_server/server.py

Werkzeuge: firered_backend_status, list_firered_voices, add_firered_voice, delete_firered_voice, synthesize_firered_speech, design_firered_voice, edit_firered_speech.

Speicher

Mac mini M4, 16 GB. Gewichte auf der Platte: base (7,9) + redae (3,5) = 11,4 GB. Im Speicher weniger — das LLM-Backbone lebt in half (4,2 statt 8,4 GB) —, aber auf 16 GB ist das trotzdem knapp. Die Konsequenzen sind im Code angelegt:

  • im Speicher liegt genau ein Modell — base oder instruct; Umschalten = vollständiges Neuladen (Minuten, wird laut protokolliert);

  • die Synthese ist durch einen globalen Lock serialisiert — zwei parallele Anfragen auf 16 GB ergeben OOM, keine Beschleunigung;

  • Auto-Stopp nach 1800 s Leerlauf — bewusst lang: ein Neustart kostet ~40 s Shader-Kompilierung, daher ist es günstiger, den Prozess am Leben zu halten;

  • Whisper für die Auto-Transkription — int8 auf CPU, wird direkt nach der Erkennung entladen.

Geschwindigkeit und vier Optimierungen

Ein naiver Start des Upstreams auf dem M4 ergab ×186 Echtzeit — 3 Sekunden Ukrainisch wurden in 9 Minuten berechnet. Nach vier Korrekturen sind es ×3.0, also etwa ~60-mal schneller. Was genau falsch war (alles gemessen mit tools/profile_steps.py):

1. Autocast im AR-Schleifenschritt — das Hauptproblem. Das Upstream hängt @torch.autocast als Dekorator an _backbone_one_step, d. h. die Region wird bei JEDEM autoregressiven Schritt geöffnet und geschlossen. Der Cache für Gewichts-Recasts in torch lebt exakt innerhalb der Region, also wurden 1,7B fp32-Parameter bei jedem Schritt in half umgewandelt. Backbone-Schritt: 19000 → 2710 ms. Jetzt ist autocast deaktiviert und der Cast erfolgt explizit an der Backbone-Grenze.

2. Backbone in fp32. Die Gewichte sind in float32 gespeichert (3,0B Parameter), was auf 16 GB Swapping bedeutet. Wir wandeln nur das LLM-Backbone in half um (4,2 GB statt 8,4), während redae und der Flow-Decoder fp32 bleiben — half bricht dort MPS-matmul. Schritt: 2710 → 1387 ms.

3. Die Referenz wurde für jeden Satz neu kodiert. generate() wird für jeden Satz des Textes aufgerufen, und jeder Aufruf ließ den redae-Encoder über dieselbe Referenzaufnahme laufen: 5,6 s jedes Mal, unabhängig von der Textlänge. Jetzt gibt es einen Cache mit Schlüssel nach Audio-Inhalt. Bei 6,6 min Audio — 30 Treffer gegen 2 Fehlversuche, ~11 % der Laufzeit.

4. Kompilierung der Metal-Shader. Der größte Teil der „Langsamkeit" erwies sich als einmalig: Metal kompiliert die Kerne bei der ersten Ausführung. Einzelmessungen des Backbone-Schritts: 9873, 2104, 120, 93, 96, 97… ms. Deshalb macht der Dienst beim Start ein Warm-up (FIREDRED_WARMUP=1) und hat ein langes Leerlauf-Timeout.

Gemessen auf Mac mini M4 / 16 GB, 3,0 s Ukrainisch, aufgewärmtes Modell:

n_timesteps

Zeit

×Echtzeit

Qualität

10 (Standard)

12 s

×4.0

Referenz

6

10 s

×3.0

Unterschied kaum hörbar

4

7 s

×2.3

merklich gröber

2

6 s

×1.9

deutliche Artefakte

Profil der aufgewärmten Generierung: Flow-Decoder 57 %, Backbone 18 %, redae 11 % — der wirksamste Hebel ist genau n_timesteps. Echtzeit gibt es nicht, aber es ist bereits ein arbeitstaugliches Werkzeug, kein „lass es über Nacht laufen".

Textnormalisierung

Das eingebaute TN (wetext) kennt nur Chinesisch und Englisch, daher ist es für Ukrainisch nutzlos und wir installieren es nicht. 19:30, 250 грн, 2026 р. spricht das Modell aus, wie es eben geht. Zwei Auswege: den Text direkt in Worten schreiben, oder LLM-TN aktivieren — FIRED_TN_API_URL / _API_KEY / _MODEL in .env. Geeignet ist jeder OpenAI-kompatible Endpunkt, auch ein lokaler (llama.cpp / vLLM / Ollama) — dann bleibt alles offline.

Lizenz

Code und Gewichte — Apache 2.0. Im README des Upstreams steht separat, dass Zero-Shot- Klonen „solely for academic research purposes" sei — das widerspricht Apache 2.0 und bei der kommerziellen Nutzung geklonter Stimmen solltest du vorsichtig sein. Für die private Nutzung stellt sich die Frage nicht.

Related MCP Connectors

Related MCP Servers