Yandex слышит тебя, dude

imageНеожиданно пришел приказ — написать приложение под iOS, использующее Yandex Speechkit для распознавания русской речи. Точнее, для распознавания коротких фраз на произвольную тему. Цель задания — сравнить успехи яндекс-двигателя с нашим, саровским движком.Приказали — сделал следующие шаги.

Зашел на yandex.ru в раздел распознавание речи Зарегистрировался и получил ключ, он же API_KEY Отправил письмо в yandex с просьбой активировать ключ На вопрос, как будет использоваться ключ, я ответил, что выпускаю карточную игру Diablo 3–13, управляемую голосом.

Через два дня ключ активировали. Я поначалу нетерпеливо бил копытом, затем понял, что в yandex работают вдумчивые, синхронные сотрудники.В своем приложении в дальнейшем я также отказался от асинхронных запросов к yandex.api.

Получив в свое распоряжение волшебный ключ, он же API_KEY, я скачал по указанной ссылке архив

YandexSpeechKit-2.1-ios.zip

В архиве содержится два проекта, демонстрирующих работу библиотеки.Собрав оба примера, я заменил в тексте SAMPLE_API_KEY на свой и запустил приложения.Оба не работают под Xcode 5.1.1, вылетают по какой-то внутренней ошибке, спрятанной глубоко в недрах библиотеки.

Пришлось загрузить актуальную SDK c github.

Cкачал по указанной выше ссылке архив

yandex-speechkit-ios-master.zip

собрал примеры, но ошибка не исчезла.Я немедленно отправил письмо-диагностику в службу поддержки и, в ожидании ответа, написал очередную игрушку.Прошло пару дней, ответа от службы не было.

Выложив игрушку в маркет, я решил написать собственное iOS-приложение, используя url-запросы к яндекс-сервису распознавания речи.

Ключ можно использовать тот же.

Шаг первый — проверка командной строкой В командной строке надо подавать wav файлы с заранее записанными фразами.Запрос выглядит просто, как бамбук

curl -v -4 «asr.yandex.net/asr_xml? key=e547b4f5-хрен-вам-ключ-97130fdbcd74&uuid=01ae13cb744628b58fb536d496daa177&topic=notes&lang=ru-RU» -H «Content-Type: audio/x-wav» --data-binary »@recordedFile.wav» В комментарии запрос не нуждается, все сделано в точности с великолепной документацией на сайте yandex.С первого раза запрос не прошел, поскольку вместо 32-цифрового uuid я подсунул udid своего iPhone. А в нем не только HEX.

Фразы типа

тридцать восемь попугаевпойдем-ка покурим-каВладимир Сысоевчо смотришь дубина давай помогайкто не пашет тот сачокАнтон СубботинХабрахаб — полный улет

распознались великолепно, в исполнении разных дикторов.

imageК моему удовольствию, срамные слова яндекс беспощадно вырезает.

Шаг второй — собираем iOS-приложение, где записывается речь Есть стандартный проект на сайте apple, в которм демонстрируется запись/проигрывание звука.Скачиваем проект SpeakHere, запускаем — все работает. Уважаю я этих ребят из Купертино, пусть индусы. Код, конечно у них, хмм, но все работает.

Модифицируем файл SpeakHereController.mm

Заходим в функцию — (void)stopRecord и дописываем одну строчку

 — (void)stopRecord { // здесь ничего не трогаем … // btn_play.enabled = YES; // эту строчку добавляем [self yandexTool]; } Понятно, что мы добавили вызов функции, обрабатывающей сформированный во время звукозаписи аудиофайл.Изначально в проекте звук записывается в файл recordedFile.caff recordFilePath = (CFStringRef)[NSTemporaryDirectory () stringByAppendingPathComponent: @«recordedFile.caff»]; Яндекс не умеет работать с файлами такого типа, поэтому по всему файлу SpeakHereController.mm расширитель имени надо заменить на recordFilePath = (CFStringRef)[NSTemporaryDirectory () stringByAppendingPathComponent: @«recordedFile.wav»]; Кроме того в файле проекта AQRecorder.mm в теле функции void AQRecorder: StartRecord (CFStringRef inRecordFile) надо поменять параметр в строке OSStatus status = AudioFileCreateWithURL (url, kAudioFileCAFType, &mRecordFormat, kAudioFileFlags_EraseFile, &mRecordFile); на OSStatus status = AudioFileCreateWithURL (url, kAudioFileWAVEType, &mRecordFormat, kAudioFileFlags_EraseFile, &mRecordFile); И последнее — яндекс понимает звуковые файлы, записанные на частоте 16000.В файле проекта AQRecorder.mm в теле функции void AQRecorder: SetupAudioFormat (UInt32 inFormatID) добавляем строчку

Float64 newRate = 16000; XThrowIfError (AudioSessionSetProperty (kAudioSessionProperty_PreferredHardwareSampleRate, sizeof (newRate), &newRate), «couldn’t set hardware sample rate»); Все, осталось вставить функцию запроса к серверу яндекс. В запросе будем аналогично командному запросу подавать файл recordedFile.wavПривожу ниже текст функции yandexTool, простой как колея от трактора Беларусь. -(void) yandexTool { NSString *urltext_temp = [NSString stringWithFormat:@«https://asr.yandex.net/asr_xml? key=%@&uuid=%@&topic=queries&lang=ru-RU», API_KEY, API_UUID]; NSString* urltext = [urltext_temp stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; NSLog (@«url=%@», urltext); NSURL *url = [NSURL URLWithString: urltext]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url]; [request setURL: url]; [request setHTTPMethod:@«PUT»]; [request setValue:@«audio/x-wav» forHTTPHeaderField:@«Content-Type»]; NSString *filePath=[NSTemporaryDirectory () stringByAppendingPathComponent: @«recordedFile.wav»]; NSData *myData = [NSData dataWithContentsOfFile: filePath]; request.HTTPBody = myData; NSError *error; NSURLResponse *response; NSData *data2 = [NSURLConnection sendSynchronousRequest: request returningResponse:&response error:&error]; NSString *responseString = [[NSString alloc] initWithData: data2 encoding: NSUTF8StringEncoding]; NSLog (@«responseString=%@», responseString); // Ответ возвращается в XML — разбор ответа сами уже напишете, чай не маленькие // NSXMLParser *parser = [[NSXMLParser alloc] initWithData: data2]; // [parser setDelegate: self]; // [parser parse]; } Свое приложение я еще немного модифицировал — добавил собственную морду и вывод распознанного текста.Распознает, надо сказать обалденно хорошо.

image

Я, как обещал яндексу, вставил распозновалку в карточную игру King of Hearts, но задержка в 1–2 секунды при управлении голосом начинает раздражать через 5 минут после начала игры.

Тем не менее, ни одной ошибки распознавания названия игральной карты за время игры не произошло.Браво, Яндекс!

Пока готовил публикацию, пришел ответ от тех.поддержки команды yandex, они просят прислать полные логи неработающих приложений.Надо, наверное ответить им.

© Habrahabr.ru