# How to Add Custom API Providers Like OpenAI and Groq for AI Enhancement in FluidVoice

> Easily add custom API providers like OpenAI and Groq to FluidVoice for AI enhancement. Configure your preferred service via URL and API key in the UI for seamless integration.

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

---

**FluidVoice supports OpenAI-compatible endpoints out of the box, allowing you to plug in Groq, Azure OpenAI, or self-hosted services by simply configuring the base URL and API key in the Settings UI.**

FluidVoice is an open-source macOS dictation application that leverages large language models to post-process and enhance transcription accuracy. Adding custom API providers like OpenAI and Groq for AI enhancement in FluidVoice requires no code changes for OpenAI-compatible services, while custom protocols need only a minimal provider implementation. The architecture abstracts all HTTP networking behind a generic `AIProvider` protocol, making it trivial to swap between cloud and self-hosted AI backends.

## Understanding the Provider-Agnostic Architecture

FluidVoice’s AI enhancement layer is built on a flexible, provider-agnostic design centered around the `OpenAICompatibleProvider` class. Any service implementing the OpenAI HTTP API specification—including Groq, Azure OpenAI, or private endpoints—works immediately without modification.

The system relies on three core components:

- **UI Configuration**: Captures base URLs and API keys securely
- **Networking Layer**: Handles request construction and authentication
- **Model Repository**: Parses available models from provider endpoints

Because the networking code in [`Sources/Fluid/Networking/AIProvider.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Networking/AIProvider.swift) is deliberately generic, FluidVoice treats any OpenAI-compatible endpoint identically, whether it is OpenAI’s official API or a custom self-hosted instance.

## Configuring OpenAI and Groq in the Settings UI

### Provider Selection and Enum

The provider enum resides in [`Sources/Fluid/UI/AISettingsView.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/UI/AISettingsView.swift) at line 75, defining the built-in choices including OpenAI and Groq:

```swift
// Sources/Fluid/UI/AISettingsView.swift
case openai = "OpenAI"

```

