The Problem

FluidVoice is a macOS dictation app that performs voice‑to‑text entirely offline, using local models (Parakeet, Whisper, Apple Speech). Users who need a private, low‑latency transcription solution without cloud dependencies can benefit from it, but the codebase shows several maintainability risks that affect onboarding and long‑term evolution.

What This Does

FluidVoice captures audio via the microphone, streams it to one of several ASR back‑ends, and either displays a live preview or types the result into the front‑most application. Core flow starts in Sources/Fluid/ContentView.swift, which instantiates Services/ASRService.swift to manage recording (through Services/AudioDeviceService.swift) and delegates recognition to a chosen provider (e.g., Sources/Fluid/Services/WhisperProvider.swift, Sources/Fluid/Services/ParakeetVocabularyStore.swift, or Sources/Fluid/Services/AppleSpeechProvider.swift). The transcribed text flows through Services/TypingService.swift for global hotkey‑driven input, while Services/CommandModeService.swift and Sources/Fluid/UI/CommandModeView.swift handle a secondary “command mode” that interprets spoken phrases as actions. Settings and model selection are managed by view models such as Sources/Fluid/UI/AISettings/AIEnhancementSettingsViewModel.swift and Sources/Fluid/Services/LLMClient.swift. The app persists user preferences in Sources/Fluid/Persistence/SettingsStore.swift and transcription history in Sources/Fluid/Persistence/TranscriptionHistoryStore.swift.

How It Is Wired

  • Entry point: Sources/Fluid/fluidApp.swift (SwiftUI app entry) → ContentView.swift sets up the UI and registers services.
  • Audio capture: AudioDeviceService.swift starts/stops a microphone session; ThreadSafeAudioBuffer.swift buffers chunks.
  • ASR routing: ASRService.swift selects a provider based on user choice; each provider (Whisper, Parakeet, Apple Speech) implements a common TranscriptionProvider protocol.
  • Typing: TypingService.swift uses macOS accessibility APIs to inject text; guarded by accessibility permissions.
  • Model management: ModelRepository.swift resolves model paths; vocabularies are stored in Resources/parakeet_custom_vocabulary.default.json.
  • No internal circular dependencies: the import graph resolves 97 Swift files with 0 internal modules or circular edges, but the sheer size of some files (e.g., ContentView.swift at 2049 lines) gives them a wide blast radius—changes ripple across the recording → recognition → typing pipeline.

How To Use It

  1. Clone the repo ``bash git clone https://github.com/moses-y/FluidVoice.git cd FluidVoice ``
  2. Open in Xcode ``bash open Fluid.xcodeproj ``
  3. Build & run – press ⌘R. All dependencies are resolved via Swift Package Manager (listed in Package.swift).
  4. First launch – the app prompts for microphone permission and accessibility permission (needed for typing). Grant “Always allow”.
  5. Configure hotkey – open Settings → Hotkey and assign a key; the setting is saved in SettingsStore.swift (keychain‑backed).
  6. Optional AI enhancement – add an API key for OpenAI, Groq, etc., in AIEnhancementSettingsViewModel.swift; keys are stored securely in the macOS Keychain.
  7. Beta builds – enable the beta channel via Settings → Automatic Updates → Beta Releases if you want early builds.

Real‑World Use

A user gives a spoken command (“Add “Buy milk” to my grocery list”) while working in any macOS app. FluidVoice captures the audio, runs it through the default Parakeet TDT v3 model on‑device, and types the recognized text into the front‑most text field via the global hotkey. No server round‑trip occurs, keeping latency under 300 ms on Apple Silicon and preserving privacy.

Code Health & Issues

  • Measured static analysis (97 Swift files examined):
  • 76 total findings: 37 high, 39 medium, 0 low.
  • Deep nesting in 47 locations, max indentation depth 10 – e.g., Sources/Fluid/ContentView.swift, Sources/Fluid/Services/ASRService.swift, Sources/Fluid/Services/CommandModeService.swift.
  • Duplicated code: 224 repeated 6‑line blocks across 34 files, including ContentView.swift, AIEnhancementSettingsViewModel.swift, WelcomeView.swift.
  • Oversized files: 12 files exceed 2000 lines (ContentView.swift, SettingsStore.swift, ASRService.swift).
  • Repository SDLC observations:
  • CI/CD present (GitHub Actions) but third‑party actions not pinned to commit SHAs.
  • GITHUB_TOKEN permissions not explicitly declared in the build workflow.
  • Test suite minimal: 2 integration tests vs 93 source files (coverage ≈ 2 %).
  • License file present; no Dockerfile or lockfile committed.

Code Health Audit (3 findings, ranked by severity/confidence):

  • HIGH – Pin third‑party GitHub Actions to a commit SHA (.github/workflows). Replace @vN with 40‑char SHA; let Dependabot bump SHAs.
  • MEDIUM – Declare least‑privilege permissions for GITHUB_TOKEN in the build workflow (build.yml); add permissions: contents: read at the top and widen per job as needed.
  • MEDIUM – Expand the test suite; currently only 2 test files cover the codebase. Add tests for highest‑fan‑in modules first.

The Bottom Line

FluidVoice delivers a fast, fully offline dictation experience on macOS with a modular but sizable codebase. The app works well out‑of‑the‑box for users needing private transcription, yet the source contains deep nesting, duplicated logic, and a few large files that raise maintenance overhead. The CI hygiene gaps (unpinned actions, missing token permissions) and the sparse test coverage are the most pressing risks for anyone planning to extend or ship the project long‑term. It’s a solid foundation for a local voice‑to‑text tool, but will benefit from refactoring the identified hot‑spots and tightening CI security.