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.swiftsets up the UI and registers services. - Audio capture:
AudioDeviceService.swiftstarts/stops a microphone session;ThreadSafeAudioBuffer.swiftbuffers chunks. - ASR routing:
ASRService.swiftselects a provider based on user choice; each provider (Whisper, Parakeet, Apple Speech) implements a commonTranscriptionProviderprotocol. - Typing:
TypingService.swiftuses macOS accessibility APIs to inject text; guarded by accessibility permissions. - Model management:
ModelRepository.swiftresolves model paths; vocabularies are stored inResources/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.swiftat 2049 lines) gives them a wide blast radius—changes ripple across the recording → recognition → typing pipeline.
How To Use It
- Clone the repo ``
bash git clone https://github.com/moses-y/FluidVoice.git cd FluidVoice`` - Open in Xcode ``
bash open Fluid.xcodeproj`` - Build & run – press ⌘R. All dependencies are resolved via Swift Package Manager (listed in
Package.swift). - First launch – the app prompts for microphone permission and accessibility permission (needed for typing). Grant “Always allow”.
- Configure hotkey – open
Settings → Hotkeyand assign a key; the setting is saved inSettingsStore.swift(keychain‑backed). - Optional AI enhancement – add an API key for OpenAI, Groq, etc., in
AIEnhancementSettingsViewModel.swift; keys are stored securely in the macOS Keychain. - Beta builds – enable the beta channel via
Settings → Automatic Updates → Beta Releasesif 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_TOKENpermissions 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@vNwith 40‑char SHA; let Dependabot bump SHAs. - MEDIUM – Declare least‑privilege permissions for
GITHUB_TOKENin the build workflow (build.yml); addpermissions: contents: readat 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.