SFSpeechRecognitionResult 在进行长时间中断时会丢弃之前的转录本

问题描述 投票:0回答:1

我遇到了此线程中描述的相同问题。自 iOS 18 起,当我使用

SFSpeechAudioBufferRecognitionRequest
时,返回 not final
SFSpeechRecognitionResult
当我在说话之间休息时间较长时,会丢弃之前识别的转录。

例如当我这样做时:

  • 说“你好”
  • 休息5秒
  • 说“你好吗”
  • 完成识别任务

部分结果首先返回“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示例,这似乎是正确的。那么,我做错了什么?

swift speech-to-text speech sfspeechrecognizer ios18
1个回答
0
投票

据我正确理解,这似乎是 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: " ")
}
© www.soinside.com 2019 - 2024. All rights reserved.