How to Switch ASR Providers in FluidVoice: A Complete Guide
FluidVoice lets you switch between speech-to-text engines like OpenAI Whisper and Qwen 3 ASR through a settings-backed provider architecture centered on ASRService.
The FluidVoice macOS app abstracts automatic speech recognition (ASR) behind a clean provider pattern. Instead of hardcoding a single transcription engine, the app stores your preference in UserDefaults and lazily instantiates the corresponding implementation of the TranscriptionProvider protocol. This guide walks through how to change ASR providers both in the UI and programmatically.
Understanding the ASR Provider Architecture
FluidVoice's transcription system is built around three core components:
TranscriptionProvider— the protocol that every ASR backend must implementASRService— the singleton façade that routes transcription requests to the active providerVoiceEngineSettingsViewModel— the settings view model that persists user selection
When you request transcription via ASRService.shared.transcribe(), the service checks the asrProviderSelection key in UserDefaults, instantiates the matching provider (e.g., WhisperProvider or Qwen3ASRProvider), and delegates the actual audio processing.
Built-in ASR Providers
| Provider | Class | Requirements | Best For |
|---|---|---|---|
| OpenAI Whisper | WhisperProvider |
macOS 13+, local model | Fast, offline transcription |
| Qwen 3 ASR | Qwen3ASRProvider |
macOS 15+, more memory | Multilingual support, higher accuracy |
Both conform to TranscriptionProvider and are located in Sources/Fluid/Services/.
Method 1: Switch ASR Providers Via Settings UI
The simplest way to change providers requires no code:
- Open FluidVoice → click the gear icon → select Voice Engine
- Choose your desired provider from the list (e.g., Qwen 3 ASR)
- Close the settings panel — your selection auto-saves to
UserDefaults
The next transcription request automatically uses the newly selected engine. VoiceEngineSettingsViewModel writes the selection to the asrProviderSelection key, and ASRService reads this on its next provider initialization.
Method 2: Switch ASR Providers Programmatically
For testing, automation, or custom UI flows, modify the provider directly in Swift:
import Fluid
func switchToProvider(_ providerId: String) {
// Update the stored preference
UserDefaults.standard.set(providerId, forKey: "asrProviderSelection")
// Invalidate current provider to force recreation
ASRService.shared.invalidateCurrentProvider()
}
// Switch to Qwen 3 ASR
switchToProvider("qwen3")
// Or revert to Whisper
switchToProvider("whisper")
Complete Transcription Example
import Fluid
func transcribeWithSelectedProvider(audioSamples: [Float]) async throws -> String {
// ASRService automatically uses the provider from UserDefaults
let result = try await ASRService.shared.transcribe(audioSamples)
return result.text
}
// Usage after switching providers
Task {
let samples: [Float] = captureAudio() // your audio capture logic
// This uses whichever provider is currently selected
let text = try await transcribeWithSelectedProvider(audioSamples: samples)
print("Transcribed: \(text)")
}
Key Source Files for ASR Provider Switching
Understanding the codebase structure helps with custom modifications:
| File | Path | Purpose |
|---|---|---|
ASRService.swift |
Sources/Fluid/Services/ASRService.swift |
Singleton service that manages provider lifecycle and routes transcription calls |
TranscriptionProvider.swift |
Sources/Fluid/Services/TranscriptionProvider.swift |
Protocol defining the interface all ASR backends must implement |
WhisperProvider.swift |
Sources/Fluid/Services/WhisperProvider.swift |
Local Whisper implementation, default provider |
VoiceEngineSettingsViewModel.swift |
Sources/Fluid/UI/AISettings/VoiceEngineSettingsViewModel.swift |
Settings model that writes asrProviderSelection to UserDefaults |
SettingsView.swift |
Sources/Fluid/UI/SettingsView.swift |
UI entry point for the voice engine selection panel |
Adding Custom ASR Providers
To integrate a new ASR engine:
- Create a new class conforming to
TranscriptionProviderinSources/Fluid/Services/ - Add your provider's identifier to
VoiceEngineSettingsViewModel - Update
ASRServiceto instantiate your class when your identifier is selected - The existing
UserDefaultskey and UI flow will automatically include your option
The protocol-based design means no changes are needed to transcription call sites — ASRService.shared.transcribe() works identically regardless of which provider is active.
Performance Considerations When Switching ASR Providers
- Memory pressure:
Qwen3ASRProviderrequires significantly more RAM thanWhisperProvider; macOS 15+ is enforced at the settings level - Cold start latency: First transcription after switching providers incurs model loading time; subsequent calls reuse the cached instance until
invalidateCurrentProvider()is called - Model downloads: Some providers may trigger background model downloads on first selection; check
VoiceEngineSettingsViewModelfor download progress UI bindings
Summary
- FluidVoice uses
ASRServiceas a unified interface to multiple ASR backends - Provider selection persists via
UserDefaultskeyasrProviderSelection - Two switch methods: Settings UI (no code) or programmatic
UserDefaultsupdates withinvalidateCurrentProvider() - Built-in providers:
WhisperProvider(default, efficient) andQwen3ASRProvider(multilingual, macOS 15+) - Protocol-based architecture enables adding custom ASR engines without modifying transcription call sites
Frequently Asked Questions
What happens to in-progress transcriptions when I switch ASR providers?
Active transcription tasks complete with their original provider. The switch only affects new requests. ASRService maintains the current provider instance until explicitly invalidated via invalidateCurrentProvider() or until the app restarts.
Can I use multiple ASR providers simultaneously in FluidVoice?
Not through the standard API. ASRService is a singleton with one active provider at a time. For parallel transcription, instantiate providers directly (e.g., WhisperProvider() and Qwen3ASRProvider()) and call their transcribe() methods independently, bypassing ASRService.
Where is my ASR provider preference stored?
The selection writes to standard UserDefaults under the key asrProviderSelection as a string identifier ("whisper", "qwen3", etc.). This persists across app launches and is readable/writeable from Swift code or command-line tools using defaults write.
Why is Qwen 3 ASR unavailable on my Mac?
VoiceEngineSettingsViewModel gates this option to macOS 15+ due to memory and framework requirements. The settings UI hides unavailable providers based on ProcessInfo.processInfo.operatingSystemVersion checks. Running on older macOS versions shows only WhisperProvider.
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 →