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 implement
  • ASRService — the singleton façade that routes transcription requests to the active provider
  • VoiceEngineSettingsViewModel — 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:

  1. Open FluidVoice → click the gear icon → select Voice Engine
  2. Choose your desired provider from the list (e.g., Qwen 3 ASR)
  3. 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:

  1. Create a new class conforming to TranscriptionProvider in Sources/Fluid/Services/
  2. Add your provider's identifier to VoiceEngineSettingsViewModel
  3. Update ASRService to instantiate your class when your identifier is selected
  4. The existing UserDefaults key 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: Qwen3ASRProvider requires significantly more RAM than WhisperProvider; 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 VoiceEngineSettingsViewModel for download progress UI bindings

Summary

  • FluidVoice uses ASRService as a unified interface to multiple ASR backends
  • Provider selection persists via UserDefaults key asrProviderSelection
  • Two switch methods: Settings UI (no code) or programmatic UserDefaults updates with invalidateCurrentProvider()
  • Built-in providers: WhisperProvider (default, efficient) and Qwen3ASRProvider (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:

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 →