How FluidVoice Handles Parakeet and Nemotron Model Downloads and Caching
FluidVoice downloads Parakeet and Nemotron speech-recognition models on-demand to platform-specific cache directories, validating integrity through markup detection and atomic file writes before loading them as Core ML providers.
FluidVoice, an open-source Swift framework by altic-dev, distributes its neural speech-recognition engines—Parakeet and Nemotron—as Core ML models hosted on Hugging Face. Rather than bundling these large binaries within the app bundle, the framework implements a self-healing download pipeline that fetches, validates, and caches model artifacts only when required.
Cache Directory Structure
FluidVoice separates caching logic between its two primary speech-recognition providers, each using distinct filesystem locations appropriate for their data lifecycles.
Parakeet Storage Location
Parakeet stores artifacts in an app-support subdirectory designed for model persistence. The ParakeetRealtimeProvider constructs this path via cacheRootDirectory(), resolving to "FluidAudio/Models/parakeet-eou-streaming" under the application support directory → Sources/Fluid/Services/ParakeetRealtimeProvider.swift#L45-L56.
Nemotron Storage Location
Nemotron utilizes the user-domain caches folder, scoped by a dynamic folderHint parameter. The NemotronProvider exposes cacheDirectory which resolves to a subdirectory within FileManager.SearchPathDirectory.cachesDirectory → Sources/Fluid/Services/NemotronProvider.swift#L72-L75.
Validation and Integrity Checks
Before initiating any network requests, both providers verify whether cached artifacts exist and are uncorrupted through strict validation gates.
Artifact Completeness Verification
The HuggingFaceModelDownloader class provides artifactsAreComplete(root:items:), which checks that every required file in the model manifest exists and contains data. Parakeet wraps this call in missingRequiredModelFiles() → Sources/Fluid/Services/ParakeetRealtimeProvider.swift#L21-L32, while Nemotron exposes artifactsAreComplete(at:) → Sources/Fluid/Services/NemotronProvider.swift#L82-L92.
Corruption Detection via Markup Analysis
To detect proxy-block pages or corrupted downloads, HuggingFaceModelDownloader.cachedPayloadContainsMarkup(root:relativePaths:) scans cached files for HTML/XML signatures → Sources/Fluid/Networking/ModelDownloader.swift#L78-L90. If markup is detected, the provider deletes the corrupted files and triggers a fresh download.
Download Pipeline and Atomic Writes
When validation fails or caches are missing, the providers invoke ensureModelsPresent(at:onProgress:), which orchestrates the download through four strict stages:
- Repository Listing: Queries the Hugging Face API to enumerate required files from the model repository.
- Streaming Download: Downloads each file to a temporary location with per-file progress callbacks.
- Strict Validation:
validateDownloadedFilechecks HTTP status codes, content-length headers, content-type consistency, and re-runs the markup heuristic →Sources/Fluid/Networking/ModelDownloader.swift#L113-L135. - Atomic Write: Validated files move from temporary storage to the cache directory via
FileManager.moveItem(at:to:). If sizes mismatch expectations, the operation fails and retries.
Provider Initialization
Once artifacts pass validation, providers instantiate their respective Core ML managers. Parakeet initializes StreamingEouAsrManager, while Nemotron creates NemotronStreamingAsrManager. Only after successful instantiation does the provider set isReady = true, indicating the model is loaded into memory and available for transcription.
Cache Invalidation
Both providers expose clearCache() to force eviction of downloaded models. This method deletes the entire cache directory tree, resets internal state flags, and requires a subsequent prepare() call to re-download artifacts.
For Parakeet: → Sources/Fluid/Services/ParakeetRealtimeProvider.swift#L56-L64
For Nemotron: → Sources/Fluid/Services/NemotronProvider.swift#L125-L138
Implementation Examples
Triggering a Parakeet Download
let provider = ParakeetRealtimeProvider(chunkSize: .ms160)
Task {
do {
// Downloads missing Parakeet Flash artifacts if needed
try await provider.prepare { progress in
print("Download progress: \(progress * 100.0)%")
}
print("Parakeet ready:", provider.isReady)
} catch {
print("Failed to prepare Parakeet:", error)
}
}
Triggering a Nemotron Download
let nemotron = NemotronProvider(mode: .streaming)
Task {
do {
// Ensures Nemotron files exist in cache
try await nemotron.prepare { progress, file in
print("[\(file)] \(progress * 100.0)%")
}
print("Nemotron ready:", nemotron.isReady)
} catch {
print("Nemotron error:", error)
}
}
Clearing Cache Manually
Task {
try await provider.clearCache() // Parakeet
try await nemotron.clearCache() // Nemotron
}
Checking Cache Existence Without Downloading
if provider.modelsExistOnDisk() {
print("Parakeet models cached")
}
if nemotron.modelsExistOnDisk() {
print("Nemotron models cached")
}
Summary
- FluidVoice treats Parakeet and Nemotron as on-demand Core ML models fetched from Hugging Face.
- Parakeet caches to
"FluidAudio/Models/parakeet-eou-streaming"under app support; Nemotron uses the user caches directory. - Integrity checks include
artifactsAreComplete()validation andcachedPayloadContainsMarkup()to detect corruption. - Atomic writes ensure files are only committed to cache after passing HTTP, size, and content-type validation.
- Clear cache functionality forces re-download by deleting cache directories and resetting provider state.
Frequently Asked Questions
How does FluidVoice detect corrupted model downloads?
FluidVoice uses HuggingFaceModelDownloader.cachedPayloadContainsMarkup() to scan cached files for HTML or XML content, which typically indicates a proxy block or failed redirect rather than binary model data. If detected, the corrupted files are deleted immediately before triggering a fresh download → Sources/Fluid/Networking/ModelDownloader.swift#L78-L90.
What happens if a download is interrupted mid-stream?
Files download to temporary URLs and only move to the final cache location via FileManager.moveItem() after validateDownloadedFile() confirms the content-length and content-type match expectations. Interrupted downloads leave incomplete temporary files that are discarded on the next prepare() invocation.
Can I change the default cache location for Nemotron models?
The NemotronProvider cache directory derives from FileManager.SearchPathDirectory.cachesDirectory combined with a folderHint parameter. While the framework does not expose a public API to override the root path, you can manipulate the folderHint during provider initialization to create subdirectories within the standard caches folder.
Where does Parakeet store its cached model files?
Parakeet stores models under the application support directory at "FluidAudio/Models/parakeet-eou-streaming", as determined by ParakeetRealtimeProvider.cacheRootDirectory() in Sources/Fluid/Services/ParakeetRealtimeProvider.swift → L45-L56.
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 →