The interactive picker that renders this list is implemented in [`Sources/Fluid/UI/SearchableProviderPicker.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/UI/SearchableProviderPicker.swift) at line 175. When users select a provider, the app stores the identifier (e.g., `"openai"` or `"groq"`) for later use by the networking layer.

### API Key and Base URL Configuration

Once a provider is selected, `Sources/Fluid/UI/AISettingsView+AIConfiguration.swift` (lines 1526-2688) displays the configuration fields:

- **OpenAI-compatible base URL**: The endpoint root (e.g., `https://api.groq.com/openai/v1`)
- **API Key**: Stored securely in the macOS Keychain via [`SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/SettingsStore.swift)
- **Model Selection**: Populated dynamically from the provider’s model list

For Groq specifically, users simply select "Groq" from the picker and enter their API key. The default base URL points to Groq’s OpenAI-compatible endpoint, requiring no additional configuration.

## The Networking Layer: OpenAICompatibleProvider

All OpenAI-style services are wrapped by the `OpenAICompatibleProvider` class found in [`Sources/Fluid/Networking/AIProvider.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Networking/AIProvider.swift) (lines 7-83). This class constructs requests by appending `/chat/completions` to the user-provided base URL and injects the API key as a Bearer token:

```swift
// Sources/Fluid/Networking/AIProvider.swift
final class OpenAICompatibleProvider: AIProvider {
    // Appends /chat/completions for OpenAI-compatible endpoints
    // Line 83: Constructs the full URL path
}

```

The provider handles streaming responses and function-calling payloads using the same logic for any OpenAI-compatible service. This means Groq, Azure, or custom endpoints receive identical request formatting without code changes.

## Model Discovery and Provider Mapping

When FluidVoice queries a provider for available models, [`Sources/Fluid/Services/ModelRepository.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/ModelRepository.swift) handles the parsing. The file maps provider identifiers to display names at line 94:

```swift
// Sources/Fluid/Services/ModelRepository.swift
case "openai": return "OpenAI"

```

At line 306, the repository parses the OpenAI-style response format:

```json
{ "data": [{ "id": "model-name" }, ...] }

```

If you add a new provider that returns models in this format, no changes are needed. For custom response formats, you extend the parser in this file to handle the new JSON structure.

## Adding a Fully Custom API Provider

For services that deviate from the OpenAI specification—different endpoint paths, custom authentication headers, or unique payload formats—you must implement a custom provider class:

1. **Create a new provider class** in [`Sources/Fluid/Networking/AIProvider.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Networking/AIProvider.swift) (or a new file) implementing the `AIProvider` protocol
2. **Override `requestHeaders()`** to inject custom authentication (e.g., `X-API-Key` instead of `Authorization: Bearer`)
3. **Override `endpointPath()`** to return custom paths (e.g., `/v2/generate` instead of `/chat/completions`)
4. **Register the provider** in [`Sources/Fluid/Services/ModelRepository.swift`](https://github.com/altic-dev/FluidVoice/blob/main/Sources/Fluid/Services/ModelRepository.swift) by adding a new case in the provider identifier switch
5. **Expose UI fields** in `Sources/Fluid/UI/AISettingsView+AIConfiguration.swift` for any additional parameters

Here is a minimal skeleton for a custom provider:

```swift
// Sources/Fluid/Networking/CustomProvider.swift
final class CustomProvider: AIProvider {
    private let baseURL: URL
    private let apiKey: String
    
    init(baseURL: URL, apiKey: String) {
        self.baseURL = baseURL
        self.apiKey = apiKey
    }
    
    override func requestHeaders() -> [String: String] {
        [
            "Authorization": "Bearer \(apiKey)",
            "X-Custom-Auth": "my-custom-value"
        ]
    }
    
    override func endpointPath(for request: AIRequest) -> String {
        // Custom endpoint path
        return "/v2/completions"
    }
}

```

After implementation, `LLMClient` automatically uses your new class for dictation enhancement without requiring changes to the transcription pipeline.

## Quick Setup Examples

### Connecting to Groq

1. Open **Settings → AI Enhancement**
2. Select **"Groq"** from the searchable provider picker
3. Enter your Groq API key (stored in macOS Keychain)
4. Adjust the base URL if needed (defaults to `https://api.groq.com/openai/v1`)
5. Select your preferred model from the populated dropdown

### Connecting to a Self-Hosted OpenAI-Compatible Service

1. Open **Settings → AI Enhancement**
2. Select **"OpenAI"** (the UI treats any OpenAI-compatible endpoint the same)
3. Set **Base URL** to your server (e.g., `https://my-llm.local/v1`)
4. Paste your server’s API key
5. Choose the model name your server advertises

## Summary

- **OpenAI-compatible services** (Groq, Azure, self-hosted) require only UI configuration in `AISettingsView+AIConfiguration.swift` with no code changes
- **Core networking** is handled by `OpenAICompatibleProvider` in [`AIProvider.swift`](https://github.com/altic-dev/FluidVoice/blob/main/AIProvider.swift), which appends `/chat/completions` and injects Bearer tokens
- **Model lists** are parsed by [`ModelRepository.swift`](https://github.com/altic-dev/FluidVoice/blob/main/ModelRepository.swift), supporting standard OpenAI response formats out of the box
- **Custom protocols** require implementing the `AIProvider` protocol with custom `requestHeaders()` and `endpointPath()` methods
- **Security** is managed through [`SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/SettingsStore.swift), which persists API keys in the macOS Keychain

## Frequently Asked Questions

### What is the default base URL for Groq in FluidVoice?

The default base URL for Groq points to `https://api.groq.com/openai/v1`, which Groq provides as an OpenAI-compatible endpoint. You can override this in the Settings UI if you are using a proxy or custom routing.

### Can I use Azure OpenAI with FluidVoice?

Yes. Select "OpenAI" from the provider picker and set the base URL to your Azure OpenAI endpoint (e.g., `https://your-resource.openai.azure.com/openai/deployments/your-deployment-name`). Enter your Azure API key in the API key field. The `OpenAICompatibleProvider` class handles the standard Azure OpenAI request format.

### Where are API keys stored in FluidVoice?

API keys are stored securely in the macOS Keychain via [`SettingsStore.swift`](https://github.com/altic-dev/FluidVoice/blob/main/SettingsStore.swift). They are never written to plaintext preferences and are retrieved only when constructing network requests in [`AIProvider.swift`](https://github.com/altic-dev/FluidVoice/blob/main/AIProvider.swift).

### Do I need to rebuild FluidVoice to add a new provider?

Only if the provider uses a non-OpenAI-compatible API. For OpenAI-compatible endpoints (including Groq), you only need to enter the base URL and API key in the Settings UI. For custom protocols, you must add a new provider class to [`AIProvider.swift`](https://github.com/altic-dev/FluidVoice/blob/main/AIProvider.swift) and register it in [`ModelRepository.swift`](https://github.com/altic-dev/FluidVoice/blob/main/ModelRepository.swift), then rebuild the application.