df1c5ff32c
Replace MLX GPU inference with CoreML bundles so transcription continues while the host app is backgrounded. Adds model download and warm-up, vendored Qwen3Speech, and updates onboarding, settings, and copy for the ~1.6 GB CoreML package (iOS 18+).
57 lines
2.1 KiB
Swift
57 lines
2.1 KiB
Swift
// LocalASRBackend.swift
|
|
// OSGKeyboard · Shared
|
|
//
|
|
// Identifies which on-device speech recognition engine to use when the
|
|
// user picks the "local" engine (no cloud LLM polish). The shared
|
|
// factory `ASRServiceFactory` dispatches on this enum; the settings UI
|
|
// renders it as a picker.
|
|
//
|
|
// Why an enum in `Shared` rather than living next to the concrete
|
|
// `ASRService` implementations: the value must be serialisable into
|
|
// the App Group store (so the keyboard extension can observe the
|
|
// selection), exposed via `ProviderConfig` (UI binding) and consumed
|
|
// by every layer that asks for an ASR backend.
|
|
|
|
import Foundation
|
|
|
|
public enum LocalASRBackend: String, CaseIterable, Identifiable, Sendable, Codable {
|
|
/// iOS 26 `SpeechAnalyzer` + `DictationTranscriber`. Always
|
|
/// on-device, no asset download, ships with iOS. Default for every
|
|
/// fresh install — anything else is opt-in.
|
|
case speechAnalyzer
|
|
|
|
/// Qwen3-ASR-0.6B via CoreML (Neural Engine + CPU). Stronger on Chinese
|
|
/// dialects and noisy audio than `SpeechAnalyzer`, works in Flow while
|
|
/// the host app is backgrounded, but requires a ~1.6 GB download on first
|
|
/// use and iOS 18+.
|
|
case qwen3ASR
|
|
|
|
public var id: String { rawValue }
|
|
|
|
/// Localisation key for the human label in the settings picker.
|
|
public var labelKey: String {
|
|
switch self {
|
|
case .speechAnalyzer: return "asr.backend.speechAnalyzer.label"
|
|
case .qwen3ASR: return "asr.backend.qwen3.label"
|
|
}
|
|
}
|
|
|
|
/// Localisation key for the one-line subtitle shown under the label.
|
|
public var blurbKey: String {
|
|
switch self {
|
|
case .speechAnalyzer: return "asr.backend.speechAnalyzer.blurb"
|
|
case .qwen3ASR: return "asr.backend.qwen3.blurb"
|
|
}
|
|
}
|
|
|
|
/// Whether this backend needs the user to download a model file
|
|
/// before it can run. Used to gate the "Downloading Qwen3-ASR" UI
|
|
/// in a follow-up; for now we just expose the flag.
|
|
public var requiresModelDownload: Bool {
|
|
switch self {
|
|
case .speechAnalyzer: return false
|
|
case .qwen3ASR: return true
|
|
}
|
|
}
|
|
}
|