// LocalASRCapabilities.swift // OSGKeyboard ยท Shared // // Declares vocabulary-bias capabilities for the current macOS Qwen3 MLX // runtime and Apple Speech fallback. Sherpa entries remain only to interpret // legacy backend identifiers and install state. import Foundation /// How a backend accepts vocabulary hints (honest matrix โ€” not every model /// supports hard hotwords). public enum LocalASRHotwordMode: String, Sendable, Codable, Equatable { case none case promptOnly case perRequest case recognizerScoped case cloudVocabulary } /// Cost of refreshing hotwords on a backend (e.g. Sherpa Qwen3 reloads recognizer). public enum LocalASRHotwordReloadCost: String, Sendable, Codable, Equatable { case none case recognizerReload case modelReload } public struct LocalASRCapabilities: Sendable, Equatable { public let hotwordMode: LocalASRHotwordMode public let maxHotwordCount: Int public let maxPromptCharacters: Int public let supportsStreaming: Bool public let hotwordReloadCost: LocalASRHotwordReloadCost public init( hotwordMode: LocalASRHotwordMode, maxHotwordCount: Int, maxPromptCharacters: Int, supportsStreaming: Bool, hotwordReloadCost: LocalASRHotwordReloadCost ) { self.hotwordMode = hotwordMode self.maxHotwordCount = maxHotwordCount self.maxPromptCharacters = maxPromptCharacters self.supportsStreaming = supportsStreaming self.hotwordReloadCost = hotwordReloadCost } /// Qwen3 MLX via mlx-audio-swift โ€” `context` soft prompt on streaming + batch. public static let qwen3MLX = LocalASRCapabilities( hotwordMode: .promptOnly, maxHotwordCount: 0, maxPromptCharacters: 800, supportsStreaming: true, hotwordReloadCost: .none ) /// Apple Speech on macOS โ€” no project-controlled hotword API today. public static let appleSpeech = LocalASRCapabilities( hotwordMode: .none, maxHotwordCount: 0, maxPromptCharacters: 0, supportsStreaming: false, hotwordReloadCost: .none ) /// Legacy Sherpa Qwen3 capability retained for persisted backend compatibility. public static let sherpaQwen3 = LocalASRCapabilities( hotwordMode: .recognizerScoped, maxHotwordCount: 100, maxPromptCharacters: 0, supportsStreaming: false, hotwordReloadCost: .recognizerReload ) /// Legacy Sherpa SenseVoice capability retained for persisted backend compatibility. public static let sherpaSenseVoice = LocalASRCapabilities( hotwordMode: .none, maxHotwordCount: 0, maxPromptCharacters: 0, supportsStreaming: false, hotwordReloadCost: .none ) /// Legacy Sherpa Paraformer capability retained for persisted backend compatibility. public static let sherpaParaformer = LocalASRCapabilities( hotwordMode: .none, maxHotwordCount: 0, maxPromptCharacters: 0, supportsStreaming: false, hotwordReloadCost: .none ) }