Files
OSGKeyboard/OSGKeyboardShared/DesignSystem/WaveformView.swift
Rocky 537a68552a perf(asr): speed up local Flow dictation and land CLM/keyboard refactor
Reduce perceived latency from key release to final text:
- Adaptive chunking: 2.5s first chunk + 5s follow-ups so short
  utterances start on-device recognition while still recording.
- Session-level ASR warmup and audio-format cache reuse to remove
  per-utterance cold-start of SpeechAnalyzer.
- Mirror live pipelined partials to the keyboard transcript line via
  a new flow.transcriptionPartial App Group key + Darwin ping.

Also commits the accumulated custom language model, Flow session,
keyboard extension restructure, and Xiaomi MiMo provider work in
progress on this branch.
2026-07-06 00:00:19 +08:00

60 lines
1.8 KiB
Swift

// WaveformView.swift
// OSGKeyboard · Shared
//
// Symmetric, real-time driven waveform. Shared between the keyboard
// extension and any host-app preview that mirrors the mic UI.
import SwiftUI
public struct WaveformView: View {
@Environment(\.themePalette) private var palette: ThemePalette
public let level: Double
public let barCount: Int
public let color: Color?
public let active: Bool
public init(
level: Double,
barCount: Int = 18,
color: Color? = nil,
active: Bool = true
) {
self.level = max(0, min(1, level))
self.barCount = barCount
self.color = color
self.active = active
}
private var resolvedColor: Color {
color ?? palette.recordRed
}
public var body: some View {
TimelineView(.animation(minimumInterval: 1.0 / 30.0)) { context in
HStack(alignment: .center, spacing: 3) {
ForEach(0..<barCount, id: \.self) { index in
Capsule()
.fill(resolvedColor)
.frame(
width: 2.4,
height: height(for: index, time: context.date.timeIntervalSinceReferenceDate)
)
.opacity(active ? 1.0 : 0.45)
}
}
}
}
private func height(for index: Int, time: TimeInterval) -> CGFloat {
guard active else { return 4 }
let centre = Double(barCount - 1) / 2.0
let distance = abs(Double(index) - centre) / max(centre, 1)
let phase = sin(time * 4.0 + Double(index) * 0.45)
let wobble = 0.18 * phase
let magnitude = max(0, min(1, Double(level) + wobble))
let profile = 1.0 - pow(distance, 1.4) * 0.85
return CGFloat(max(6, 32 * magnitude * profile))
}
}