How to Configure AI Enhancement Settings in FluidVoice: A Complete Guide

Configure FluidVoice's AI enhancement by selecting a provider in AISettingsView, securing your API key in the macOS Keychain via AIEnhancementSettingsViewModel, and customizing models and reasoning parameters—all persisted automatically through SettingsStore.

FluidVoice is an open-source macOS dictation application that leverages large language models to enhance transcription quality. To customize this behavior, you configure AI enhancement settings through a SwiftUI interface backed by secure storage and modular view models. This guide walks through the exact implementation found in the altic-dev/FluidVoice repository, covering provider selection, credential management, and advanced reasoning configuration.

Core Components of the AI Enhancement System

AISettingsView (The UI Layer)

Located in Sources/Fluid/UI/AISettingsView.swift, this SwiftUI view hosts the configuration interface. It initializes two critical view models that drive the entire configuration flow:

@StateObject private var voiceViewModel = VoiceEngineSettingsViewModel(...)
@StateObject private var enhancementViewModel = AIEnhancementSettingsViewModel(...)

AIEnhancementSettingsViewModel (State Management)

Defined in Sources/Fluid/UI/AISettings/AIEnhancementSettingsViewModel.swift, this ObservableObject manages all runtime state. It handles provider selection, API key references, model availability, reasoning configurations, and connection testing through published properties that automatically update the UI.

SettingsStore (Persistence Layer)

Found in Sources/Fluid/Persistence/SettingsStore.swift, this class handles UserDefaults for general settings and the macOS Keychain for secure API key storage. All mutations in the view model ultimately propagate here, ensuring configurations survive app restarts.

Configuring AI Enhancement Settings Step by Step

1. Select or Create an AI Provider

The selectedProviderID property binds directly to the provider picker. Built-in providers (OpenAI, Groq, Apple Intelligence) automatically populate their base URLs via ModelRepository.defaultBaseURL(for:), while custom providers use a custom: prefix.

To create a custom provider programmatically:

if let newID = enhancementViewModel.createDraftProvider(named: "MyAI") {
    enhancementViewModel.selectProvider(newID)
}

Changing the provider triggers updateCurrentProvider(), which refreshes openAIBaseURL and availableModels for the new selection.

2. Secure API Key Configuration

API keys are never stored in plain text. Instead, AIEnhancementSettingsViewModel uses providerAPIKeys to interface with the macOS Keychain. Before displaying the key editor, the system verifies Keychain permissions through ensureKeychainAccessForAPIKeyEdit().

Update or add keys using:

enhancementViewModel.handleAPIKeyButtonTapped()
enhancementViewModel.updateProviderAPIKey("sk-mykey123", 
                                           for: enhancementViewModel.selectedProviderID)

3. Manage Available Models

The availableModelsByProvider dictionary maintains provider-specific model lists. Users can extend beyond default offerings using addNewModel() or remove entries via deleteSelectedModel(). The UI reflects current options through the availableModels computed property, which updates dynamically when switching providers.

4. Configure Reasoning Parameters

For models supporting chain-of-thought reasoning, enable the feature by toggling editingReasoningEnabled and configuring ModelReasoningConfig:

enhancementViewModel.editingReasoningEnabled = true
enhancementViewModel.editingReasoningParamName = "reasoning_effort"
enhancementViewModel.editingReasoningParamValue = "high"

When testAPIConnection() executes with usesResponsesAPI enabled, these values inject into the request payload to control reasoning depth.

5. Test the Connection

Before saving, validate the configuration by calling testAPIConnection(). This method constructs a POST request using the current provider's base URL, validates the API key from Keychain, and checks model availability. It updates connectionStatus and connectionErrorMessage to provide immediate visual feedback in the UI.

Prompt Profile Customization

Dictation enhancement prompts are stored in SettingsStore.dictationPromptProfiles. The system combines user-editable prompt bodies with hidden base prompts using SettingsStore.combineBasePrompt(for:with:). This architecture allows customization of transcription behavior without exposing or modifying system-level instructions.

Summary

  • AISettingsView.swift renders the configuration interface and injects the view models that drive the UI.
  • AIEnhancementSettingsViewModel.swift manages provider selection through selectedProviderID, handles secure API keys via providerAPIKeys, and controls model lists with availableModelsByProvider.
  • SettingsStore.swift persists settings to UserDefaults and stores API keys securely in the macOS Keychain.
  • Create custom providers beyond built-in options using createDraftProvider(named:) when you need to connect to private endpoints.
  • Enable advanced reasoning through ModelReasoningConfig properties (editingReasoningParamName, editingReasoningParamValue) for supported models.
  • Always validate setups using testAPIConnection() before beginning dictation sessions.

Frequently Asked Questions

Where are my API keys stored in FluidVoice?

API keys are stored in the macOS Keychain, accessed through the providerAPIKeys property in AIEnhancementSettingsViewModel. The app requests Keychain access permissions via ensureKeychainAccessForAPIKeyEdit() before allowing any key editing operations, ensuring credentials remain encrypted and sandbox-compliant.

Can I use custom AI providers not listed by default?

Yes. Call createDraftProvider(named:) on the view model to generate a custom provider with a custom: prefix identifier. You must manually specify the base URL, and the provider will immediately appear in the selectedProviderID picker alongside built-in options like OpenAI and Groq.

How do I add a model that isn't in the default list?

Use the addNewModel() method in AIEnhancementSettingsViewModel to append models to availableModelsByProvider. Conversely, use deleteSelectedModel() to remove unused entries. These modifications persist automatically through SettingsStore and reflect immediately in the model selection picker.

What does the reasoning configuration do?

When editingReasoningEnabled is true, FluidVoice injects reasoning parameters into API requests to enable chain-of-thought processing. Configure the exact parameter name via editingReasoningParamName (e.g., reasoning_effort) and the intensity via editingReasoningParamValue (e.g., low, medium, high) to control the model's analytical depth during transcription enhancement.

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 →