我遇到了此线程中描述的相同问题。自 iOS 18 起,当我使用
SFSpeechAudioBufferRecognitionRequest
时,返回 not final SFSpeechRecognitionResult
当我在讲话之间进行较长的停顿时,会丢弃之前识别的转录。
例如当我这样做时:
部分结果首先返回“Hello”,然后返回“how are you”,最终结果仅返回“how are you”。这是一个问题,因为预期的行为(在 iOS 17 上有效)是它返回整个转录“Hello how are you”。
我像这样创建
SFSpeechRecognitionRequest
:
let request = SFSpeechAudioBufferRecognitionRequest()
let audioEngine = AVAudioEngine()
let inputNode = audioEngine.inputNode
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, when in
request.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
我像这样创建
SFSpeechRecognitionTask
:
recognizer.recognitionTask(
with: request,
resultHandler: { [weak self] result, error in
self?.recognitionHandler(result: result, error: error)
}
)
最后我的识别处理程序如下所示:
func recognitionHandler(result: SFSpeechRecognitionResult?, error: Error?) {
if let result {
let recognizedText = result.bestTranscription.formattedString
print(recognizedText)
} else if let error {
...
} else {
...
}
}
根据提供的Apple示例,这似乎是正确的。那么,我做错了什么?
据我正确理解,这似乎是 iOS 18 上的一个错误。作为解决方法,您可以加入最终部分结果。您可以通过检查分段的置信度来确定它是最终的部分结果。当您确定它是最终部分结果时,可以将其附加到累加器数组中。然后,当您想要获得识别的文本时,您需要将所有按
speechStartTimestamp
排序的最终部分结果与非最终部分结果连接起来。
因此,在类/结构/参与者范围内,像这样定义数组(当您进行新识别时不要忘记清除它):
private var finalPartialRecognizedResults = [SFSpeechRecognitionResult]()
然后改变你的
recognitionHandler
:
func recognitionHandler(result: SFSpeechRecognitionResult?, error: Error?) {
if let result {
let isFinalPartialRecognizedResult = (result.bestTranscription.segments.first?.confidence ?? 0) > .zero
if isFinalPartialRecognizedResult {
finalPartialRecognizedResults.append(result)
}
let recognizedText = getCurrentlyRecognizedText(
notFinalPartialRecognizedResult: !isFinalPartialRecognizedResult ? result : nil
)
print(recognizedText)
} else if let error {
...
} else {
...
}
}
func getCurrentlyRecognizedText(notFinalPartialRecognizedResult: SFSpeechRecognitionResult?) -> String {
let finalResults = finalPartialRecognizedResults.sorted(
by: {
($0.speechRecognitionMetadata?.speechStartTimestamp ?? 0)
< ($1.speechRecognitionMetadata?.speechStartTimestamp ?? 0)
}
)
let results = finalResults + [notFinalPartialRecognizedResult].compactMap { $0 }
return results
.map(\.bestTranscription.formattedString)
.joined(separator: " ")
}