【问题标题】:SpeechKit Function Result Called Multiple Times多次调用 SpeechKit 函数结果
【发布时间】:2020-06-08 08:51:23
【问题描述】:

我正在使用 SpeechKit 将语音到文本返回到列表中。例如制作杂货清单。但我不断得到多个值。我不知道有什么问题。我知道该函数只调用一次,但它返回多个值。下面是它的外观和代码的 gif。请给我一些指导。

func prepareAudioEngine() {
    let node = audioEngine.inputNode
    let recordingFormat = node.outputFormat(forBus: 0)
    node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, _) in
        self.request.append(buffer)
    }

    audioEngine.prepare()
    do {
        try audioEngine.start()
    } catch {
        return print(error)
    }

    guard let myRecogizer = speechRecognizer else { return }

    if !myRecogizer.isAvailable {
        return
    }

    recordandRecognizeSpeech()
}

func recordandRecognizeSpeech() {
    recognitionTask = speechRecognizer?.recognitionTask(with: request, resultHandler: { (result, error) in
        if let result = result {
            let stringArray = result.bestTranscription.formattedString
            let size = stringArray.reversed().firstIndex(of: " ") ?? stringArray.count
            let startWord = stringArray.index(stringArray.endIndex, offsetBy: -size)
            let last = stringArray[startWord...]
            self.detectedTextLabel.text = String(last).capitalized

        } else if let error = error {
            print("There was an error",error)
        }

        self.ingredients.append(Ingredient(name: self.detectedTextLabel.text ?? "Default", imageName: "????"))
        let indexPath = IndexPath(item: self.ingredients.count - 1, section: 0)
        self.tableView.insertRows(at: [indexPath], with: .automatic)
    })
}

【问题讨论】:

    标签: swift speech-recognition speech-to-text


    【解决方案1】:

    所以我认为这里发生的事情是,当request.shouldReportPartialResults = true 时,多个 SFSpeechRecognitionResult 在 SpeechRecognizer 解析它们时被返回。用以下代码替换您的 recognitionTask 代码:

            let df = DateFormatter()
            df.dateFormat = "y-MM-dd H:m:ss.SSSS"
            recognitionTask = speechRecognizer?.recognitionTask(with: request, resultHandler: { (result, error) in
                if let result = result {
                    let d = Date()
                    print(df.string(from: d)) // -> "2016-11-17 17:51:15.1720"
                    print("isFinal: \(result.isFinal)")
                    for (isegment, segment) in result.bestTranscription.segments.enumerated() {
                        print("\(isegment): \(segment.substring) (ts \(segment.timestamp), dur \(segment.duration), conf \(segment.confidence)")
                    }
    
                } else if let error = error {
                    print("There was an error",error)
                }
            })
    

    在我的 iPad 上测试时检查 Xcode 控制台输出...

    这是我在启动音频引擎时看到的,说“嘿,做”,短暂停顿(约 1 秒),然后说“你听到我说话”

    2020-06-07 17:31:14.0330
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:14.2190
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    1: do (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:14.2560
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:14.5600
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    1: do (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:14.6690
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    1: do (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:14.7930
    isFinal: false
    0: Hey (ts 0.55, dur -0.55, conf 0.745)
    1: do (ts 0.84, dur -0.84, conf 0.816)
    2020-06-07 17:31:15.6900
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    1: do (ts 0.0, dur 0.0, conf 0.0)
    2: you (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:15.8630
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    1: do (ts 0.0, dur 0.0, conf 0.0)
    2: you (ts 0.0, dur 0.0, conf 0.0)
    3: hear (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:16.1120
    isFinal: false
    0: Hey (ts 0.0, dur 0.0, conf 0.0)
    1: do (ts 0.0, dur 0.0, conf 0.0)
    2: you (ts 0.0, dur 0.0, conf 0.0)
    3: hear (ts 0.0, dur 0.0, conf 0.0)
    4: me (ts 0.0, dur 0.0, conf 0.0)
    2020-06-07 17:31:16.1950
    isFinal: false
    0: Hey (ts 0.55, dur -0.55, conf 0.93)
    1: do (ts 0.84, dur -0.84, conf 0.915)
    2: you (ts 1.92, dur -1.92, conf 0.927)
    3: hear (ts 2.2800000000000002, dur -2.2800000000000002, conf 0.932)
    4: me (ts 2.5100000000000002, dur -2.5100000000000002, conf 0.923)
    

    稍等片刻(~2 秒),然后停止 audioEngine:

    2020-06-07 17:31:18.4710
    isFinal: false
    0: Hey (ts 0.55, dur -0.55, conf 0.93)
    1: do (ts 0.84, dur -0.84, conf 0.915)
    2: you (ts 1.92, dur -1.92, conf 0.927)
    3: hear (ts 2.2800000000000002, dur -2.2800000000000002, conf 0.932)
    4: me (ts 2.5100000000000002, dur -2.5100000000000002, conf 0.923)
    2020-06-07 17:31:18.5200
    isFinal: true
    0: Hey (ts 0.55, dur 0.2899999999999999, conf 0.93)
    1: do (ts 0.84, dur 0.42000000000000004, conf 0.915)
    2: you (ts 1.92, dur 0.3600000000000003, conf 0.927)
    3: hear (ts 2.2800000000000002, dur 0.22999999999999998, conf 0.932)
    4: me (ts 2.5100000000000002, dur 0.3099999999999996, conf 0.923)
    

    注意几点:

    • SFTranscriptionSegments 上的时间戳为 0.0,而 result 仍处于“正在解析”(或正在发生的任何事情)
    • 当解析器似乎对时间戳感到满意时,时间戳都会变成合理的值。
    • 随着更多音频的输入,会添加额外的片段。这些时间戳最终会变得有效,并且我们会得到一个具有单调递增时间戳的令牌列表,正如您所期望的那样。从之前解析的音频片段报告的时间戳保持不变。
    • result 上的 isFinal 标志仅在 audioEngine 停止时为 True。

    不幸的是,我在 SFTranscriptionSegmentSFSpeechRecognitionResult 类中看不到任何其他标志,这些标志有助于区分“仍在解析”和“好的,我已经完成了”。

    推荐

    为了实时处理转录,我建议根据时间戳过滤结果。保留令牌和时间戳(或其他内容)的输出列表,并且仅在令牌以更大的时间戳到达时添加。

    我预计如果识别任务在整个音频片段结束时决定要从片段的早期更改单词,这可能会崩溃。然后,您会在该段的早期部分获得更改的令牌和时间戳。

    对于您的特定情况,如果音频中有一段时间的静默,则停止 audioEngine 并重新启动它可能会有所帮助。这将强制识别任务完成其对音频的解析并确保片段/时间戳/令牌不会更改。

    【讨论】:

    • 谢谢!让我试试看,我从来没想过要检查 Xcode 控制台输出。
    猜你喜欢
    • 1970-01-01
    • 2020-10-03
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    相关资源
    最近更新 更多