SFSpeechRecognizer - обнаружить конец высказывания

Я взламываю небольшой проект, использующий встроенную в iOS 10 функцию распознавания речи. У меня есть результаты работы с помощью микрофона устройства, моя речь распознается очень точно.

Моя проблема в том, что обратный вызов задачи распознавания вызывается для каждой доступной частичной транскрипции, и я хочу, чтобы он обнаружил, что человек перестал говорить, и вызывает обратный вызов с isFinal свойство установлено в true. Этого не происходит - приложение слушает бесконечно.

Является SFSpeechRecognizer когда-либо способен определить конец предложения?

Вот мой код - он основан на примере, найденном в Интернете, в основном это шаблон, необходимый для распознавания из источника микрофона. Я изменил его, добавив признание taskHint, Я тоже поставил shouldReportPartialResults ложно, но, кажется, это было проигнорировано.

    func startRecording() {

    if recognitionTask != nil {
        recognitionTask?.cancel()
        recognitionTask = nil
    }

    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(AVAudioSessionCategoryRecord)
        try audioSession.setMode(AVAudioSessionModeMeasurement)
        try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
    } catch {
        print("audioSession properties weren't set because of an error.")
    }

    recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
    recognitionRequest?.shouldReportPartialResults = false
    recognitionRequest?.taskHint = .search

    guard let inputNode = audioEngine.inputNode else {
        fatalError("Audio engine has no input node")
    }

    guard let recognitionRequest = recognitionRequest else {
        fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
    }

    recognitionRequest.shouldReportPartialResults = true

    recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in

        var isFinal = false

        if result != nil {
            print("RECOGNIZED \(result?.bestTranscription.formattedString)")
            self.transcriptLabel.text = result?.bestTranscription.formattedString
            isFinal = (result?.isFinal)!
        }

        if error != nil || isFinal {
            self.state = .Idle

            self.audioEngine.stop()
            inputNode.removeTap(onBus: 0)

            self.recognitionRequest = nil
            self.recognitionTask = nil

            self.micButton.isEnabled = true

            self.say(text: "OK. Let me see.")
        }
    })

    let recordingFormat = inputNode.outputFormat(forBus: 0)
    inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
        self.recognitionRequest?.append(buffer)
    }

    audioEngine.prepare()

    do {
        try audioEngine.start()
    } catch {
        print("audioEngine couldn't start because of an error.")
    }

    transcriptLabel.text = "Say something, I'm listening!"

    state = .Listening
}

5 ответов

Кажется, что флаг isFinal не становится истинным, когда пользователь перестает говорить, как ожидалось. Я предполагаю, что это желаемое поведение Apple, потому что событие "Пользователь перестает говорить" является неопределенным событием.

Я считаю, что самый простой способ достичь вашей цели - это сделать следующее:

  • Вы должны установить "интервал молчания". Это означает, что если пользователь не говорит в течение времени, превышающего ваш интервал, он прекращает говорить (т.е. 2 секунды).

  • Создайте таймер в начале audio session:

var timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "didFinishTalk", userInfo: nil, repeats: false)

  • когда вы получаете новые транскрипции в recognitionTaskсделать недействительным и перезапустить ваш таймер

    timer.invalidate() timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "didFinishTalk", userInfo: nil, repeats: false)

  • если таймер истекает, это означает, что пользователь не разговаривает в течение 2 секунд. Вы можете безопасно остановить Audio Session и выйти

Основываясь на моем тесте на iOS10, когда shouldReportPartialResults имеет значение false, вам нужно подождать 60 секунд, чтобы получить результат.

У меня есть другой подход, который я считаю гораздо более надежным в определении того, когда задача распознавания завершает угадывание: confidenceсчет.

Когда shouldReportPartialResultsустановлено значение true, частичные результаты будут иметь показатель достоверности 0.0. Только окончательное предположение вернется со счетом больше 0.

      recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { result, error in

    if let result = result {
        let confidence = result.bestTranscription.segments[0].confidence
        print(confidence)
        self.transcript = result.bestTranscription.formattedString
    }

}

В segmentsмассив выше содержит каждое слово в транскрипции. 0— самый безопасный индекс для изучения, поэтому я предпочитаю использовать его.

Как вы его используете, зависит от вас, но если все, что вы хотите сделать, это узнать, когда угадывающий закончит угадывать, вы можете просто вызвать:

let myIsFinal = confidence > 0.0 ? true : false

Вы также можете посмотреть на оценку (100,0 — это полная уверенность) и сгруппировать ответы в группы предположений с низкой -> высокой достоверностью, если это поможет вашему приложению.

В настоящее время я использую текст в приложении для работы с речью, и он работает нормально для меня. Мой блок распознавания задач выглядит следующим образом:

recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
        var isFinal = false

        if let result = result, result.isFinal {
            print("Result: \(result.bestTranscription.formattedString)")
            isFinal = result.isFinal
            completion(result.bestTranscription.formattedString, nil)
        }

        if error != nil || isFinal {
            self.audioEngine.stop()
            inputNode.removeTap(onBus: 0)

            self.recognitionRequest = nil
            self.recognitionTask = nil
            completion(nil, error)
        }
    })
if result != nil {
    self.timerDidFinishTalk.invalidate()
    self.timerDidFinishTalk = Timer.scheduledTimer(timeInterval: TimeInterval(self.listeningTime), target: self, selector:#selector(self.didFinishTalk), userInfo: nil, repeats: false)

    let bestString = result?.bestTranscription.formattedString

    self.fullsTring =  bestString!.trimmingCharacters(in: .whitespaces)
    self.st = self.fullsTring
  }

Вот self.listeningTime это время, по истечении которого вы хотите остановиться после завершения произнесения.

Другие вопросы по тегам