Привет! Вы наверняка слышали про первый в России хакатон по теме цифровизации индустрии туризма. Компанию Аэроклуб ИТ представляли на нём сразу две команды, и нам удалось не только отлично провести время, но и разработать прототипы проектов, попробовать силы в необычном для себя формате работы, и пообщаться с другими участниками. Под катом – история одной из наших команд!
При подаче заявки надо было выбрать одну из 10-ти предложенных задач (треков). Это были кейсы таких известных компаний, как «МегаФон», Facebook, PANORAMA 360, MTS Startup Hub, «Аэроэкспресс», Пушкинский музей, парк «Царицыно», Discover Moscow, «Город открытий», и Russpass.
Мы подали заявки на участие сразу двух команд: «Team 73» в треке «Аэроэкспресс», и «New horizons» — в «Царицыно». Первый был выбран потому, что близок к сфере деятельности нашей компании (программные B2B-решения), и в случае победы мы вполне могли бы продолжить сотрудничество и разработку. Второй – ребятами, которые хотели отвлечься от повседневных задач и попробовать что-то новое.
В общем чате мероприятия говорили, что была подана 1241 заявка (как командные, так и индивидуальные), и, как вы уже догадываетесь, мы прошли отбор! Причём обе наши команды!
Дело оставалось за малым – поучаствовать в самом хакатоне.
Хакатон
На площадке было всё как обычно: регистрация, зона с закусками, столы с номерами команд.
В 9:30 состоялось короткое открытие: пара слов от организаторов, торжественный старт хакатона, и началась работа. Далее речь пойдёт от имени участников команды «Team 73», которая взялась за задачу от «Аэроэкспресса».
Вначале мы пообщались с менторами: узнали, что они хотели бы увидеть в решении, какие есть нюансы, и чему отдать предпочтение. Команды были немного удивлены, когда оказалось, что обещанные ресурсы не будут предоставлены. По описанию задачи, мы могли получить API «Аэроэкспресс»,
Решение
Основная проблема, которую требовалось решить – автоматизация продажи билетов на «Аэроэкспресс» для юр. лиц. Мы провели некоторые исследования текущего процесса и были, мягко говоря, в шоке. Как мы узнали из публичной оферты для юридических лиц, сначала от компании-заказчика отправляется письмо-акцепт в качестве запроса на необходимое количество билетов, с указанием реквизитов компании. Далее — оплачивается выставленный счёт и, самое главное, каким-то образом происходит получение билетов в виде запароленного архива. То есть, как вы поняли, минимальный уровень автоматизации.
Мы набросали CJM (customer journey map), выбрали минимально необходимый функционал, подумали над дизайном. В какой-то момент мы рассудили следующим образом: каждая команда, так или иначе, покажет примерно одинаковые решения: регистрация юр. лица, покупка билета, выставление счёта, и так далее. Чтобы как-то выделиться, надо было придумать что-то особенное. Как минимум, нужен хороший дизайн, тогда на общем фоне наше решение будет чуть заметнее. Благо, в другой нашей команде есть дизайнер, и она нам с этим поможет. Но нужно было что-то ещё, что-то совсем необычное для B2B. И тогда мы решили добавить интеграцию с Алисой – той самой, голосовым помощником от Яндекса.
Причин было несколько: основная – у нас есть некоторый опыт работы с ней, чтобы в короткие сроки сделать более-менее полезный прототип. Ещё одна – B2B, как правило, ассоциируется с чем-то скучным и формальным, а получение билетов через говорящую колонку – что-то новенькое. К тому же, у нас два бэкенд-разработчика, и толкаться вдвоём в одном проекте не очень удобно, а так мы параллельно сделаем и основной функционал, и дополнительный.
Начну с основного решения – Портал оптовых продаж Аэроэкспресса. По нашей задумке, он состоит из двух частей: фронтенд и, конечно же, бэкенд.
Фронтенд
Наш фронтендер – адепт Angular, отсюда и выбор именно этого фреймворка. Angular «из коробки» даёт хорошее стартовое окружение, в котором не надо заморачиваться с конфигурацией, роутингом, и подключением к бэкенду– то, что надо для хакатона. Так же наш разработчик давно работает с ним и накопил несколько своих библиотек, с которыми можно сэкономить немного времени на хакатоне.
В результате у нас получился вот такой фронтенд:
Внешний вид мы старались сделать современным, стильным, выдерживая цвета «Аэроэкспресса».
Здесь у нас был реализован следующий функционал:
- Поиск названия компании по ИНН
- Регистрация компании и контактного лица с указанием примерного объёма продаж билетов в месяц.
- Авторизация сотрудника компании
- Заказ билета
- Количество предстоящих поездок
- История заказов
- Личный кабинет менеджера со стороны «Аэроэкспресса»
Мы постарались сделать максимально простую регистрацию компании на портале: её представителю достаточно знать ИНН юр. лица, и ввести его в соответствующем поле. Если появившееся название подходит – можно продолжать. Регистрация на портале – это одновременно заявка на сотрудничество с компанией «Аэроэкспресс». Менторы подсказали, что им будет проще рассматривать такие заявки, если представители будут указывать примерный объём продаж билетов в месяц, для этого мы добавили соответствующее поле.
На первый взгляд может показаться, что сделано не так уж и много, но у нашего решения очень красивый и проработанный дизайн. Его сделали с нуля, не используя никаких готовых шаблонов. По предыдущему опыту, в хакатонах зачастую побеждали решения, которые были не столь хорошо проработаны, но «завёрнуты в красивую упаковку», и в этот раз мы решили сделать ставку именно на красивый внешний вид. Забегая вперёд, скажу, что менторы были в восторге от нашего дизайна, но оценивали решения именно по количеству реализованных функций и по дальнейшей перспективе применения решения (которую некоторые команды хорошо продумали).
Бэкенд
Оба наших бэк-разработчика – матёрые шарписты (пишут на C#), поэтому и бэк основан на .net core. Была выбрана версия 2.1, поскольку приложения на нём точно поднимаются на резервном
Здесь мы сделали всё необходимое для «фронта»:
- Поиск информации о компании по ИНН
- Регистрация компании и его контактного лица
- Аутентификация по логину-паролю
- Авторизация по Bearer-токену
- Получение информации о пользователе
- Получение списка сотрудников компании текущего пользователя
- Создание заказа
- Отправление билета на почту после создания заказа
- Отправка билета на почту запрошенному пользователю (для внешней интеграции)
- Получение информации о всех билетах компании
- Вывод списка заказов
- Вывод списка зарегистрированных компаний
Из интересного – интеграция с поиском организации по ИНН или ОГРН в Dadata, для лёгкой регистрации юр. лица. Если кратко – бэкенд получает запрос «найди компанию» с переданным ИНН, и отправляет эту информацию в API сервиса. В ответ, если компания найдена, получаем информацию о ней: краткое название (отдаём в ответе), и реквизиты. Полученные данные полезно где-то сохранить, потому что они пригодятся при формировании счетов: пользователю будет достаточно проверить их корректность, что гораздо проще, чем «вбивать» самостоятельно.
Навык для голосового помощника
Навыки для ассистентов – это, как правило, веб-сервисы, которые работают с определённым протоколом запросов и ответов. Как уже говорил, мы выбрали интеграцию с Алисой в качестве дополнения к основному решению. Подробнее о протоколе работы с ней вы можете узнать из документации, а ещё в свежей статье про навыки. В нашем случае веб-сервис навыка тоже был основан на .net core.
Пользователю должно быть комфортно взаимодействовать с навыком, как если бы он разговаривал со своим близким приятелем. Для этого, как минимум, необходимо поддерживать контекст разговора, понимать, о каком объекте говорит пользователь, и отвечать по теме. Если же пользователь отклоняется от цели диалога, нужно уметь вернуть его в нужное русло. И всё это должно происходить не дольше 3х секунд – именно столько времени платформа Яндекс-диалогов даёт навыку на ответ. Если ответ не будет получен за отведённое время – диалог прекратится, а пользователю скажут, что навык не отвечает, и в него вряд ли захотят вернуться снова.
Справиться с такой задачей можно при помощи различных сервисов, предназначенных для поддержания диалога с пользователем. У нас уже был кое-какой опыт работы с Dialogflow от Google, поэтому выбрали его. Как минимум, для него есть альтернатива из России – Aimylogic от JustAI, но с ним пока ещё не приходилось работать.
В нашем случае предполагается достаточно простой диалог: пользователь просит отправить ему билет, и если он сразу назвал свои ФИО – отправляем. Если нет – уточняем ФИО, и тогда уже отправляем.
Уточнение имени пользователя любой ценой
На наш взгляд, самое сложное в этой задаче – получить ФИО пользователя. Если они не будут названы, надо каким-то образом получить их от пользователя, и только после этого выполнить нужное действие. К счастью, DF (Dialogflow) позволяет делать такое «из коробки».
Для этого в намерении (Intent), в котором предполагается получение ФИО, нужно добавить тренировочные фразы, содержащие полное имя, и разметить их таким образом, чтобы эта информация попадала в соответствующий параметр намерения. Если ФИО будут распознаны, то параметр будет содержать это значение.
Размеченные тренировочные фразы
Параметры намерения
В противном случае надо получить эти параметры любой ценой. Для этого надо пометить параметр с ФИО как обязательный (галочка в колонке «Required»), и задать для него уточняющие фразы («Prompts»). Теперь, если нужно, в ответ DF будет отдавать именно их. А если ФИО распознаны – то обычные ответы для этого намерения, а также действие («Action»).
Уточняющие фразы
Обычные ответы
Дальше всё просто: если получено название действия и в ответе DF есть все необходимые параметры – выполняем это действие, и передаём ответ пользователю. Если же нет – отправляем текст уточнения.
Для отправки билетов навык должен выполнить запрос к бэкенду нашего портала с заголовком авторизации и ФИО пользователя в теле. По заголовку будет определена компания, а по ФИО легко найти нужного пользователя. В жизни заголовок может быть получен путём авторизации в навыке, но на хакатоне мы его просто «захардкодили», для экономии времени. С полным именем чуть сложнее.
Можно воспользоваться ФИО, распознанными в DF, но есть небольшая проблема: если пользователь назовёт себя не в именительном падеже, то и в параметре будет записано такое значение. На бэкенде имена пользователей записаны в нормальной форме (в именительном падеже), и несоответствие написания затруднит поиск.
И тут мы обратили внимание, что в запросе от Алисы приходят распознанные ФИО, нормализованные и записанные в отдельные поля!
Распознанное ФИО
К сожалению, NLU Яндекс-диалогов не очень хорошо справляется с более сложными именами, например Мамедов Полад Муртуза оглы, но для демонстрации на хакатоне подойдёт и этот вариант.
В итоге, получилась вот такая цепочка:
Диаграмма запросов
К концу хакатона у нас уже были готовы все три части нашего решения, которые мы и показали менторам. По их реакции сложно было сказать, нравится им наша разработка или нет, но, как мы позже узнали из личной беседы, демонстрация интеграции с Алисой однозначно оказала ожидаемый вау-эффект.
Во время работы также проходила техническая комиссия: каждая команда должна была предоставить доступы к своим репозиториям, и не реже одного раза в час делать в них «коммиты». Также к нам иногда приходили представители комиссии, обсуждали разрабатываемое решение. Кстати, их впечатление о хакатоне можете узнать вот здесь.
Победители
После выступлений приглашённых спикеров начались финальные питчи команд, победивших в той или иной задаче. В треке «Аэроэкспресс» выиграла команда «AeroTeam». Как позже нам рассказали менторы (они же — жюри), именно у этой команды была наиболее продуманная концепция дальнейшего развития решения, и ребята учли и проработали некоторые моменты, о которых даже сами заказчики не задумывались (к сожалению, не упомянули, какие именно). Нам же для победы не хватало некоторых деталей, который по-настоящему интересны менторам с точки зрения бизнеса. Они выбрали решение, которое достаточно проработано для того, чтобы начать его разработку «прямо сейчас», а значит были весьма объективны в своём решении, и это здорово.
Как мы потом узнали из беседы с участниками «AeroTeam», они собрались в команду достаточно сумбурно: узнали о хакатоне из совершенно разных источников, так или иначе попали в общий чат мероприятия, и там уже объединились. Всего в «AeroTeam» было три человека. В какой-то момент им предлагали ещё и UX-дизайнера, но они отказались, и вполне хорошо справились без этой роли. Никаких особых предпосылок к победе у ребят не было (например, в виде каких-то наработок), и им удалось проделать настолько мощную работу, которая, на мой взгляд, по праву заслужила победу.
Другая наша команда, к сожалению, тоже не выходила на сцену с питчем, а значит – не выиграла в своём треке, но эту историю мы расскажем в другой раз. А пока – кто же стал суперпобедителем хакатона? Эту номинацию отдали команде, которая, по мнению жюри, сделала самое лучше решение среди всех победителей в той или иной категории — «Голден ПСЖ». Они работали над задачей от смотровой площадки «Панорама 360». По заданию предполагалось, что посетители площадки будут фотографироваться на фоне «хромакея» (однотонного полотна), выбирать вместо него другой красочный фон, и сразу же печатать фотографию. Ребята же пошли дальше, и их решение позволяет удалять любой фон (а программно выполнить это гораздо сложнее, чем убирать одинаковый цвет) вокруг основного объекта (человека), и заменять его другим. На наш взгляд, это решение также достойно победы.
Сами участники – студенты бюджетного отделения ИТМО. Как ребята рассказали в личной беседе, они всё время были на площадке, ночью никуда не разъезжались, и «пахали» почти 26 часов из 30-ти (с перерывами, конечно же). У них уже был опыт участия в хакатонах, но приз забирают впервые.
Выводы
В первую очередь, стоит уделять больше времени реализации основного решения, чтобы жюри могли «потрогать» его, увидеть вживую на прототипе, а не на макетах и словах. Также стоит продумать дальнейшие перспективы развития проекта. При прочих равных, судьи могут отдать предпочтение решению, которое выполняет не только текущую задачу, но и сопутствующие цели заказчика.
Тем не менее, если есть возможность как-то выделиться — сделать красивый дизайн, или реализовать необычную идею, этим однозначно стоит воспользоваться. По опыту участия в других соревнованиях, это может помочь выиграть если не в основной, то хотя бы в дополнительной номинации — например, получить «приз зрительских симпатий», если такие предусмотрены. Или просто запомниться участникам и судьям необычным подходом.
До мероприятия стоит провести некоторые исследования бизнеса заказчика, чтобы лучше узнать его «боль» и придумать что-то для её устранения. Идеи и небольшие наработки не являются «готовым решением», так что правила хакатона не будут нарушены, и будет больше времени на самом соревновании.
Ещё не стоит полагаться на предоставление ресурсов со стороны заказчика, даже если это прописано в задаче. И вообще, к хакатону всегда следует хорошо готовиться: поднять минимально необходимую инфраструктуру, продумать публикацию проекта, исследовать API нужных сервисов, и тому подобное. Обязательно стоит предусмотреть решение такого вопроса, как собственный доступ в интернет, поскольку на большинстве подобных мероприятий с этим возникают трудности. Здесь, например, большую часть времени не было стабильного подключения. Ирония ещё заключается в том, что символом хакатона был оффлайновый динозавр, которого можно увидеть в Chrome, когда у вас нет интернета.
Хотелось бы отдельно отметить организацию хакатона: в целом, она была на высоте. Каждый этап проходил вовремя, на самой площадке тоже был полный порядок: еды хватало всем, закусок было много. На публичную часть во второй день, по идее, можно было прийти после предварительной регистрации, но, в итоге, туда мог попасть любой желающий. Небольшая вечеринка с музыкальной группой и фуршетом тоже удалась! Мы выражаем благодарность и уважением организаторам. Наша оценка – четыре зелёных динозавра из пяти – чтобы было к чему стремиться!
Таким был для нас Moscow travel hack: что-то в нашем решении было плохо, а что-то – хорошо. В любом случае, мы учтём свои ошибки и будем помнить их на следующем соревновании. Вообще, участвовать в хакатоне, особенно в команде коллег – это здорово! Для нас это был не только золотой опыт, но и лучший тимбилдинг. Мы очень круто сыгрались, творили безумные вещи без сна и отдыха. Убедились, что можем продуктивно работать над сложными задачами в сжатые сроки и в стрессовой ситуации. Главное — это наслаждаться процессом!
Если интересны технические детали реализации нашего решения — напишите в комментариях, с радостью расскажем.
Не прощаемся, увидимся на хабре!
Команда «Team 73», Аэроклуб ИТ
Автор: Степан