Function bodies 17 total
OpenWispr class · ruby · L1-L30 (30 LOC)Formula/open-wispr.rb
class OpenWispr < Formula
desc "Push-to-talk voice dictation for macOS using Whisper"
homepage "https://github.com/human37/open-wispr"
url "https://github.com/human37/open-wispr.git", tag: "v0.9.1"
license "MIT"
depends_on "whisper-cpp"
depends_on :macos
def install
system "swift", "build", "-c", "release", "--disable-sandbox"
system "bash", "scripts/bundle-app.sh", ".build/release/open-wispr", "OpenWispr.app", version.to_s
bin.install ".build/release/open-wispr"
prefix.install "OpenWispr.app"
end
def post_install
target = Pathname.new("#{Dir.home}/Applications/OpenWispr.app")
target.dirname.mkpath
rm_rf target if target.exist? && !target.symlink?
ln_sf prefix/"OpenWispr.app", target
end
service do
run [opt_prefix/"OpenWispr.app/Contents/MacOS/open-wispr", "start"]
keep_alive successful_exit: false
log_path var/"log/open-wispr.log"
error_log_path var/"log/open-wispr.log"
process_type :interactive
endinstall method · ruby · L10-L15 (6 LOC)Formula/open-wispr.rb
def install
system "swift", "build", "-c", "release", "--disable-sandbox"
system "bash", "scripts/bundle-app.sh", ".build/release/open-wispr", "OpenWispr.app", version.to_s
bin.install ".build/release/open-wispr"
prefix.install "OpenWispr.app"
endpost_install method · ruby · L17-L22 (6 LOC)Formula/open-wispr.rb
def post_install
target = Pathname.new("#{Dir.home}/Applications/OpenWispr.app")
target.dirname.mkpath
rm_rf target if target.exist? && !target.symlink?
ln_sf prefix/"OpenWispr.app", target
endcaveats function · ruby · L32-L43 (12 LOC)Formula/open-wispr.rb
def caveats
<<~EOS
Recommended: use the install script for guided setup:
curl -fsSL https://raw.githubusercontent.com/human37/open-wispr/main/scripts/install.sh | bash
Or start manually:
brew services start open-wispr
Grant Accessibility and Microphone when prompted.
The Whisper model downloads automatically (~142 MB).
EOS
endAudioRecorder class · swift · L4-L84 (81 LOC)Sources/OpenWisprLib/AudioRecorder.swift
class AudioRecorder {
private var audioEngine: AVAudioEngine?
private var audioFile: AVAudioFile?
private var isRecording = false
private var currentOutputURL: URL?
// Serial queue protects audioFile from concurrent access between audio thread and main thread
private let writeQueue = DispatchQueue(label: "com.openwisprmod.audiowrite")
/// No-op — engine is created fresh per recording session to avoid stale-tap crashes.
func warmUp() {}
func startRecording(to outputURL: URL) throws {
guard !isRecording else { return }
// Always create a fresh engine — avoids stale-tap NSException crashes
// (seen on macOS 26 when reusing a paused engine across sessions)
let engine = AVAudioEngine()
let inputNode = engine.inputNode
let inputFormat = inputNode.outputFormat(forBus: 0)
let targetFormat = AVAudioFormat(
commonFormat: .pcmFormatFloat32,
sampleRate: 16000,
channelHelpController class · swift · L3-L105 (103 LOC)Sources/OpenWisprLib/HelpController.swift
class HelpController: NSWindowController {
private static var shared: HelpController?
static func show() {
if shared == nil { shared = HelpController() }
shared?.showWindow(nil)
NSApp.activate(ignoringOtherApps: true)
shared?.window?.makeKeyAndOrderFront(nil)
}
override func loadWindow() {
let panel = NSPanel(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 560),
styleMask: [.titled, .closable, .resizable],
backing: .buffered,
defer: false
)
panel.title = "speakfree Help"
panel.minSize = NSSize(width: 380, height: 400)
panel.center()
self.window = panel
let scrollView = NSScrollView(frame: panel.contentView!.bounds)
scrollView.autoresizingMask = [.width, .height]
scrollView.hasVerticalScroller = true
scrollView.drawsBackground = false
let textView = NSTextView()
textView.isEditable = falseHotkeyManager class · swift · L5-L173 (169 LOC)Sources/OpenWisprLib/HotkeyManager.swift
class HotkeyManager {
private var eventTap: CFMachPort?
private var runLoopSource: CFRunLoopSource?
private var globalMonitor: Any?
private let keyCode: UInt16
private let requiredModifiers: UInt64
private var onKeyDown: (() -> Void)?
private var onKeyUp: (() -> Void)?
private var onAbort: (() -> Void)?
private var modifierPressed = false
/// When fn was pressed — used to distinguish keyboard shortcuts (key within 300ms) from dictation
private var modifierPressedAt: UInt64 = 0
init(keyCode: UInt16, modifiers: UInt64 = 0) {
self.keyCode = keyCode
self.requiredModifiers = modifiers
}
func start(onKeyDown: @escaping () -> Void, onKeyUp: @escaping () -> Void, onAbort: (() -> Void)? = nil) {
self.onKeyDown = onKeyDown
self.onKeyUp = onKeyUp
self.onAbort = onAbort
// For modifier-only keys (like Fn), use a CGEventTap so we can suppress
// the default system action (e.g. the emojCitation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
ModelDownloader class · swift · L3-L35 (33 LOC)Sources/OpenWisprLib/ModelDownloader.swift
public class ModelDownloader {
static let baseURL = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main"
public static func download(modelSize: String) throws {
let modelFileName = "ggml-\(modelSize).bin"
let modelsDir = Config.configDir.appendingPathComponent("models")
let destPath = modelsDir.appendingPathComponent(modelFileName)
if FileManager.default.fileExists(atPath: destPath.path) {
print("Model '\(modelSize)' already exists at \(destPath.path)")
return
}
try FileManager.default.createDirectory(at: modelsDir, withIntermediateDirectories: true)
let url = "\(baseURL)/\(modelFileName)"
print("Downloading \(modelSize) model from \(url)...")
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/curl")
process.arguments = ["-L", "--progress-bar", "-o", destPath.path, url]
process.standardError = FileHandle.standardError
ModelPickerController class · swift · L4-L122 (119 LOC)Sources/OpenWisprLib/ModelPickerController.swift
class ModelPickerController: NSWindowController {
private var onComplete: ((String) -> Void)?
private var selectedModel = "base.en"
private var progressLabel: NSTextField!
private var progressBar: NSProgressIndicator!
private var downloadButton: NSButton!
private var radioButtons: [NSButton] = []
private let modelIDs = ["tiny.en", "base.en", "small.en", "medium.en", "large"]
static func show(onComplete: @escaping (String) -> Void) {
let controller = ModelPickerController()
controller.onComplete = onComplete
controller.showWindow(nil)
NSApp.activate(ignoringOtherApps: true)
}
override func loadWindow() {
let panel = NSPanel(
contentRect: NSRect(x: 0, y: 0, width: 420, height: 330),
styleMask: [.titled],
backing: .buffered,
defer: false
)
panel.title = "Choose Whisper Model"
panel.center()
panel.isMovableByWindowBackground = truRecordingStore class · swift · L9-L133 (125 LOC)Sources/OpenWisprLib/RecordingStore.swift
public class RecordingStore {
public static var recordingsDir = Config.configDir.appendingPathComponent("recordings")
static let filePrefix = "recording-"
static let fileExtension = "wav"
static let sentinelFile = Config.configDir.appendingPathComponent(".recording-in-progress.json")
static let dateFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "yyyy-MM-dd-HHmmss"
f.locale = Locale(identifier: "en_US_POSIX")
return f
}()
public static func ensureDirectory() {
do {
try FileManager.default.createDirectory(at: recordingsDir, withIntermediateDirectories: true)
} catch {
fputs("Warning: could not create recordings directory: \(error.localizedDescription)\n", stderr)
}
}
// Always write to recordings dir, never temp — enables crash recovery regardless of maxRecordings setting
public static func newRecordingURL() -> URL {
ensureDirectory()
MenuItemTarget class · swift · L3-L7 (5 LOC)Sources/OpenWisprLib/StatusBarController.swift
class MenuItemTarget: NSObject {
let handler: () -> Void
init(handler: @escaping () -> Void) { self.handler = handler }
@objc func invoke() { handler() }
}TextInserter class · swift · L7-L156 (150 LOC)Sources/OpenWisprLib/TextInserter.swift
class TextInserter {
// Cache the 'v' key code — only changes if keyboard layout changes
private var cachedVKeyCode: CGKeyCode?
private var cachedInputSourceID: String?
// Paste text, optionally refocusing the element that was active when recording started.
// Returns true if text was pasted, false if focus couldn't be restored (text copied to clipboard instead).
@discardableResult
func insert(text: String, refocusing element: AXUIElement? = nil, onFocusLost: (() -> Void)? = nil) -> Bool {
if let element = element {
let currentElement = currentFocusedElement()
let sameElement = currentElement.map { CFEqual($0, element) } ?? false
if !sameElement {
let refocused = AXUIElementSetAttributeValue(element, kAXFocusedAttribute as CFString, kCFBooleanTrue) == .success
if refocused {
Thread.sleep(forTimeInterval: 0.15)
pasteText(text)
Transcriber class · swift · L3-L137 (135 LOC)Sources/OpenWisprLib/Transcriber.swift
public class Transcriber {
private let modelSize: String
private let language: String
public var suppressAutoPunctuation: Bool = false
public init(modelSize: String = "base.en", language: String = "en") {
self.modelSize = modelSize
self.language = language
}
public func transcribe(audioURL: URL, prompt: String? = nil) throws -> String {
guard let whisperPath = Transcriber.findWhisperBinary() else {
throw TranscriberError.whisperNotFound
}
guard let modelPath = Transcriber.findModel(modelSize: modelSize) else {
throw TranscriberError.modelNotFound(modelSize)
}
let process = Process()
process.executableURL = URL(fileURLWithPath: whisperPath)
var args = [
"-m", modelPath,
"-f", audioURL.path,
"-l", language,
"--no-timestamps",
"-nt",
]
// Spoken mode: suppress whisper's auto-punctuation so onConfigTests class · swift · L4-L158 (155 LOC)Tests/OpenWisprTests/ConfigTests.swift
final class ConfigTests: XCTestCase {
// MARK: - effectiveMaxRecordings
func testEffectiveMaxRecordingsNilDefaultsToZero() {
XCTAssertEqual(Config.effectiveMaxRecordings(nil), 0)
}
func testEffectiveMaxRecordingsZero() {
XCTAssertEqual(Config.effectiveMaxRecordings(0), 0)
}
func testEffectiveMaxRecordingsNegativeClampsToOne() {
XCTAssertEqual(Config.effectiveMaxRecordings(-5), 1)
}
func testEffectiveMaxRecordingsWithinRange() {
XCTAssertEqual(Config.effectiveMaxRecordings(1), 1)
XCTAssertEqual(Config.effectiveMaxRecordings(10), 10)
XCTAssertEqual(Config.effectiveMaxRecordings(100), 100)
}
func testEffectiveMaxRecordingsClampsAbove100() {
XCTAssertEqual(Config.effectiveMaxRecordings(200), 100)
XCTAssertEqual(Config.effectiveMaxRecordings(999), 100)
}
// MARK: - FlexBool decoding
func testFlexBoolDecodesBool() throws {
let json = #"{"spokenPunctuation": trueKeyCodesTests class · swift · L4-L122 (119 LOC)Tests/OpenWisprTests/KeyCodesTests.swift
final class KeyCodesTests: XCTestCase {
// MARK: - nameToCode
func testNameToCodeContainsAllLetters() {
for char in "abcdefghijklmnopqrstuvwxyz" {
XCTAssertNotNil(KeyCodes.nameToCode[String(char)], "Missing key: \(char)")
}
}
func testNameToCodeContainsDigits() {
for digit in 0...9 {
XCTAssertNotNil(KeyCodes.nameToCode[String(digit)], "Missing digit: \(digit)")
}
}
func testNameToCodeContainsFunctionKeys() {
for n in 1...15 {
XCTAssertNotNil(KeyCodes.nameToCode["f\(n)"], "Missing function key: f\(n)")
}
}
func testNameToCodeContainsModifiers() {
let modifiers = ["cmd", "leftcmd", "rightcmd", "shift", "leftshift", "rightshift",
"option", "leftoption", "rightoption", "alt", "leftalt", "rightalt",
"ctrl", "leftctrl", "rightctrl", "control", "rightcontrol",
"fn", "globe", "capslock"]
Same scanner, your repo: https://repobility.com — Repobility
RecordingStoreTests class · swift · L4-L108 (105 LOC)Tests/OpenWisprTests/RecordingStoreTests.swift
final class RecordingStoreTests: XCTestCase {
private var testDir: URL!
private var savedDir: URL!
override func setUp() {
super.setUp()
savedDir = RecordingStore.recordingsDir
testDir = FileManager.default.temporaryDirectory.appendingPathComponent("open-wispr-test-\(UUID().uuidString)")
try? FileManager.default.createDirectory(at: testDir, withIntermediateDirectories: true)
RecordingStore.recordingsDir = testDir
}
override func tearDown() {
try? FileManager.default.removeItem(at: testDir)
RecordingStore.recordingsDir = savedDir
super.tearDown()
}
func testNewRecordingURLCreatesValidPath() {
let url = RecordingStore.newRecordingURL()
XCTAssertTrue(url.lastPathComponent.hasPrefix("recording-"))
XCTAssertEqual(url.pathExtension, "wav")
XCTAssertTrue(url.path.contains(testDir.path))
}
func testNewRecordingURLsAreUnique() {
let url1 = RecordingStorTextPostProcessorTests class · swift · L4-L97 (94 LOC)Tests/OpenWisprTests/TextPostProcessorTests.swift
final class TextPostProcessorTests: XCTestCase {
func testPeriodReplacement() {
XCTAssertEqual(TextPostProcessor.process("hello period"), "hello.")
}
func testCommaReplacement() {
XCTAssertEqual(TextPostProcessor.process("one comma two"), "one, two")
}
func testQuestionMark() {
XCTAssertEqual(TextPostProcessor.process("how are you question mark"), "how are you?")
}
func testExclamationMark() {
XCTAssertEqual(TextPostProcessor.process("wow exclamation mark"), "wow!")
}
func testExclamationPoint() {
XCTAssertEqual(TextPostProcessor.process("wow exclamation point"), "wow!")
}
func testColon() {
XCTAssertEqual(TextPostProcessor.process("note colon"), "note:")
}
func testSemicolon() {
XCTAssertEqual(TextPostProcessor.process("first semicolon second"), "first; second")
}
func testEllipsis() {
XCTAssertEqual(TextPostProcessor.process("wait ellipsis"), "wait...")