SOURCE RECORD · S04
S04 · 制作视频 / Vidma
Apple speech request and local-only versus automatic attempts
保留原行号。个人/账户信息如有删除,已用 REDACTED 标识。原文件 SHA-256 只用于识别截取时的本机原文件;不能证明编写或提交时间,也不等于脱敏下载文件的哈希。
Original line numbers are retained. Redactions are explicitly marked. The original full-file hash identifies a captured local file, not its creation/submission time or the redacted download. Public-file hashes are listed separately. This is selected source, not a whole-repository or binary absence finding.
Project key: vidma
Original relative path: Vidma/Services/SpeechSubtitleService.swift
Captured: 2026-09-12T18:57:15+08:00
Original full-file SHA256: 1f55567b14fb54e0699df7709137a264da703dd162d7a5b550e944670f628220
Evidence level: local source excerpt
Build correspondence: not yet established with an Apple-received binary.
Line numbers refer to the captured original file. Gaps are explicitly marked. No source code was changed.
Original lines 46 to 63
0046 init(recognizer: SFSpeechRecognizer) {
0047 self.recognizer = recognizer
0048 }
0049
0050 func recognize(
0051 url: URL,
0052 requiresOnDeviceRecognition: Bool,
0053 audioDuration: Double,
0054 progress: @escaping @Sendable (Double) async -> Void
0055 ) async throws -> [RecognizedSpeechSegment] {
0056 try Task.checkCancellation()
0057 let request = SFSpeechURLRecognitionRequest(url: url)
0058 request.shouldReportPartialResults = true
0059 request.requiresOnDeviceRecognition = requiresOnDeviceRecognition
0060 request.taskHint = .dictation
0061 request.addsPunctuation = true
0062
0063 return try await withCheckedThrowingContinuation { continuation inOriginal lines 259 to 286
0259 guard let recognizerBox = await LegacySpeechRecognizerBox(localeIdentifier: localeIdentifier), recognizerBox.recognizer.isAvailable else {
0260 throw AppError.speechRecognitionFailure(context: "speech recognizer unavailable for \(localeIdentifier)")
0261 }
0262 let recognizer = recognizerBox.recognizer
0263 if mode == .onDeviceOnly, !recognizer.supportsOnDeviceRecognition {
0264 throw AppError.speechRecognitionFailure(messageKey: "error.speech.onDevice.message", context: "on-device recognition unavailable for \(localeIdentifier)")
0265 }
0266
0267 let attempts = Self.recognitionAttempts(mode: mode, supportsOnDeviceRecognition: recognizer.supportsOnDeviceRecognition)
0268 let chunks = try await AudioPreprocessingService.shared.legacyChunks(from: prepared, outputDirectory: outputDirectory)
0269 await SubtitleDiagnosticsStore.shared.recordChunks(chunks)
0270 var recognized: [RecognizedSpeechSegment] = []
0271 var lastFailure: Error?
0272 var completedRequest = false
0273
0274 for (chunkIndex, chunk) in chunks.enumerated() {
0275 var chunkCompleted = false
0276 for (attemptIndex, requiresOnDeviceRecognition) in attempts.enumerated() {
0277 try Task.checkCancellation()
0278 let session = SpeechRecognitionSession(recognizer: recognizer)
0279 do {
0280 let segments = try await withTaskCancellationHandler {
0281 try await session.recognize(
0282 url: chunk.url,
0283 requiresOnDeviceRecognition: requiresOnDeviceRecognition,
0284 audioDuration: chunk.duration
0285 ) { fraction in
0286 let attemptFraction = (Double(attemptIndex) + min(1, max(0, fraction))) / Double(attempts.count)Original lines 434 to 445
0434 nonisolated static func recognitionAttempts(
0435 mode: SpeechRecognitionMode,
0436 supportsOnDeviceRecognition: Bool
0437 ) -> [Bool] {
0438 switch mode {
0439 case .automatic:
0440 supportsOnDeviceRecognition ? [true, false] : [false]
0441 case .onDeviceOnly:
0442 [true]
0443 }
0444 }
0445