How FluidVoice Switches Between Multiple Speech Recognition Models: A Complete Guide

FluidVoice uses a centralized SettingsStore singleton to persist the active speech model, while VoiceEngineSettingsViewModel orchestrates the switch by updating state and triggering ASR providers to reinitialize their engines.

FluidVoice supports a pluggable architecture that allows users to seamlessly switch between speech recognition models including Apple’s Parakeet, OpenAI’s Whisper, NVIDIA builds, and Cohere variants. The altic-dev/FluidVoice repository implements this through a clean separation of concerns across persistence, UI orchestration, and provider-specific ASR engines.

The SpeechModel Enum and Model Catalog

All available speech recognition backends are defined in Sources/Fluid/Persistence/SettingsStore.swift. The SettingsStore.SpeechModel enum encodes metadata for each provider, including language support, download size, and installation status.

Each case represents a specific model variant—such as .whisperTiny, .nemotronStreaming, or configurations for Apple’s Parakeet—allowing the system to track which models are available locally versus those requiring download.

Persisting User Selection with SettingsStore

The SettingsStore singleton manages the currently active model through the selectedSpeechModel property. When this value changes, the system automatically persists the selection to UserDefaults and publishes an objectWillChange notification to SwiftUI observers.

This design ensures that the active model state survives app restarts and remains accessible throughout the application through SettingsStore.shared.selectedSpeechModel.

The Switching Flow: From UI to ASR Provider

The architecture implements a reactive pipeline that propagates model changes from the user interface down to the underlying speech recognition engines.

UI Layer Presentation

The AISettingsView+SpeechRecognition.swift file renders the "Voice Engine" card that lists the active model at the top and available alternatives below. Each row displays speed/accuracy metrics and conditional action buttons—Activate for installed models or Download for those requiring local artifacts.

ViewModel Orchestration

When a user taps Activate, VoiceEngineSettingsViewModel.activateSpeechModel(_:) executes the state transition. This method in Sources/Fluid/UI/AISettings/VoiceEngineSettingsViewModel.swift performs three critical actions: it validates that areSpeechModelActionsBlocked is false, updates settings.selectedSpeechModel to persist the choice, and synchronizes previewSpeechModel to reflect the change in the UI preview panel.

ASR Provider Initialization

Concrete ASR implementations—including WhisperProvider, AppleIntelligenceProvider, and FluidAudioProvider—observe SettingsStore.shared.selectedSpeechModel and reinitialize their engines when the value changes. The providers unload previous model artifacts and load the new corresponding CoreML or external binaries, making the switch transparent to transcription and editing features.

Code Implementation Examples

You can trigger model switches programmatically or through the UI using the following patterns from the FluidVoice source code.

Programmatically select a model from a shortcut or automation script:

import Fluid

// Choose the Nemotron streaming model
SettingsStore.shared.selectedSpeechModel = .nemotronStreaming

The view-model activation logic handles validation and state updates:

// In VoiceEngineSettingsViewModel
func activateSpeechModel(_ model: SettingsStore.SpeechModel) {
    guard !areSpeechModelActionsBlocked else { return }
    // Store the new active model
    settings.selectedSpeechModel = model
    // Update UI preview
    previewSpeechModel = model
}

The UI layer triggers this activation from the model selection row:

// AISettingsView+SpeechRecognition.swift – inside `speechModelCard(for:)`
Button("Activate") {
    viewModel.activateSpeechModel(model)   // ← triggers the flow above
}
.buttonStyle(.borderedProminent)
.controlSize(.small)
.tint(Color.fluidGreen)

ASR providers read the current selection when initializing transcription sessions:

// Provider loading logic (example from WhisperProvider.swift)
let model = modelOverride ?? SettingsStore.shared.selectedSpeechModel
// `model` is the currently‑selected SpeechModel; the provider
// loads the corresponding CoreML / external artifact.

Summary

  • Model definitions reside in the SpeechModel enum within Sources/Fluid/Persistence/SettingsStore.swift, tracking metadata for each available speech recognition backend.
  • State persistence occurs through SettingsStore.shared.selectedSpeechModel, which automatically syncs to UserDefaults and publishes changes to SwiftUI observers.
  • UI orchestration is handled by VoiceEngineSettingsViewModel.activateSpeechModel(_:), which validates blockers and updates both persistent settings and preview state.
  • Provider switching happens reactively when ASR implementations like WhisperProvider or AppleIntelligenceProvider detect the selectedSpeechModel change and reinitialize their engines.
  • Integration tests in Tests/FluidDictationIntegrationTests/DictationE2ETests.swift verify the complete switching flow end-to-end.

Frequently Asked Questions

How does FluidVoice persist the selected speech model across app launches?

FluidVoice stores the active model in SettingsStore.shared.selectedSpeechModel, which automatically serializes to UserDefaults when modified. This singleton pattern ensures the selection persists between sessions and remains accessible to all ASR providers through the shared instance.

Can I switch speech recognition models while dictation is active?

While the UI allows model selection at any time via VoiceEngineSettingsViewModel.activateSpeechModel(_:), the view-model guards against conflicting actions through the areSpeechModelActionsBlocked property. The ASR provider handles the teardown of the previous engine and initialization of the new model, though active transcription sessions may briefly interrupt during the switch.

Which speech recognition providers does FluidVoice support?

According to the source code in SettingsStore.swift and various provider implementations, FluidVoice supports Apple’s Parakeet (via AppleIntelligenceProvider), OpenAI’s Whisper (via WhisperProvider), NVIDIA models, Cohere, and various Nemotron builds. Each provider reads SettingsStore.shared.selectedSpeechModel to determine which specific variant to load.

How can I programmatically switch models without using the settings UI?

You can directly assign the desired model to the shared settings store: SettingsStore.shared.selectedSpeechModel = .whisperTiny (or .nemotronStreaming, etc.). The reactive architecture ensures that VoiceEngineSettingsViewModel and all ASR providers automatically detect this change and reinitialize accordingly, without requiring manual UI interaction.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →