How FluidAudio Handles Model Downloads and Caching
FluidAudio uses a centralized download subsystem to pull pre-trained Core ML models from Hugging Face (or custom registries), cache them in platform-specific directories, and verify integrity before loading them into MLModel instances.
FluidAudio, the open-source speech processing framework from fluidinference, relies on a robust model management layer to deliver Core ML assets efficiently. Understanding how FluidAudio handles model downloads and caching is essential for deploying offline-capable applications, optimizing network usage, and troubleshooting deployment issues.
Registry Configuration
ModelRegistry provides a single point of truth for constructing URLs and configuring the HTTP session used throughout the download pipeline.
The base URL can be overridden programmatically, via the REGISTRY_URL or MODEL_REGISTRY_URL environment variables, or defaults to https://huggingface.co【/Sources/FluidAudio/ModelRegistry.swift#L30-L38】. Proxy settings are read from http_proxy / https_proxy (macOS only) and added to the URLSessionConfiguration through configureProxySettings()【/Sources/FluidAudio/ModelRegistry.swift#L94-L126】.
A shared URLSession is exposed through DownloadUtils.sharedSession so every downloader re-uses the same configuration【/Sources/FluidAudio/DownloadUtils.swift#L10-L12】.
// Example: Override the registry URL at runtime
ModelRegistry.baseURL = "https://my-mirror.example.com"
Cache Layout and Storage Locations
FluidAudio uses platform-specific directories to store downloaded assets, with different model types cached in distinct locations to avoid conflicts.
TTS Models (Kokoro / PocketTTS)
These are cached under ~/.cache/fluidaudio/Models/ on macOS and Linux, or the platform-specific caches directory on iOS. The TtsModels.getCacheDirectory() method creates ~/.cache/fluidaudio if missing and returns the path【/Sources/FluidAudioEspeak/TextToSpeech/TtsModels.swift#L86-L102】.
ASR, VAD, and Diarization Models
These are stored in the Application Support folder: ~/Library/Application Support/FluidAudio/Models/ on macOS【/Sources/FluidAudio/DownloadUtils.swift#L13-L19】.
Both locations are created lazily the first time a model is downloaded.
The Download Flow
The download process follows a cache-first strategy that minimizes network traffic and ensures atomic updates.
High-Level Entry Points
For TTS models, TtsModels.download(variants:from:directory:) builds the target directory, resolves the list of model file names, and calls DownloadUtils.loadModels【/Sources/FluidAudioEspeak/TextToSpeech/TtsModels.swift#L27-L48】.
For ASR, VAD, and Diarizer components, each invokes DownloadUtils.loadModels(repo:modelNames:directory:computeUnits:) directly (e.g., ASRModels.load(...) inside the ASR module).
Cache-First Verification
loadModelsOnce (called by loadModels) first creates the destination folder, then checks whether all required model files already exist【/Sources/FluidAudio/DownloadUtils.swift#L44-L50】. If they do, no network traffic occurs and the cached models are loaded immediately.
Repository Enumeration
If cache validation fails, downloadRepo walks the remote repository using the Hugging Face tree API (/api/models/.../tree/main/...). It builds a list of files that match the required patterns (model folders, metadata, binary blobs)【/Sources/FluidAudio/DownloadUtils.swift#L33-L88】.
Streaming and Error Handling
For each entry, a URLRequest is created with optional Authorization: Bearer <HF_TOKEN> header via DownloadUtils.authorizedRequest【/Sources/FluidAudio/DownloadUtils.swift#L24-L33】. The request is handed to sharedSession.download(for:), which writes a temporary file and then moves it to the final location【/Sources/FluidAudio/DownloadUtils.swift#L30-L55】.
- Zero-byte files are handled specially (created locally) because Hugging Face returns a 500 error for them【/Sources/FluidAudio/DownloadUtils.swift#L20-L24】.
- Rate-limit (
429/503) and generic HTTP errors are wrapped intoHuggingFaceDownloadErrorand surfaced to the caller【/Sources/FluidAudio/DownloadUtils.swift#L42-L48】.
Model Instantiation
After download, each model directory is verified to contain coremldata.bin. The model is then instantiated with a custom MLModelConfiguration that selects the appropriate compute units (.cpuAndNeuralEngine for TTS, .cpuAndGPU for Kokoro)【/Sources/FluidAudio/DownloadUtils.swift#L58-L62】.
let config = MLModelConfiguration()
config.computeUnits = .cpuAndNeuralEngine
let model = try MLModel(contentsOf: modelPath, configuration: config)
Cache Management Utilities
FluidAudio provides utilities to manage disk space used by cached models.
- Clear a single repository –
DownloadUtils.clearModelCache(forRepo:directory:). - Clear all caches –
DownloadUtils.clearAllModelCaches()removes both the Application Support and the~/.cache/fluidaudiotrees【/Sources/FluidAudio/DownloadUtils.swift#L100-L131】.
These utilities are used by the CLI (fluidaudio clear-cache) and in integration tests.
Practical Code Examples
Downloading TTS Models (Kokoro)
import FluidAudioEspeak
let variants: Set<ModelNames.TTS.Variant> = [.fiveSecond, .fifteenSecond]
// Download (or reuse cached) models into the default cache directory
let ttsModels = try await TtsModels.download(
variants: variants,
progressHandler: { progress in
print("Download progress: \(Int(progress * 100))%")
}
)
// Access a specific model for synthesis
if let model = ttsModels.model(for: .fiveSecond) {
// Use `model` with the KokoroSynthesizer
}
The method internally calls DownloadUtils.loadModels and stores files under ~/.cache/fluidaudio/Models/kokoro/.
Loading an ASR Model Directly
import FluidAudio
let repo = Repo.asr // defined in ModelNames.swift
let modelNames = ["asr_coreml.model"] // names required for the selected repo
let models = try await DownloadUtils.loadModels(
repo,
modelNames: modelNames,
directory: try ModelRegistry.configuredCacheDirectory(),
computeUnits: .cpuAndGPU
)
let asrModel = models["asr_coreml.model"]!
Configuring Proxies and Custom Registries
// Use a corporate mirror and an HTTP proxy
ModelRegistry.baseURL = "https://my-mirror.company.com"
setenv("http_proxy", "http://proxy.company.com:3128", 1)
// Subsequent downloads will respect these settings automatically
let _ = try await TtsModels.download()
Clearing the Model Cache
import FluidAudio
DownloadUtils.clearAllModelCaches()
print("All downloaded models have been removed.")
Summary
- FluidAudio manages Core ML models through a centralized registry system that defaults to Hugging Face but supports custom mirrors via
ModelRegistry.baseURL. - Cache-first architecture ensures that
DownloadUtils.loadModelschecks local storage in~/.cache/fluidaudio/(TTS) or~/Library/Application Support/FluidAudio/(ASR/VAD) before initiating network requests. - Robust download pipeline handles zero-byte files, rate limiting, and authentication tokens, streaming files via a shared
URLSessionconfigured for proxy support. - Automatic model instantiation validates downloaded
coremldata.binfiles and configures compute units (CPU/GPU/Neural Engine) appropriate for each model type.
Frequently Asked Questions
Can FluidAudio work completely offline?
Yes, once models are cached, FluidAudio operates entirely offline. The loadModels method performs a cache-first check【/Sources/FluidAudio/DownloadUtils.swift#L44-L50】; if all required files exist locally, no network connection is established. Ensure you download models during the initial setup while connected to the internet.
How do I use a private Hugging Face model repository?
Set the HF_TOKEN environment variable or configure the authorization header in your application. The DownloadUtils.authorizedRequest method automatically injects Authorization: Bearer <HF_TOKEN> into download requests【/Sources/FluidAudio/DownloadUtils.swift#L24-L33】. Additionally, override ModelRegistry.baseURL if using a private registry mirror.
Where exactly are models stored on macOS?
TTS models (Kokoro, PocketTTS) reside in ~/.cache/fluidaudio/Models/, while ASR, VAD, and diarization models are stored in ~/Library/Application Support/FluidAudio/Models/【/Sources/FluidAudioEspeak/TextToSpeech/TtsModels.swift#L86-L102】【/Sources/FluidAudio/DownloadUtils.swift#L13-L19】. Both paths are created lazily on first download.
What happens if a download is interrupted?
FluidAudio streams files to temporary locations before atomic moves to the final cache path【/Sources/FluidAudio/DownloadUtils.swift#L30-L55】. If a download is interrupted, the temporary file is discarded, and the next request will restart the download for that specific file. The cache-first check ensures partial downloads do not satisfy future requests; only complete, verified files are used.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →