Runs F5-TTS (SWivid) as a service on macOS, on the Apple GPU (MPS), without Pinokio in the picture at all.
Third project in the same family as kokoro-tts-mac-service and xtts-mac-service. Same shape, different model. F5-TTS is flow matching based, lighter than XTTS, with very good zero-shot voice cloning.
Same motivation as the sister repos: have a TTS service that's just there, on a known port, surviving reboots and crashes, on the Apple GPU. The differences this time:
- No Pinokio. F5-TTS already has a CLI Gradio entry point. We just create a venv and call it.
- No code patch. F5-TTS upstream already detects MPS and sets
PYTORCH_ENABLE_MPS_FALLBACK=1internally. So all the work is in packaging.
- F5-TTS at
http://127.0.0.1:7862, 24/7. - Inference on the Apple GPU. Roughly the same throughput as XTTS in MPS (around 2.5 to 3 chars/s after warmup), but with smaller model and faster cold start.
- Co-exists with Kokoro on 7860 and XTTS on 7861. Run all three, address each by URL.
- Auto-restart if the process crashes.
- Voice cloning from a 5 to 30 second reference WAV. F5 can also auto-transcribe the reference with Whisper if you don't pass
ref_text.
- macOS (tested on Sequoia, Apple Silicon).
- Python 3.12 on PATH.
brew install python@3.12works. Avoid 3.13 for now (some torch wheels still flaky). - ~3 GB of disk: ~1.3 GB for the F5TTS_v1_Base checkpoint, ~1 GB for torch, ~700 MB for transformers and friends.
git clone https://github.com/linuxelitebr/f5-tts-mac-service.git
cd f5-tts-mac-service
./scripts/install.shThe installer will:
- Create
./envwith Python 3.12 if it doesn't exist. pip install f5-ttsfrom PyPI.- Render
com.f5.tts.plistwith your real paths, drop it in~/Library/LaunchAgents/. - Load the LaunchAgent and wait for Gradio to answer on :7862.
First boot downloads the F5TTS_v1_Base checkpoint (~1.3 GB) plus the Vocos vocoder, so factor in 2 to 5 minutes on a decent connection. Boots after that are just model-to-MPS, which is fast.
Open http://127.0.0.1:7862. Upload a 5 to 30 second reference WAV, write your prompt, generate. F5 also auto-transcribes the reference with Whisper, so you don't strictly need to provide the reference text.
from gradio_client import Client, handle_file
c = Client("http://127.0.0.1:7862")
audio_path, spectrogram, ref_text, _ = c.predict(
ref_audio_input=handle_file("path/to/your/voice-sample.wav"),
ref_text_input="", # leave empty to auto-transcribe
gen_text_input="Hello in my own voice, generated on the Apple GPU.",
remove_silence=False,
randomize_seed=True,
seed_input=0,
cross_fade_duration_slider=0.15,
nfe_slider=32,
speed_slider=1.0,
api_name="/basic_tts",
)
print(audio_path)nfe_slider(default 32): number of function evaluations the flow matcher runs. Lower is faster, higher is more refined. Useful range 16 to 64. The diff is audible in the upper register.speed_slider(default 1.0): straight playback speed multiplier.cross_fade_duration_slider(default 0.15): when F5 generates long text it splits in chunks; this is the crossfade between chunks in seconds. Lower for snappier delivery, higher to mask seams in noisy refs.ref_text_input(default ""): if you pass it, F5 skips the Whisper transcribe step and is faster + more deterministic.
| Thing | Command | What it does |
|---|---|---|
| Start | ./scripts/start.sh |
Idempotent. Returns 0 instantly if already up. |
| Stop | ./scripts/stop.sh |
Unloads the agent for this session. Comes back at next login. |
| Status | ./scripts/status.sh |
Plist + LaunchAgent + HTTP, all in one screen. |
| Tail stdout | tail -f logs/f5.out.log |
|
| Tail stderr | tail -f logs/f5.err.log |
./scripts/test.shThree checks: launchd state, HTTP, and an E2E voice cloning call using the bundled F5 example WAV (or whatever F5_REF_AUDIO points at).
F5_REF_AUDIO=/path/to/your-voice.wav ./scripts/test.shf5-tts package on PyPI ships f5_tts.infer.infer_gradio with a Click CLI that already takes --port and --host. The utils_infer module already does:
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"So we just venv + pip install + LaunchAgent. No source modification.
~/Library/LaunchAgents/com.f5.tts.plist runs as your user, on your login. Same shape as the sister projects: RunAtLoad=true, KeepAlive only on crash, ThrottleInterval=10, PYTHONUNBUFFERED=1.
./scripts/uninstall.sh # just unloads the service
./scripts/uninstall.sh --purge # also nukes the venv and the F5 model cache- First call is the slowest (around 90s for short text) because of MPS JIT warmup. Subsequent calls land in roughly 25 to 30s for ~70 chars.
- Reference quality matters a lot. Mono, 22 to 24 kHz, normalized, no background noise. F5 is good but not magical.
- F5 transcribes Portuguese references fine with Whisper on the auto path. If your reference is in PT and your generation is in EN, it still works because Whisper just reads the timbre/pacing.
- The PyPI package is ~3 GB resolved. Mostly torch + transformers. Live with it.
- Model and code: SWivid/F5-TTS (MIT-ish, see upstream)
- Vocoder: charactr/vocos
MIT for the wrapper code in this repo. F5-TTS upstream and its weights have their own terms (very permissive). See LICENSE.