|
|
|
@ -5,7 +5,9 @@ public final class SonioxLiveSession { |
|
|
|
public static let primaryWsBase = "wss://translate.compare.soniox.com/compare/api/compare-websocket" |
|
|
|
public static let fallbackWsBase = "wss://stt.compare.soniox.com/compare/api/compare-websocket" |
|
|
|
private static let userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" |
|
|
|
private static let origin = "https://translate.compare.soniox.com" |
|
|
|
public static func origin(for endpoint: String) -> String { |
|
|
|
return endpoint.contains("translate") ? "https://translate.compare.soniox.com" : "https://stt.compare.soniox.com" |
|
|
|
} |
|
|
|
|
|
|
|
// Pre-compiled static regexes for zero-allocation hot path |
|
|
|
private static let faRegex: NSRegularExpression = { |
|
|
|
@ -142,7 +144,7 @@ public final class SonioxLiveSession { |
|
|
|
|
|
|
|
var request = URLRequest(url: url) |
|
|
|
request.setValue(SonioxLiveSession.userAgent, forHTTPHeaderField: "User-Agent") |
|
|
|
request.setValue(SonioxLiveSession.origin, forHTTPHeaderField: "Origin") |
|
|
|
request.setValue(SonioxLiveSession.origin(for: endpoint), forHTTPHeaderField: "Origin") |
|
|
|
request.timeoutInterval = 12.0 |
|
|
|
|
|
|
|
let config = URLSessionConfiguration.default |
|
|
|
@ -255,6 +257,10 @@ public final class SonioxLiveSession { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 3. Send official "END" token for complete Soniox termination |
|
|
|
let endMsg = URLSessionWebSocketTask.Message.string("END") |
|
|
|
task.send(endMsg) { _ in } |
|
|
|
|
|
|
|
// Safety timeout fallback: allow up to 4.0s for STT inference & network transit |
|
|
|
DispatchQueue.global().asyncAfter(deadline: .now() + 4.0) { [weak self] in |
|
|
|
guard let self = self else { return } |
|
|
|
@ -425,8 +431,13 @@ public final class SonioxLiveSession { |
|
|
|
|
|
|
|
let sessionEnded = json["session_ended"] as? Bool ?? false |
|
|
|
let sessionDone = (json["type"] as? String) == "session_done" |
|
|
|
let isFinished = json["finished"] as? Bool ?? false |
|
|
|
let hasRawFinished: Bool = { |
|
|
|
guard let raw = json["raw"] as? String else { return false } |
|
|
|
return raw.contains("\"finished\":true") || raw.contains("\"finished\": true") |
|
|
|
}() |
|
|
|
|
|
|
|
if gotFin || sessionEnded || sessionDone { |
|
|
|
if gotFin || sessionEnded || sessionDone || isFinished || hasRawFinished { |
|
|
|
completeWithCurrentText() |
|
|
|
} |
|
|
|
} |
|
|
|
@ -623,7 +634,7 @@ public final class SonioxLiveSession { |
|
|
|
|
|
|
|
var request = URLRequest(url: url) |
|
|
|
request.setValue(userAgent, forHTTPHeaderField: "User-Agent") |
|
|
|
request.setValue(origin, forHTTPHeaderField: "Origin") |
|
|
|
request.setValue(origin(for: endpoint), forHTTPHeaderField: "Origin") |
|
|
|
|
|
|
|
let durationSec = Double(pcmData.count) / 32000.0 |
|
|
|
let watchdogTimeout = max(6.5, min(25.0, durationSec * 0.60 + 5.0)) |
|
|
|
@ -721,7 +732,14 @@ public final class SonioxLiveSession { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
let ended = (json["session_ended"] as? Bool ?? false) || ((json["type"] as? String) == "session_done") |
|
|
|
let sessionEnded = json["session_ended"] as? Bool ?? false |
|
|
|
let sessionDone = (json["type"] as? String) == "session_done" |
|
|
|
let isFinished = json["finished"] as? Bool ?? false |
|
|
|
let hasRawFinished: Bool = { |
|
|
|
guard let raw = json["raw"] as? String else { return false } |
|
|
|
return raw.contains("\"finished\":true") || raw.contains("\"finished\": true") |
|
|
|
}() |
|
|
|
let ended = sessionEnded || sessionDone || isFinished || hasRawFinished |
|
|
|
if gotFin || ended { |
|
|
|
lock.lock() |
|
|
|
let textToReturn = fullCommitted.joined() + (gotFin ? "" : latestNonFinal.joined()) |
|
|
|
@ -780,7 +798,9 @@ public final class SonioxLiveSession { |
|
|
|
if offset >= pcmData.count { |
|
|
|
let silence = Data(count: 6400) |
|
|
|
task.send(.data(silence)) { _ in |
|
|
|
task.send(.string("{\"type\": \"finalize\"}")) { _ in } |
|
|
|
task.send(.string("{\"type\": \"finalize\"}")) { _ in |
|
|
|
task.send(.string("END")) { _ in } |
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
} |
|
|
|
|