63 lines
2.1 KiB
Swift
63 lines
2.1 KiB
Swift
import Foundation
|
|
import Speech
|
|
|
|
@MainActor
|
|
enum SpeechEngine {
|
|
private static var warm: (any RecognitionSession)?
|
|
private static var warming: Task<Void, Never>?
|
|
private static var expiry: Task<Void, Never>?
|
|
private static var generation = UUID()
|
|
|
|
static var currentLocale: Locale { Locale(identifier: Prefs.shared.languageCode) }
|
|
|
|
static func warmUp() {
|
|
guard warming == nil, warm == nil else { return }
|
|
let token = generation
|
|
let locale = currentLocale
|
|
warming = Task {
|
|
let session = try? await make(locale: locale)
|
|
guard token == generation else { await session?.cancel(); return }
|
|
warming = nil
|
|
warm = session
|
|
expiry?.cancel()
|
|
expiry = Task {
|
|
try? await Task.sleep(for: .seconds(600))
|
|
guard !Task.isCancelled, token == generation else { return }
|
|
let old = warm
|
|
warm = nil
|
|
await old?.cancel()
|
|
}
|
|
}
|
|
}
|
|
|
|
static func acquire() async throws -> any RecognitionSession {
|
|
if let warming { await warming.value }
|
|
expiry?.cancel()
|
|
if let session = warm { warm = nil; return session }
|
|
return try await make(locale: currentLocale)
|
|
}
|
|
|
|
private static func make(locale: Locale) async throws -> any RecognitionSession {
|
|
if Prefs.shared.engineChoice == "legacy" { return try await LegacySession.make(locale: locale) }
|
|
do { return try await SpeechSession.make(locale: locale) }
|
|
catch {
|
|
guard Prefs.shared.engineChoice == "auto" else { throw error }
|
|
Log.error("primary analyzer unavailable; trying local dictation")
|
|
if let session = try? await SpeechSession.make(locale: locale, forceDictation: true) { return session }
|
|
return try await LegacySession.make(locale: locale)
|
|
}
|
|
}
|
|
|
|
static func replenish() { warmUp() }
|
|
|
|
static func resetWarm() {
|
|
generation = UUID()
|
|
warming?.cancel()
|
|
warming = nil
|
|
expiry?.cancel()
|
|
let old = warm
|
|
warm = nil
|
|
Task { await old?.cancel() }
|
|
}
|
|
}
|