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

> Discover how FluidVoice efficiently manages multiple speech recognition models. Learn about its SettingsStore and VoiceEngineSettingsViewModel for seamless ASR engine switching and optimized performance.

- Repository: [ALTIC/FluidVoice](https://github.com/altic-dev/FluidVoice)
- Tags: how-to-guide
- Published: 2026-07-03

---

**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`](https://github.com/altic-dev/FluidVoice/blob/main/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`](https://github.com/altic-dev/FluidVoice/blob/main/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:

```swift
import Fluid

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

```

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

```swift
// 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:

```swift
// 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:

```swift
// 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`](https://github.com/altic-dev/FluidVoice/blob/main/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`](https://github.com/altic-dev/FluidVoice/blob/main/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`](https://github.com/altic-dev/FluidVoice/blob/main/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.