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+).
58 lines
2.4 KiB
Swift
58 lines
2.4 KiB
Swift
// FlowSessionKeys.swift
|
|
// OSGKeyboard · Shared
|
|
//
|
|
// App Group keys for TypeWhisper-style Flow sessions between the
|
|
// keyboard extension and the host app (Session Owner).
|
|
|
|
import Foundation
|
|
|
|
public enum FlowSessionKeys {
|
|
public static let flowSessionActive = "flow.flowSessionActive"
|
|
public static let flowSessionExpires = "flow.flowSessionExpires"
|
|
public static let flowHeartbeat = "flow.flowHeartbeat"
|
|
public static let keyboardRecordingState = "flow.keyboardRecordingState"
|
|
public static let transcriptionLanguage = "flow.transcriptionLanguage"
|
|
public static let transcriptionResult = "flow.transcriptionResult"
|
|
/// Soft warning when polish failed but raw transcript was delivered.
|
|
public static let transcriptionPolishWarning = "flow.transcriptionPolishWarning"
|
|
public static let transcriptionError = "flow.transcriptionError"
|
|
public static let audioLevels = "flow.audioLevels"
|
|
|
|
/// Heartbeat older than this while the host is foreground → likely killed.
|
|
public static let heartbeatStaleInterval: TimeInterval = 3
|
|
|
|
/// Default Flow session length when started from the keyboard.
|
|
public static let defaultSessionDuration: TimeInterval = 480
|
|
|
|
/// Maximum duration for a single keyboard utterance (3 minutes).
|
|
public static let maxUtteranceDuration: TimeInterval = 180
|
|
|
|
/// Host polls for pipelined ASR drain after mic stop. Pipelining usually
|
|
/// finishes most chunks during recording; this is a soft deadline before
|
|
/// blocking on `asrTask.value` (which waits until the pipeline exits).
|
|
public static let localASRWaitTimeout: TimeInterval = 120
|
|
public static let localQwen3ASRWaitTimeout: TimeInterval = 180
|
|
public static let cloudASRWaitTimeout: TimeInterval = 120
|
|
|
|
/// Keyboard watchdog after the user stops recording (not utterance max length).
|
|
/// Must cover worst-case post-stop backlog: remaining MLX/SpeechAnalyzer chunks
|
|
/// plus cloud LLM polish (see `PolishingService.effectiveTimeout` cap).
|
|
public static func keyboardResultTimeout(
|
|
engineMode: String,
|
|
localASRBackend: LocalASRBackend
|
|
) -> TimeInterval {
|
|
if engineMode == "local" {
|
|
return localASRBackend == .qwen3ASR ? 240 : 180
|
|
}
|
|
return 240
|
|
}
|
|
|
|
public enum RecordingState: String, Sendable, Equatable {
|
|
case idle
|
|
case recording
|
|
case stopped
|
|
case processing
|
|
case aborted
|
|
}
|
|
}
|