- PVSM.RU - https://www.pvsm.ru -
Очередная конференция — очередные новшества. Судя по настроениям нас ждет отмена клавиатур и устройств ввода. Apple в iOS 10 представила разработчикам возможность работать с речью. Мой коллега Геор Касапиди [1] уже описал возможности Siri в своей статье [2], а я расскажу о Speech.framework [3]. Рассмотренный в статье материал реализован в демо-приложении what_i_say. На момент написания статьи официальной документации нет, так что будем основываться на том, что рассказал Henry Mason [4].
Работа с речью полностью завязана на доступе к Интернету, и это неудивительно, так как используется тот же самый движок Siri. Разработчику даётся возможность либо распознавать живую речь, либо уже записанную в файл. Различие в объекте запроса:
SFSpeechURLRecognitionRequest
— используется для распознавания из файла;
SFSpeechAudioBufferRecognitionRequest
— используется для распознания диктовки.
Рассмотрим работу с real-time диктовкой.
Вся работа основывается на принципиальной схеме:
Но так как Speech.framework не содержит специального API для работы с микрофоном, разработчику потребуется задействовать AVAudioEngine [5].
Первым делом разработчику необходимо добавить два ключа в Info.plist
файл
NSMicrophoneUsageDescription
— для чего нужен доступ к микрофону
NSSpeechRecognitionUsageDescription
— для чего нужен доступ к распознанию речи
это важно, потому как без них будет неминуемый крэш.
Далее нам необходимо обработать статус авторизации:
- (void)handleAuthorizationStatus:(SFSpeechRecognizerAuthorizationStatus)s {
switch (s) {
case SFSpeechRecognizerAuthorizationStatusNotDetermined:
// система еще не запрашивала доступ у пользователя
[self requestAuthorization];
break;
case SFSpeechRecognizerAuthorizationStatusDenied:
// пользователь запретил доступ
[self informDelegateErrorType:(EVASpeechManagerErrorSpeechRecognitionDenied)];
break;
case SFSpeechRecognizerAuthorizationStatusRestricted:
// доступ ограничен
break;
case SFSpeechRecognizerAuthorizationStatusAuthorized: {
// можно работать
}
break;
}
}
На этапе знакомства с Speech.framework я так и не нашел use-case использования статуса SFSpeechRecognizerAuthorizationStatusRestricted
. Я предполагаю, что этот статус планировался под ограниченные права доступа, но пока для “Распознавание речи” нет дополнительных опций. Что ж, дождёмся официальной документации.
При первом запуске приложения после установки распознаватель вернёт статус SFSpeechRecognizerAuthorizationStatusNotDetermined
, поэтому необходимо запросить авторизацию у пользователя:
- (void)requestAuthorization {
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
[self handleAuthorizationStatus:status];
}];
}
В API нет ни методов, ни нотификаций для отслеживания изменения статуса. Система форсированно перезагрузит приложение, если пользователь изменит состояние авторизации.
Для успешной работы по распознаванию речи нам потребуется четыре объекта:
@property (nonatomic, strong) SFSpeechRecognizer *recognizer;
@property (nonatomic, strong) AVAudioEngine *audioEngine;
@property (nonatomic, strong) SFSpeechAudioBufferRecognitionRequest *request;
@property (nonatomic, strong) SFSpeechRecognitionTask *currentTask;
и реализовать протокол:
@interface EVASpeechManager () <SFSpeechRecognitionTaskDelegate>
recognizer
— объект, который будет обрабатывать запросы.
Из важного:
ro-RO en-IN he-IL tr-TR en-NZ sv-SE fr-BE it-CH de-CH pl-PL pt-PT uk-UA fi-FI vi-VN ar-SA zh-TW es-ES en-GB yue-CN th-TH en-ID ja-JP en-SA en-AE da-DK fr-FR sk-SK de-AT ms-MY hu-HU ca-ES ko-KR fr-CH nb-NO en-AU el-GR ru-RU zh-CN en-US en-IE nl-BE es-CO pt-BR es-US hr-HR fr-CA zh-HK es-MX id-ID it-IT nl-NL cs-CZ en-ZA es-CL en-PH en-CA en-SG de-DE.
распознаватель не переключает локаль автоматически. Он работает в рамках локали, определенной при инициализации. Т.е. если инициализация была локалью en-US
, а пользователь говорит на другом языке, то распознаватель отработает и вернёт пустой ответ;
queue
(по умолчанию mainQueue
), что даёт возможность обрабатывать callback’и асинхронно. Это позволит обработать достаточно большой текст без задержки.audioEngine
— объект, который будет связывать входной сигнал с микрофона (диктуемую речь) и выходной сигнал в буфер.
self.audioEngine = [[AVAudioEngine alloc] init];
AVAudioInputNode *node = self.audioEngine.inputNode;
AVAudioFormat *recordingFormat = [node outputFormatForBus:bus];
[node installTapOnBus:0
bufferSize:1024
format:recordingFormat
block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[self.request appendAudioPCMBuffer:buffer];
}];
request
— запрос на распознавание речи.
Из интересного:
по описанию можно предположить, что планируется разделить запросы еще и на типы, т. е. обычная диктовка, диктовка для поиска информации, диктовка для подтверждения чего-либо. Увы, сейчас они нигде не используются, разве что как маркеры. Предполагаю, будет развитие этого звена.
currentTask
— объект задачи на обработку одного запроса.
Из важного:
error
. Здесь можно получить ошибку, если задача была провалена;finishing
/cancelled
по которым можно определить была закончена задача или отменена. При отмене задачи система моментально отменяет дальнейшую обработку и распознавание, но разработчик в любом случае может получить ту часть распознанного, что уже обработана. При завершении задачи система вернёт полностью обработанный результат.После успешной настройки менеджера речи можно приступить к самой работе.
Необходимо создать запрос:
self.request = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
и передать его в распознаватель:
Важно! перед тем, как запрос передать в распознаватель, необходимо активировать
audioEngine
для получения аудиопотока с микрофона.
- (void)performRecognize {
[self.audioEngine prepare];
NSError *error = nil;
if ([self.audioEngine startAndReturnError:&error]) {
self.currentTask = [self.recognizer recognitionTaskWithRequest:self.request
delegate:self];
} else {
[self informDelegateError:error];
}
}
Приняв запрос, система вернёт нам объект задачи. Он потребуется позже для остановки процесса.
Объект запроса нельзя переиспользовать пока он активен, иначе будет крэш “reason: 'SFSpeechAudioBufferRecognitionRequest cannot be re-used’”
. Поэтому важно по завершении процесса остановить задачу и audioEngine:
- (void)stopRecognize {
if ([self isTaskInProgress]) {
[self.currentTask finish];
[self.audioEngine stop];
}
}
По окончании задачи результат будет доставлен в методы делегата SFSpeechRecognitionTaskDelegate
:
обработать распознанный текст можно в методе:
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult {
self.buffer = recognitionResult.bestTranscription.formattedString;
}
а ошибки в методе:
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishSuccessfully:(BOOL)successfully {
if (!successfully) {
[self informDelegateError:task.error];
} else {
[self.delegate manager:self didRecognizeText:[self.buffer copy]];
}
}
За время работы с приложением я столкнулся с ошибками:
Error: SessionId=com.siri.cortex.ace.speech.session.event.SpeechSessionId@439e90ed, Message=Timeout waiting for command after 30000 ms
Error: SessionId=com.siri.cortex.ace.speech.session.event.SpeechSessionId@714a717a, Message=Empty recognition
первая ошибка прилетела, когда после небольшой диктовки речь была закончена (пользователь перестал говорить), а распознаватель продолжал работу;
вторая ошибка была, когда распознаватель не получил никакого аудиопотока и процесс был отменен пользователем.
Обе ошибки были пойманы в методе делегата:
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishSuccessfully:(BOOL)successfully {
if (!successfully) {
// здесь требуется обработка ошибок task.error
}
}
После первого знакомства с Speech.framework стало понятно, что он ещё “сырой”. Многое необходимо доработать и протестировать. Начало неплохое, есть стремление в сторону искусственного интеллекта и работы без средств ввода информации. В комбинации с IoT, открываются большие возможности по управлению гаджетами, домом, автомобилем. А пока ждём, тренируемся и исследуем дальше.
Автор: e-Legion Ltd.
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios-development/151521
Ссылки в тексте:
[1] Геор Касапиди: https://habrahabr.ru/users/devnseven/
[2] в своей статье: https://habrahabr.ru/company/e-Legion/blog/303886/
[3] Speech.framework: https://developer.apple.com/reference/speech
[4] что рассказал Henry Mason: https://developer.apple.com/videos/play/wwdc2016/509/
[5] AVAudioEngine: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAudioEngine_Class/
[6] демо приложение what_i_say: https://github.com/podaenur/what_i_say
[7] Apple WWDC 2016: https://developer.apple.com/videos/wwdc2016/
[8] Источник: https://habrahabr.ru/post/304714/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.