Status: ratified (M1 complete; iterations expected)
Owner: OpenQuackKit/Transcription/
Last updated: 2026-04-26
Transcribe a discrete audio buffer (file or PCM samples) into text behind a stable abstraction so engines can be swapped, compared, and benchmarked.
public protocol TranscriptionEngine: AnyObject {
static var engineName: String { get }
static var suggestedModels: [String] { get }
var modelID: String { get }
func transcribe(audioFile url: URL, language: String?) async throws -> EngineTranscription
}
public struct EngineTranscription: Sendable {
var text: String
var detectedLanguage: String?
var audioSeconds: TimeInterval
var wallSeconds: TimeInterval
var timeToFirstToken: TimeInterval?
}
public enum EngineKind: String, CaseIterable, Sendable { case whisperkit, lightning }
| Engine | Status | Use case |
|---|---|---|
WhisperKit (argmaxinc/argmax-oss-swift) |
shipped | Primary runtime engine for the app |
Lightning (lightning-whisper-mlx via subprocess) |
shipped, bench-only | Comparison baseline; not for app runtime |
| WhisperCpp | future | Non-MLX reference for cross-platform later |
MLXAudioEngine (mlx-audio-swift) |
future | Voxtral / Qwen3-ASR / Parakeet variants |
Weights live in ~/Library/Application Support/OpenQuack/WhisperKit/models/argmaxinc/whisperkit-coreml/openai_whisper-<variant>/, shared by the app, the CLI and the bench. Each variant is three .mlmodelc bundles, and a bundle’s payload is its weights/weight.bin — everything else in it is small metadata.
“Is this variant downloaded?” (WhisperKitEngine.hasModelWeights) must therefore test those three weight files, never the bundle directories: HubApi creates the directories and the small files the moment a transfer starts and moves the weight file in only on completion, so a directory test reports every torn download — a cancel, a quit, a dropped connection — as finished. Downstream that means the app skips its own visible download, WhisperKit’s init silently re-fetches gigabytes with no progress surface, and Settings offers the half-model for deletion.
bench/corpus/librispeech for the chosen default model.A model that fails any of these is not the default. BENCHMARKS.md is the source of truth.
BENCHMARKS.md carries the numbers.weights/weight.bin files are all present reads as downloaded; one missing any of them — including the torn case where every bundle directory and its small files exist — reads as not downloaded (unit tests: WhisperKitEngineCacheTests.testHasModelWeights_*).large-v3-turbo in argmaxinc/whisperkit-coreml — current config glob doesn’t match. Use WhisperKit.fetchAvailableModels() to enumerate.Sources/OpenQuackKit/Transcription/TranscriptionEngine.swiftSources/OpenQuackKit/Transcription/WhisperKitEngine.swiftSources/OpenQuackKit/Transcription/LightningEngine.swiftdocs/BENCHMARKS.md