Голосовые помощники уже используются для решения разных задач и в колл-центрах, и на производстве, и дома. Также очевиден тренд – разработка, развитие и интеграция решений из сегментов UC и IoT – это новый виток в развитии обоих направлений, когда умные датчики самостоятельно отправляют сообщения со статусом производственного процесса, оповещают о неполадках, выполняют массу других функций, «завязанных» на коммуникационные каналы. Развитие таких интеграций – настолько креативный процесс, что ограничен он только творческими возможностями разработчиков. На наших глазах создается целая экосистема с принципиально новым пользовательским опытом.
Какой он, современный секретарь в «Офисе будущего»?
Благодаря симбиозу технологий совместной работы, универсальной платформы интернета вещей CTI IoT Platform и голосовых помощников с искусственным интеллектом можно создавать умные переговорные комнаты, аудитории, производственные помещения.
Например, умный секретарь от CTI позволяет через голосовые команды управлять всеми процессами в переговорной комнате: регулировать климат, освещение, управлять оборудованием, заказывать напитки, организовывать собрания, бронировать помещения, подключать удаленных участников и прочее. Объединив разрозненные системы в высокоэффективное рабочее пространство, можно вывести комфорт и продуктивность совместной работы сотрудников на новый уровень.
Давайте посмотрим, как это работает, и немного расскажем о наших секретах
Мы в CTI занимаемся сложными интеграционными проектами и автоматизацией процессов. Делаем это ещё с тех времён, когда вместо какой-нибудь «Алисы» энтузиасты вручную собирали умные розетки на базе ESP8266 или Arduino, а понятие Internet of Things (IoT) не приобрело широкую популярность.
Одна из концепций, которую развиваем, — объединение унифицированных коммуникаций (UC), мультимедия и Интернета вещей (IoT). В первое понятие входит как офисная видеоконференцсвязь, так и умные голосовые помощники. В современных офисных пространствах на стенах перед входом в кабинет вешают информационные тачпанели или используют настольные варианты, которые стоят в самом кабинете. На такую панель без проблем выводится любая информация и простым нажатием на кнопки можно реализовать любой запрос (настроить кондиционер, заказать напитки, запустить проектор, приглушить свет и т.д.). Но для этого нужно нажимать и выбирать пункт из меню. А удобнее ведь просто сказать …
Два кофе в переговорку
Эта идея зародилась в CTI в отделе «Дополнительные сервисы» давно и пережила несколько итераций — почти каждый сотрудник внёс свой вклад. Мы хотели, чтобы в переговорке каждый мог сказать умной колонке свои пожелания по напиткам и заказ автоматически уходил секретарю или «хозяйке офиса».
Итак, мы взяли колонку «Яндекс.Алиса» и под неё написали навык на Python 3, который сейчас крутится в офисе на нашем внутреннем сервере и обрабатывает все команды из переговорок. Заказ поступает в Telegram-бота, который мониторит «хозяйка офиса». В боте две кнопки, которые показывают возможно принять и выполнить заказ или нет.
![](https://habrastorage.org/getpro/habr/upload_files/332/32c/881/33232c8812645a24b1965a8a38a14f00.png)
Первоначально приходилось вручную обрабатывать все словоформы, поскольку человек может сказать как «зелёный чай», так и, например, «чашку зелёного чая». Впоследствии Яндекс добавил систему интентов, куда стало возможно вводить леммы.
![](https://habrastorage.org/getpro/habr/upload_files/851/953/33a/85195333ad4d630561c7b5033cfe0832.png)
Поначалу мы реализовывали только самые простые команды, но всем хотелось разнообразия: указывать тип напитка с добавкой, например, молоко к кофе. Иногда нужно знать параметр, который человек не назвал: тот же чай бывает чёрным или зелёным. В таких ситуациях боту приходится переспрашивать, если информации было недостаточно. Подобный процесс называется заполнением слотов (slot-filling). В движке Amazon Alexa он, например, реализован прямо из коробки: можно перечислить требуемые слоты в настройках навыка, и Alexa будет задавать вопросы самостоятельно. Но у Яндекса пока такого нет — пришлось написать обработку вручную.
Основная версия кода выглядит вот так:
# coding: utf-8
# Импортирует поддержку UTF-8.
"""
МОДУЛЬ DrinksIntent заказ напитков
МЕТОД - НОВЫЙ NLP метод
https://yandex.ru/dev/dialogs/alice/doc/nlu-docpage/
"""
from __future__ import unicode_literals
from superIntent import superIntent
from utils import *
import random # для генерации случайных ответов
import requests # для отправки HTTP GET/POST запросов
class Intent(superIntent):
intent_name = "DrinksIntent"
slot_dict = {
'water': 'вода',
'tea': 'чай',
'coffee': 'кофе',
'black': 'чёрный',
'green': 'зелёный',
'milk': 'с молоком',
'pure': 'негазированая',
'spring':'газированая'
}
def __init__(self, log, config,enable=True):
super().__init__(self.intent_name, log, config, enable) #вызываем конструктор родительского класса
self.user_id = ""
self.lastmsg = False
self.order_id = 0 # номер заказа
def slot(self,req,slot):
return super().getSlot(req,self.intent_name,slot)
def Run(self, req, res, tbot,params=False):
self.DisambiguationCheck(req,res)
if self.intent_name in req['request']['nlu']['intents']:
self.log.debug("Request has this intent!")
else:
return False
if super().preRun(req,res):
self.log.debug("Start proceed")
room = self.last_room
if len(room) and self.config.has_option('rooms',room) and self.config.has_option(room,'chat_id'): #если есть в комнате свой чат
self.log.debug("room: %s what: %s sort: %s qnt: %s" % (room,self.slot(req,'what'),self.slot(req,'sort'), self.slot(req,'qnt')))
if self.slot(req,'what'):
what = self.slot(req,'what')['value']
if self.slot(req,'qnt') and self.slot(req,'sort'):
qnt = self.slot(req,'qnt')['value']
if what == 'water' and self.slot(req,'sort')['value']=='spring' and self.slot(req,'prep') and self.slot(req,'prep')['value'] == 'without':
sort = self.slot_dict['pure']
else:
sort = self.slot_dict[self.slot(req,'sort')['value']]
self.lastmsg = tbot.send_text(self.config[room]['chat_id'],"Заказ напитков от пользователя '%s' в комнату: <b>%s</b>\n %s %s : <b>%d</b>" % (self.getAuthName(), self.config['rooms'][room], self.slot_dict[what], sort, qnt ), buttons_type = False )
tbot.setLastMsg(self.lastmsg)
if self.config.has_option(room,'drinks_chat_id'): #если есть доп. чат для напитков
tbot.send_text(self.config[room]['drinks_chat_id'],"Заказ напитков от пользователя '%s' в комнату: <b>%s</b>\n %s %s : <b>%d</b>" % (self.getAuthName(), self.config['rooms'][room], self.slot_dict[what], sort, qnt ) , buttons_type =1 )
super().setRes(res, text="%s, Напиток %s %s - заказан, в количестве %d " % (self.getAuthName(), self.slot_dict[what], sort, qnt) )
self.order_id += 1
self.log.info( "New order: %d" % self.order_id )
elif self.slot(req,'qnt') and not self.slot(req,'sort'): # неуказан тип-характеристика напитка, создаем уточнение
qnt = self.slot(req,'qnt')['value']
if what=='water':
super().setRes(res, text="Уточните пожалуйста, вам воду с газом или без?" )
elif what =='tea':
super().setRes(res, text="Уточните пожалуйста, чай чёрный или зеленый?" )
else:
super().setRes(res, text="Уточните пожалуйста, кофе чёрный или с молоком?" )
super().saveSlot( 'what',what ) # сохраняем в сессии уже определенный слот
super().saveSlot( 'qnt', qnt ) # сохраняем в сессии уже определенный слот
super().createDisambiguation('sort',2)
else: # Неуказано кол-во напитков, или вообще ничего - создаем уточнение
if self.slot(req,'sort'):
super().saveSlot('sort', self.slot(req,'sort')['value'] ) # сохраняем в сессии уже определенный слот
super().setRes(res, text="Уточните, пожалуйста, сколько нужно?" )
super().saveSlot('what',what ) # сохраняем в сессии уже определенный слот
super().createDisambiguation('qnt',2)
return True
return False
#self.log.info("Request tokens Matched!")
# TODO HERE:
# room = self.last_room
# if len(room) and self.config.has_option('rooms',room) and self.config.has_option(room,'Tea-URL'):
# url = self.config[room]['Tea-URL']
else:
return False
def DisambiguationCheck(self, req, res):
self.log.debug(req)
qnt = find_yandexnumber(req['request']['nlu']['entities'])
sort = ""
if check_needles( req['request']['nlu']['tokens'],['зелёного','зелёный', 'зелёные','зелёных' ,'зеленого','зеленый', 'зеленые','зеленых' ] ):
sort = 'green'
if check_needles( req['request']['nlu']['tokens'],['чёрного','чёрный', 'чёрные','чёрных' ,'черного','черный', 'черные','черных' ] ):
sort = 'black'
if check_needles( req['request']['nlu']['tokens'],['молоком','молоко','молока' ] ):
sort = 'milk'
if check_needles( req['request']['nlu']['tokens'],['газированная','газированную'] ) or ( check_needles( req['request']['nlu']['tokens'],['газом'] ) and check_needles( req['request']['nlu']['tokens'],['с'] ) ):
sort = 'spring'
if check_needles( req['request']['nlu']['tokens'],['негазированная','без','негазированную', 'бес', 'вес' ] ) or ( check_needles( req['request']['nlu']['tokens'],['газа'] ) and check_needles( req['request']['nlu']['tokens'],['без','бес','вес'] ) ):
sort = 'pure'
dis = self.getDisambiguation()
if dis:
self.log.debug(dis)
dis['attempts'] -= 1
if super().getSavedSlot('what'):
req['request']['nlu']['intents'][self.intent_name] = {
'slots': {
'what':{ 'value': super().getSavedSlot('what') }
}
}
for s in ('sort','qnt' ):
if super().getSavedSlot(s):
req['request']['nlu']['intents'][self.intent_name]['slots'][s] = { 'value': super().getSavedSlot(s) }
if qnt and int(qnt['value']) > 0 and dis['slot']=='qnt':
req['request']['nlu']['intents'][self.intent_name]['slots']['qnt'] = { 'value': int(qnt['value']) }
if sort:
req['request']['nlu']['intents'][self.intent_name]['slots']['sort'] = { 'value': sort }
self.flushSession()
Результат
Голосовое управление впечатляет гостей нашего офиса: люди интересуются системой, спрашивают, можно ли сделать так у них и интегрировать в их систему (спойлер: можно как угодно).
Помимо демонстрационного эффекта есть и чисто практический: уменьшается время реакции и минимизируется количество ошибок по принятию заказа. Этот бизнес-процесс породил и другие. Например, через собственного голосового ассистента наши сотрудники взаимодействуют с административно-хозяйственным отделом (заказ уборки помещений), с кадрами (заказ различных справок, уточнение количество дней отпуска). Ассистент принимает голосовые заявки, обрабатывает и сообщает о статусе их выполнения.
А нашим партнерам мы помогли реализовать интересный кейс в кафе, где заказ формируется человеком, а развозится роботом. Мы предложили собирать заказ с помощью голосового ассистента и сразу передавать его в гейткипер и на кухню, а далее развозить роботом. Получилось почти полностью автоматизированное кафе – «кафе будущего».
Алиса, открой окно
Более технически сложный кейс — организация автоматического проветривания. Помозговали, от каких параметров отталкиваться, и сделали.
Начали с выбора железа. Вообще, на рынке большое количество устройств и технологий для автоматизации. У нас есть экспертиза работы как с дорогими решениями (Crestron, AMX и т. п.), так и с бюджетными DIY на Arduino и Raspberry Pi. Опыт и текущая обстановка показали, что требуется законченное многофункциональное устройство с небольшим бюджетом, широкими возможностями по кастомизации, хорошим комьюнити, открытыми протоколами и при этом российского производства. Так что в основу проекта лег контроллер для промышленной и домашней автоматизации от компании Wiren Board. Он очень гибок и поддерживает большинство существующих протоколов.
![](https://habrastorage.org/getpro/habr/upload_files/cdc/469/ac6/cdc469ac663d68a312d543ce5d50a3aa.png)
У Wiren Board есть универсальный комбинированный датчик WB-MSW, измеряющий температуру, влажность, уровень углекислого газа и ещё несколько показателей — именно с него стали для начала брать информацию. Позже, помимо показания температуры, мы с помощью датчика движения и видеоаналитики решили оценивать количество людей в помещении. Например, можно включать проветривание, только когда в переговорке нет людей или наоборот их слишком много. На такой случай мы сделали настраиваемые пресеты. В зависимости от этих условий система принимает решение — открывать окна или нет. По аналогии настроили работу кондиционера, но сейчас мы рассматриваем более сложный кейс с окном.
![](https://habrastorage.org/getpro/habr/upload_files/f6e/5f0/2c5/f6e5f02c5085c807a3ead29b3b3f3d77.png)
Многие системы электроприводов окон очень дорогие и поставляются чуть ли не под заказ. Здесь нас спас небольшой российский стартап Drivent.ru. Ребята работают больше над качеством, чем над массовостью. Их приводы управляются через Wi-Fi по протоколу MQTT. Можно задавать положения: открыть окно на небольшой уровень проветривания или на полный.
Разумеется, всё это интегрировано в нашу IoT-платформу и работает как полноценная климатическая система. Главные сервисы на Wiren Board: это MQTT-брокер Mosquitto, Node-RED (чтобы связать MQTT и разнообразное оборудование), Zigbee2MQTT (для беспроводных датчиков) — старались выбирать открытые, не проприетарные инструменты, не требующие сертификаций или подписания NDA. В помещении у нас отдельный датчик температуры WB-MSW v.3, подключенный по Modbus протоколу. Климат-контроль, занимающийся обогревом и охлаждением помещения, связан с системой проветривания: например, окна закрываются при падении температуры ниже критического минимума, даже если при этом целевое содержание CO2 не достигнуто. Приоритет данных показателей тоже настраивается в пресете.
![](https://habrastorage.org/getpro/habr/upload_files/a38/f6f/08c/a38f6f08c3882443762698f04da86a8e.png)
В дополнение всё это точно также управляется через Алису: можно установить голосом целевую температуру, включить/выключить отдельные функции. Если проветривание мешает, его можно временно отключить с автоматическим возвратом через заданное время.
Это лишь два простых примера, которые мы реализовали в начале пути создания «Офиса будущего» и самого умного и сговорчивого секретаря. Причем используемый голосовой бот может быть любым – от любого производителя. Наш умный секретарь понимает речь человека за счет встроенного механизма распознавания речи (Automatic Speech Recognition, ASR) и может выполнять задания, не связанные с физическим трудом, общается с помощью голоса за счет механизмов синтеза речи (Тext To Speech, TTS), встраивается в АТС организации как полноценный абонент с отдельным номером, может самостоятельно осуществлять и принимать звонки, соединять между собой сотрудников компании, умеет идентифицировать звонящего сотрудника независимо от источника звонка (мобильный телефон/внутренний телефон АТС предприятия), а также может применять технологии идентификации человека по пин-коду в IVR.
Также наш умный секретарь формирует и предоставляет отчеты, озвучивая их голосом или отправляя текстовый вариант на e-mail и в мессенджеры, через голосовые команды помогает бронировать переговорные комнаты, назначать совещания, приглашать сотрудников на встречу, заказывать напитки, формировать заявки для служб АХО, HR и т.д.
А начиналось все с заказа кофе в переговорку.