Тема улучшения взаимодействия машин и человека сейчас актуальна как никогда.
Появились технические возможности перейти от модели «100 кликов» к парадигме «говори, что хочешь».
Да, я имею в виду различных ботов, которые разрабатываются всеми уже несколько лет. Например, многие крупные компании, причем не только технологические, но и ритейловые, логистические, банки, сейчас ведут активные исследования и разработки в этой области.
Простой пример, как, например, происходит процесс выбора товара в интернет-магазине? Куча списков, категорий, в которых я роюсь и что-то выбираю.
Это отстой.
Или, допустим, зайдя в интернет-банк, я сталкиваюсь с различными меню, если я хочу сделать перевод, то мне приходится выбирать в меню соответствующие пункты и вводить кучу данных, а если я хочу посмотреть список транзакций, тут опять же приходится напрягать как мозг, так и указательный палец.
Гораздо проще и удобнее было бы зайти на страницу и просто сказать: «Хочу купить литр молока и пол-литра водки» или просто спросить в банке: «Что не так с деньгамиЭ» В список профессий, которым грозит исчезновение в достаточно ближайшем будущем, вошли: кассиры, операторы колл-центров и многие другие.
И на простом примере, на реализацию которого у меня ушло около 7 часов, я покажу, как можно довольно просто интегрировать распознавание речи и обнаружение сущностей, на примере открытого Wit.Ai (интеграция с Google Speech API также включена).
API для распознавания речи довольно много, некоторые из них платные, некоторые открыты для разработки собственных систем.
Например, Google Speech API предлагает 60 минут распознавания в месяц бесплатно; если вы превысите этот лимит, с вас будет взиматься плата в размере 0,006 цента за минуту с шагом в 15 секунд. Wit.ai, наоборот, позиционирует себя как открытый API для разработчиков, но предоставят ли они тот же уровень сервиса, если, например, количество обращений к сервису вырастет до сотен тысяч, а то и миллионов в месяц? остается вопросом.
Пару недель назад мы проводили семинары по Data Science и искусственному интеллекту в Тарту, и многие спикеры так или иначе затрагивали тему взаимодействия человека и машины на понятном человеку языке.
И на следующих выходных после событий я решил реализовать распознавание речи с помощью общедоступных сервисов.
И конечно, хотелось бы, чтобы бот понимал, что я хочу пить пиво, и какое именно.
Темный или светлый, а также, возможно, поймет разновидности.
В общем, задача сводится к тому, чтобы записать на стороне клиента то, что он сказал, отправить на сервер, сделать какие-то преобразования, сделать вызов стороннего API и получить результат. Изначально я планировал вызвать Google Speech API, чтобы получить транскрипцию аудиофайла, а затем отправить строку текста в Wit.AI, чтобы получить набор сущностей и намерений.
Выбор бэкенда для меня был тривиален; это был Spring Boot. И не только потому, что стек Java для меня родной, но и потому, что мне хотелось создать небольшой сервис, который бы служил посредником между сторонними API и клиентом.
Дополнительный функционал можно реализовать, внедрив дополнительный сервис.
Я разместил исходный код на GitHub .
Рабочее приложение, которое я развернул на Heroku — https://speechbotpoc.herokuapp.com/ .
Перед использованием включите микрофон.
Затем щелкните значок микрофона и скажите что-нибудь, затем щелкните значок еще раз.
То, что вы сказали, будет использовано против вас, будет отправлено на признание, и через некоторое время вы получите результат на панели слева.
Я отключил выбор языка перевода, так как этим примером могут пользоваться несколько человек, то во избежание гонки выбор языка распознавания отключен.
Итак, для начала создаём пустой проект с помощью Spring Initializr или Spring Boot CLI, как вам больше нравится, я выбрал Spring Initializr. Необходимые зависимости — Spring MVC, Lombok (если не хотите писать много шаблонного кода), Log4j. Импортируйте созданную структуру проекта в предпочитаемую вами среду IDE (кто-нибудь еще использует Eclipse?).
Сначала нам нужно записать аудиофайл на стороне клиента.
HTML5 предоставляет для этого все возможности (интерфейс MediaRecorder), но есть отличная реализация от Мэтта Даймонда, которая распространяется под лицензией MIT, и я решил воспользоваться ею, поскольку Мэтт тоже разработал неплохой рендеринг на стороне клиента.
На самом деле больше всего времени заняла не разработка серверной части, а реализация на стороне клиента.
Я не использовал AngularJS или ReactJS, потому что меня интересовала общая интеграция, и мой выбор пал на jQuery, дешево и сердито.
Что касается серверной стороны, то сначала я хотел использовать Google Speech API для первоначальной транскрипции аудиофайла в текст, а поскольку этот API требует перекодирования записанной речи в Base64, на стороне клиента, получив аудиоданные, Я перекодировал его в Base64, а затем отправил на сервер.
В нашей структуре мы создаем контроллер, который будет получать наш аудиофайл.
Все довольно просто, принимаем данные и передаем их сервису, который делает всю дальнейшую работу.@RestController public class ReceiveAudioController { @Autowired @Setter private WitAiService service; private static final Logger logger = LogManager.getLogger(ReceiveAudioController.class); @RequestMapping(value = "/save", method = RequestMethod.POST) public @ResponseBody String saveAudio(@RequestBody Audio data, HttpServletRequest request) throws IOException { logger.info("Request from:" + request.getRemoteAddr()); return service.processAudio(data); } }
Сервис WitAiService также достаточно прост. @Data
@Component
@ConfigurationProperties(prefix="witai")
public class WitAiService {
private static final Logger logger = LogManager.getLogger(WitAiService.class);
private String url;
private String key;
private String version;
private String command;
private String charset;
public String processAudio(Audio audio) throws IOException {
URLConnection connection = getUrlConnection();
OutputStream outputStream = connection.getOutputStream();
byte[] decoded;
decoded = Base64.getDecoder().
decode(audio.getContent()); outputStream.write(decoded); BufferedReader response = new BufferedReader(new InputStreamReader(connection.getInputStream())); StringBuilder sb = new StringBuilder(); String line; while((line = response.readLine()) != null) { sb.append(line); } logger.info("Received from Wit.ai: " + sb.toString()); return sb.toString(); } private URLConnection getUrlConnection() { String query = null; try { query = String.format("v=%s", URLEncoder.encode(version, charset)); logger.info("Query string for wit.ai: " + query); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } URLConnection connection = null; try { connection = new URL(url + "?" + query).
openConnection();
} catch (IOException e) {
e.printStackTrace();
}
connection.setRequestProperty ("Authorization","Bearer " + key);
connection.setRequestProperty("Content-Type", "audio/wav");
connection.setDoOutput(true);
return connection;
}
}
Все необходимые параметры, такие как ключ и токен для Wit.AI, берутся из файла application.properties. (да, я открыл токены для своего приложения).
Если вы хотите зарегистрировать свое приложение на Wit.AI, то вам нужно будет изменить токены и App.ID в файлах настроек.
Регистрация на Wit.AI довольно проста; токен можно получить в разделе Настройки.
Spring Boot уточняет настройки с помощью аннотаций.
Аннотации Данные И Сеттер это аннотации проекта Ломбок , которые помогают избежать написания шаблонного кода в виде сеттеров, геттеров, конструкторов по умолчанию и т. д. Файлы модели и вспомогательный конвертор я сюда не включаю, все это можно посмотреть в исходниках.
Если вы откроете консоль разработчика в Chrome, вы увидите, что после того, как вы записали сказанное, происходит вызов REST службы, при котором аудиоданные в кодировке Base64 передаются на сервер в поле контента.
У меня были некоторые проблемы с биллингом Google (биллинг был зарегистрирован на старую кредитную карту, которая была закрыта, но новую я еще не оформил), и после того, как я написал взаимодействие с Google Speech API, я решил отправить его напрямую в Wit.AI для признания.
Но Wit.AI принимает данные в потоковом виде как есть, и поэтому сервер конвертирует их из Base64 обратно в формат wav. byte[] decoded;
decoded = Base64.getDecoder().
decode(audio.getContent());
outputStream.write(decoded);
Небольшие моменты, касающиеся признания.
Обратите внимание на уровень микрофона, так как если он очень чувствительный, вы получите обрезанный звук, что негативно скажется на качестве распознавания.
Теперь, когда мы получили признание сказанного, давайте научим приложение понимать, чего мы конкретно хотим.
В главе Понимание Wit.AI (Для этого вам необходимо зарегистрировать свое приложение на Wit.AI, то есть зарегистрироваться, это не сложно.
) Мы можем задать так называемый интент, или намерения.
Выглядит вполне логично, пишем строку, например, «Пойдем пить пиво» и выделяем нужное нам слово, в данном случае «Пиво», и нажимаем на Добавить новую сущность (Добавить новую сущность), затем выбираем намерение , и создайте намерение «Пиво».
Идем дальше, хотим понять, хотим ли мы пить пиво, а затем создаем новую сущность «Пить» или «Пить».
Далее рекомендуется ввести еще несколько примеров, например: «Может быть сегодня пивка», «Давай завтра выпьем пивка» и т. д. Тогда система будет все точнее определять намерение - Пиво.
Теперь, допустим, мы хотим понять, какое пиво мы хотим пить, светлое или темное.
Таким же образом вводим новую фразу «Завтра выпьем темное пиво» и на слово «темное» нужно нажать еще раз.
Добавить новую сущность , но далее нам нужно не использовать то, что уже есть, а создать свою сущность, в моем приложении она так называется тип пива .
Далее повторяем для светлого пива, только выбираем уже созданную сущность тип пива .
В результате система начинает понимать, что я хочу пить пиво и какое именно.
Все вышеперечисленное также можно настроить не вручную, а автоматически с помощью REST-интерфейса Wit.AI. Категории можно легко преобразовать в сущности в пакетном режиме.
Попробуйте в примере предложить выпить темное или светлое пиво, вы увидите, что система возвращает объект, который содержит как намерение пива, так и тип пива — темное или светлое.
Этот пример немного игрушечный, НО.
Добавлять сущности можно и через REST-интерфейс, таким образом, перевод каталога товаров в сущности бота можно выполнить довольно легко, а в Wit.AI есть множество контекстных сущностей, например время/дата, место и т. д. То есть получить информацию можно из контекстных слов, таких как сегодня-завтра (дата), здесь (место) и т. д. Подробная документация доступна.
здесь .
Сам код довольно простой, и на его основе все понятно.
Логика интеграции с другими сервисами та же.
После получения транскрипции вы можете передать эту строку другим сервисам, например, написать сервис, который будет добавлять нужные товары в корзину, или просто передать строку нейросервису для перевода ( http://xn--neurotlge-v7a.ee/# пока с эстонского на английский и обратно, но можно обучить модель и на других языках).
То есть этот пример может послужить небольшим строительным блоком для построения более сложного потока взаимодействий.
Например, я могу, скажем, заказать пиво на дом, подключив этот пример к сервису заказа еды, получив его токен или cookie. Или, наоборот, отправлять предложения пива друзьям через мессенджер.
Существует огромное количество вариантов использования.
Возможные способы использования: интернет-магазины, интернет-банки, системы переводов и т.д. Если у вас есть какие-либо вопросы, вы можете связаться с нами.
Теги: #открытый исходный код #распознавание речи #бот #java #spring #spring boot #открытый исходный код #программирование #java #Системный анализ и проектирование #Машинное обучение
-
Как Нанять Надежный Ремонт Компьютеров
19 Oct, 24 -
Мой Принтер Умер - Эпитафия
19 Oct, 24 -
Бета-Версия Mvc Framework
19 Oct, 24 -
Именование Сложных Действий В Rest Api
19 Oct, 24