-
Notifications
You must be signed in to change notification settings - Fork 1
Speech to Text
The original Zerm capability: press a hotkey, speak, and the transcript is pasted at your cursor.
flowchart TB
HK[Hotkey down] --> UIM[RecorderUIManager.toggleMiniRecorder]
UIM --> SND[start sound after CoreAudio is live]
UIM --> ENG[ZermEngine.toggleRecord]
ENG --> REC[Recorder / CoreAudioRecorder<br/>AUHAL, background queue]
ENG --> LOAD[WhisperModelManager.loadModel<br/>concurrent Task.detached]
HK2[Hotkey up / silence] --> PIPE[ZermEngine.runPipeline]
PIPE --> WAIT[wait until model loaded]
WAIT --> TX[TranscriptionService.transcribe]
TX --> FILT[output filter + WordReplacementService]
FILT --> ENH[AIEnhancementService.enhance · optional]
ENH --> PASTE[CursorPaster.startPasteAtCursor]
| Provider | Type | Key file |
|---|---|---|
| Whisper (local) | Local ggml | WhisperTranscriptionService.swift |
| Parakeet / FluidAudio | Local ANE | FluidAudioTranscriptionService.swift |
| Apple Speech | Local | NativeAppleTranscriptionService.swift |
| OpenAI, Gemini, Deepgram, … | Cloud | CloudTranscriptionService.swift |
| Deepgram, ElevenLabs streaming | Cloud streaming | StreamingTranscriptionService.swift |
Models live in …/WhisperModels/. Loading runs on DispatchQueue.global (blocking C call) inside a detached task; runPipeline waits for isModelLoading == false before transcribing — this prevents the "first transcription after idle fails" bug. Flash attention is on by default (with a fallback for q5_0/q8_0).
CursorPaster uses a CGEvent ⌘V by default. The AppleScript paste path (opt-in) runs @MainActor because TIS keyboard APIs must be on the main queue (macOS 26 fix).
Detects the frontmost app and, for browsers, the active tab URL (inline AppleScript targeting the frontmost regular-policy browser instance), then selects context-appropriate enhancement settings.
See: AI Enhancement · Architecture