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
это время, по истечении которого вы хотите остановиться после завершения произнесения.