Статья описывает свой скромный опыт работы с Yandex Speachkit Cloud. Она не претендует на максимально развернутое сообщение об этой системе. Скорее, это даже немного художественная статья, переплетающаяся с технической.
Однажды я задумал написать для себя проект: телеграм-бота, который помогает вести семейный бюджет. Вроде всего-ничего: арендовал vds на убунте 16.4, развернул postgresql 9.6 и, конечно же, сервер 1С 8.3.12...(не помню по памяти), накидал план-проект и, соответственно, приступил к работе. Во время работы вдруг пришла идея: а почему бы не сделать так: отправлять боту аудиосообщение с командой, скажем, "поступление 5 рублей", после этого речь должна будет преобразовываться в текст и обрабатывать команду? К моменту, когда пришла эта идея, основной модуль по обработке команд из текстовых сообщений был готов.
Пришла идея и понеслось. Во-первых нужно было решить, какой использовать сервис, который будет преобразовывать речь в текст. Оказалось, что русскую речь преобразовывает только сервис Яндекса.
Небольшое отступление. Прочитав документацию, я понял, что в этом нет ничего сложного. Достаточно написать один http запрос и вуаля... Однако на Инфостарте я нашел обработку, которая, конечно, чуть посложнее, но в принципе - то же самое. Стоит такая обработка 9000р. Нормально так.
Итак, поехали. Буду писать код по частям и комментировать. Код будет содержать также запросы в телеграм.
Для начала нужно получить файл звукового сообщения с сервера телеграм. Для этого нужно выполнить два GET запроса. У первого запроса метод "getFile", в котором указывается один параметр - "file_id". Значение этого параметра содержится в структуре сообщения (читайте документацию телеграм апи). При выполнении этого запроса сервер телеграм находит нужный нам звуковой файл и дает ему временную уникальную ссылку, которую выдает в ответе. Второй запрос - это получение, непосредственно, самих двоичных данных файла. После получения сохраняем файл.
Звук = СтруктураСообщения.voice; Запрос = Новый HTTPЗапрос(BotID + "/getFile?file_id=" + Звук.file_id); Ответ = Соединение.Получить(Запрос); СтрокаОтвет = Ответ.ПолучитьТелоКакСтроку(); Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(СтрокаОтвет); Структура = ПрочитатьJSON(Чтение); Запрос = Новый HTTPЗапрос("/file/" + BotID + "/" + Структура.result.file_path); Ответ = Соединение.Получить(Запрос); ДД = Ответ.ПолучитьТелоКакДвоичныеДанные(); Файл = ПолучитьИмяВременногоФайла("ogg"); ДД.Записать(Файл);
На этом останавляваться не будем. Кому интересно - читайте документацию.
Вот, у нас есть звуковой файл. Такие голосовые сообщения хранятся в формате .ogg, что очень удобно ввиду их небольших размеров, а также того, что Яндекс также по-умолчанию принимает именно этот формат файла. Теперь нам необходимо авторизоваться в Яндекс облаке. Во-первых, нужно похимичить с созданием платежного аккаунта, созданием каталога, назначении ему прав. Обо всём написано здесь. Четвертый пункт в этой инструкции гласит, что нужно получить IAM-токен. Здесь самое интереное: IAM-токен действителен в течение 12 часов. Получается, что его нужно периодически обновлять. Здесь описано, как это сделать. Для обновления IAM-токена нужен постоянный пользовательский OAuth-токен, который можно получить на той же странице, перейдя по ссылке в пункте 2 на вкладке API. Всё, самое сложное позади;)
Так как IAM-токен действителен в течение 12 часов, то сначала я сделал регламентное задание. Но практика показала, что он действует меньше. Поэтому я сделал, чтобы он обновлялся при получении каждого голосового сообщения. Ничего страшного, пусть пашет;) Итак, для обновления токена создается https соединение с доменом "iam.api.cloud.yandex.net" и стандартными портами и выполняется один простой POST-запрос "/iam/v1/tokens". Заголовок один, который гласит, что мы отправляем данные в формате json. В теле запроса указываем один параметр "yandexPassportOauthToken" и в значение этого параметра указываем наш OAuth-токен. В ответе на такой запрос получаем новенький IAM-токен.
Процедура ОбновитьIAMЯндекс() СоединениеЯндекс = Новый HTTPСоединение("iam.api.cloud.yandex.net", 443, , , , 20, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено); Заголовки = Новый Соответствие; Заголовки.Вставить("Content-Type","application/json"); Запрос = Новый HTTPЗапрос("/iam/v1/tokens",Заголовки); СтрокаТела = "{""yandexPassportOauthToken"": """ + Константы.OAUTHТокен.Получить() + """}"; Запрос.УстановитьТелоИзСтроки(СтрокаТела,КодировкаТекста.UTF8); ФайлИтога = ПолучитьИмяВременногоФайла(); СоединениеЯндекс.ОтправитьДляОбработки(Запрос, ФайлИтога); ТекДок = Новый ТекстовыйДокумент; ТекДок.Прочитать(ФайлИтога); Ответ = ТекДок.ПолучитьТекст(); Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(Ответ); СтруктураОтвета = ПрочитатьJSON(Чтение); Константы.IAMТокенЯндекс.Установить(СтруктураОтвета.iamToken); КонецПроцедуры
Итак, ещё одна часть завершена. Теперь, наконец, самое интересное - отравить яндексу запрос на распознавание речи. Ах да, ещё нюанс... Помните, что нужно было создать каталог в Яндекс облаке? Нам нужен ID этого каталога. Это совсем не сложно - смотрите здесь.
И финишная прямая. Создаем новое https соединение с доменом "stt.api.cloud.yandex.net"и стандартными портами. Создаем POST-запрос "/speech/v1/stt:recognize/". В заголовках указываем стандартный "Content-Type=application/json", А также наш IAM-токен. Имя заголовка "Authorization", значение - "Bearer " + наш токен. В параметрах запроса только один обязательный - "folderId", в значение которого вписываем ID нашего каталога. О других параметрах читайте в документации. В тело запроса вставляем наши двоичные данные, полученные с сервера телеграм.
СоединениеЯндекс = Новый HTTPСоединение("stt.api.cloud.yandex.net", 443, , , , 20, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено); Заголовки = Новый Соответствие(); Заголовки.Вставить("Authorization", "Bearer " + Константы.IAMТокенЯндекс.Получить()); Заголовки.Вставить("Content-Type", "application/json"); Запрос = Новый HTTPЗапрос("/speech/v1/stt:recognize/?topic=general&folderId=" + Константы.ИДПапкиЯндекс.Получить() + "&lang=ru-RU",Заголовки); Запрос.УстановитьТелоИзДвоичныхДанных(ДД); Ответ = СоединениеЯндекс.ОтправитьДляОбработки(Запрос); СтрокаОтвет = Ответ.ПолучитьТелоКакСтроку(); Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(СтрокаОтвет); СтруктураОтвета = ПрочитатьJSON(Чтение); ТекстСообщения = СтруктураОтвета.result;
Всё. В ответе на последний запрос будет результат - строка. После этого делаем с этой строкой всё, что душе угодно;)
Итак, организовать распознавание речи в текст сделать не так уж сложно. Конечно, не во всяком бизнесе это пригодится. Но зато мне очень круто говорить своему боту, а он делает всё, что я ему скажу;)
Полный листинг того, что получилось, прилагаю внизу. Если вам оказалась эта статья полезной и интересной, или же у вас есть объективные отзывы и комментарии, буду рад о них узнать. Если статья окажется полезной, то в дальнейшем напишу про прочие фишки, которые я использовал при создании бота, а, может, даже и про то, как этот бот создается. Всем спасибо за внимание!
Листинг:
Функция ПолучитьТекстИзГолосовогоСообщения(СтруктураСообщения) Если СтруктураСообщения.Свойство("voice") Тогда // получаем уникальный код звукового файла Звук = СтруктураСообщения.voice; Запрос = Новый HTTPЗапрос(BotID + "/getFile?file_id=" + Звук.file_id); Ответ = Соединение.Получить(Запрос); СтрокаОтвет = Ответ.ПолучитьТелоКакСтроку(); Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(СтрокаОтвет); Структура = ПрочитатьJSON(Чтение); // получаем двоичные данные Запрос = Новый HTTPЗапрос("/file/" + BotID + "/" + Структура.result.file_path); Ответ = Соединение.Получить(Запрос); ДД = Ответ.ПолучитьТелоКакДвоичныеДанные(); // обновляем IAM-токен ОбновитьIAMЯндекс(); // получаем готовый результат СоединениеЯндекс = Новый HTTPСоединение("stt.api.cloud.yandex.net", 443, , , , 20, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено); Заголовки = Новый Соответствие(); Заголовки.Вставить("Authorization", "Bearer " + Константы.IAMТокенЯндекс.Получить()); Заголовки.Вставить("Content-Type", "application/json"); Запрос = Новый HTTPЗапрос("/speech/v1/stt:recognize/?topic=general&folderId=" + Константы.ИДПапкиЯндекс.Получить() + "&lang=ru-RU",Заголовки); Запрос.УстановитьТелоИзДвоичныхДанных(ДД); Ответ = СоединениеЯндекс.ОтправитьДляОбработки(Запрос); СтрокаОтвет = Ответ.ПолучитьТелоКакСтроку(); Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(СтрокаОтвет); СтруктураОтвета = ПрочитатьJSON(Чтение); Возврат СтруктураОтвета.result; Иначе Возврат Неопределено; КонецЕсли; КонецФункции Процедура ОбновитьIAMЯндекс() СоединениеЯндекс = Новый HTTPСоединение("iam.api.cloud.yandex.net", 443, , , , 20, Новый ЗащищенноеСоединениеOpenSSL(), Неопределено); Заголовки = Новый Соответствие; Заголовки.Вставить("Content-Type","application/json"); Запрос = Новый HTTPЗапрос("/iam/v1/tokens",Заголовки); СтрокаТела = "{""yandexPassportOauthToken"": """ + Константы.OAUTHТокен.Получить() + """}"; Запрос.УстановитьТелоИзСтроки(СтрокаТела,КодировкаТекста.UTF8); ФайлИтога = ПолучитьИмяВременногоФайла(); СоединениеЯндекс.ОтправитьДляОбработки(Запрос, ФайлИтога); ТекДок = Новый ТекстовыйДокумент; ТекДок.Прочитать(ФайлИтога); Ответ = ТекДок.ПолучитьТекст(); Чтение = Новый ЧтениеJSON; Чтение.УстановитьСтроку(Ответ); СтруктураОтвета = ПрочитатьJSON(Чтение); Константы.IAMТокенЯндекс.Установить(СтруктураОтвета.iamToken); КонецПроцедуры