iOS: update onboarding and gateway UI

This commit is contained in:
Mariano Belinky
2026-02-02 12:58:09 +00:00
parent 532b9653be
commit ff6114599e
9 changed files with 725 additions and 58 deletions

View File

@@ -451,7 +451,8 @@ final class TalkModeManager: NSObject {
private func handleTranscript(transcript: String, isFinal: Bool) async {
let trimmed = transcript.trimmingCharacters(in: .whitespacesAndNewlines)
if self.isSpeaking, self.interruptOnSpeech {
let ttsActive = self.isSpeechOutputActive
if ttsActive, self.interruptOnSpeech {
if self.shouldInterrupt(with: trimmed) {
self.stopSpeaking()
}
@@ -470,7 +471,7 @@ final class TalkModeManager: NSObject {
_ = await self.endPushToTalk()
return
}
if self.captureMode == .continuous, !self.isSpeaking {
if self.captureMode == .continuous, !self.isSpeechOutputActive {
await self.processTranscript(trimmed, restartAfter: true)
}
}
@@ -489,7 +490,7 @@ final class TalkModeManager: NSObject {
private func checkSilence() async {
if self.captureMode == .continuous {
guard self.isListening, !self.isSpeaking else { return }
guard self.isListening, !self.isSpeechOutputActive else { return }
let transcript = self.lastTranscript.trimmingCharacters(in: .whitespacesAndNewlines)
guard !transcript.isEmpty else { return }
guard let lastHeard else { return }
@@ -895,16 +896,22 @@ final class TalkModeManager: NSObject {
}
private func stopSpeaking(storeInterruption: Bool = true) {
guard self.isSpeaking else { return }
let interruptedAt = self.lastPlaybackWasPCM
? self.pcmPlayer.stop()
: self.mp3Player.stop()
if storeInterruption {
self.lastInterruptedAtSeconds = interruptedAt
let hasIncremental = self.incrementalSpeechActive ||
self.incrementalSpeechTask != nil ||
!self.incrementalSpeechQueue.isEmpty
if self.isSpeaking {
let interruptedAt = self.lastPlaybackWasPCM
? self.pcmPlayer.stop()
: self.mp3Player.stop()
if storeInterruption {
self.lastInterruptedAtSeconds = interruptedAt
}
_ = self.lastPlaybackWasPCM
? self.mp3Player.stop()
: self.pcmPlayer.stop()
} else if !hasIncremental {
return
}
_ = self.lastPlaybackWasPCM
? self.mp3Player.stop()
: self.pcmPlayer.stop()
TalkSystemSpeechSynthesizer.shared.stop()
self.cancelIncrementalSpeech()
self.isSpeaking = false
@@ -923,6 +930,13 @@ final class TalkModeManager: NSObject {
true
}
private var isSpeechOutputActive: Bool {
self.isSpeaking ||
self.incrementalSpeechActive ||
self.incrementalSpeechTask != nil ||
!self.incrementalSpeechQueue.isEmpty
}
private func applyDirective(_ directive: TalkDirective?) {
let requestedVoice = directive?.voiceId?.trimmingCharacters(in: .whitespacesAndNewlines)
let resolvedVoice = self.resolveVoiceAlias(requestedVoice)
@@ -1348,15 +1362,33 @@ private struct IncrementalSpeechBuffer {
if newText.hasPrefix(self.latestText) {
self.latestText = newText
} else if self.latestText.hasPrefix(newText) {
// Keep the longer cached text.
// Stream reset or correction; prefer the newer prefix.
self.latestText = newText
self.spokenOffset = min(self.spokenOffset, newText.count)
} else {
self.latestText += newText
// Diverged text means chunks arrived out of order or stream restarted.
let commonPrefix = Self.commonPrefixCount(self.latestText, newText)
self.latestText = newText
if self.spokenOffset > commonPrefix {
self.spokenOffset = commonPrefix
}
}
if self.spokenOffset > self.latestText.count {
self.spokenOffset = self.latestText.count
}
}
private static func commonPrefixCount(_ lhs: String, _ rhs: String) -> Int {
let left = Array(lhs)
let right = Array(rhs)
let limit = min(left.count, right.count)
var idx = 0
while idx < limit, left[idx] == right[idx] {
idx += 1
}
return idx
}
private mutating func extractSegments(isFinal: Bool) -> [String] {
let chars = Array(self.latestText)
guard self.spokenOffset < chars.count else { return [] }