feat: migrate on-device Qwen3 ASR to CoreML for background Flow dictation

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+).
This commit is contained in:
Rocky
2026-06-23 00:46:58 +08:00
parent 5e5122f172
commit df1c5ff32c
160 changed files with 22080 additions and 492 deletions
@@ -34,7 +34,7 @@ private final class FlowCaptureStreamRelay: @unchecked Sendable {
}
func yield(_ snapshot: AudioBufferSnapshot) {
lock.withLock { continuation?.yield(snapshot) }
_ = lock.withLock { continuation?.yield(snapshot) }
}
func finish() {
@@ -250,6 +250,22 @@ public final class FlowContinuousCapture {
)
}
/// Re-activate capture after returning from background without
/// reinstalling the tap (iOS may deactivate the audio session).
public func reassertIfRunning() {
guard isRunning else { return }
let session = AVAudioSession.sharedInstance()
try? session.setCategory(
.playAndRecord,
mode: .measurement,
options: [.defaultToSpeaker, .allowBluetoothHFP, .mixWithOthers]
)
try? session.setActive(true, options: .notifyOthersOnDeactivation)
if !audioEngine.isRunning {
try? audioEngine.start()
}
}
/// Begin forwarding downsampled buffers to ASR for one utterance.
public func beginUtterance() -> AsyncStream<AudioBufferSnapshot> {
let (stream, continuation) = AsyncStream<AudioBufferSnapshot>.makeStream()