Конечно, идея не новая, на инфостарте есть несколько статей про работу со сторонними сервисами по распознаванию лиц. Некоторые из данных статей написаны еще в 2017 году (распознавание лиц с тех пор значительно развилось). Тем не менее, надеюсь кому-то будет полезно.
В общем, на досуге пишу платформу по работе с видео потоком и обработкой результатов, платформа еще сыровата, но что-то (например, узнавание лиц из базы) работает вполне себе приемлемо. И родилась тут мысль, интегрировать платформу с 1С. А именно, написать «на коленке» такой механизм, который будет вместо карты лояльности покупателя считывать его лицо и исходя из этого рассчитывать скидку. Кстати «на коленке» пишу специально (чтобы сильно не ругали за кривую архитектуру и реализацию на стороне 1С). Ведь в данном случае цель – проверить гипотезу.
А гипотеза выглядит так:
Покупатель стоит у кассы, его лицо находится в объективе камеры. Камера каждые несколько секунд улавливает его лицо, распознает через нейросеть, и результаты распознавания записываются в БД событий. Далее, кассир вместо привычного:
- У Вас есть карта нашего магазина? Нет? Желаете оформить?
Просто нажимает кнопку «Проверить покупателя», и последнее событие из базы проверяется на наличие у него карты лояльности (виртуальной конечно же). Если таковая есть, 1С учитывает скидки.
Сейчас комплекс выглядит следующим образом:
Платформа работает с изображением с камеры, распознает лица, кидает изображение в нейросеть, получает ответ и записывает результаты в БД MySQL. К демонстрационной базе 1С: Управление торговлей 11.4 требуется реализовать получение данных событий (та самая MySQL база в которой фиксируются результаты с камеры).
Для того, чтобы это заработало, требуется:
- Добавить получение событий из БД событий в 1С: УТ.
- Добавить в 1С: УТ признак опознанного пользователя.
- Добавить в 1С: УТ процедуру которая будет проверять наличие виртуальной карты лояльности у покупателя.
Итак, начнем с первого пункта.
Правильно было бы написать веб-сервис при обращении, к которому в 1С «прилетали» данные события. Но поскольку «на коленке» то будем подключить базу MySQL в качестве внешнего источника данных. Интересно, как это будет работать если в таблице записей больше чем хотя-бы 100 тысяч? Есть у кого опыт работы с большими таблицами во внешних источниках? Расскажите, как оно. Кроме тех случаев, когда внешние источники используются для разовой загрузки данных в 1С.
Подключить внешний источник данных в 1С дело нехитрое. Для подключения используется коннектор ODBC
Процедура подключения абсолютно тривиальна, поэтому рассказывать о ней отдельно, смысла нет. Проверим что в режиме 1С: Предприятия таблицы с данными доступны.
Есть контакт, таблицы доступны, ошибок не выявлено.
Поскольку, делать персональные карты лояльности, для программы которая работает по распознаванию лица было-бы как-то не логично, правильнее использовать для этого справочник «Виды карт лояльности». Для этого, добавляю в данный справочник новую табличную часть «Ники владельцев». В данной табличной части есть всего один реквизит «Ник владельца» с типом строка. Как нетрудно догадаться, в данную табличную часть будут заполняться наименования пользователей в том виде, в котором они содержатся в БД событий.
Указываем, что код состоит из двух символов. Теперь в системе есть не персонализированная карта лояльности, у которой может быть множество держателей, со скидкой 20% на всё. Данной виртуальной карте присвоен код 18.
Сразу добавлю себя в табличную часть «Ники владельцев». В базе лиц я числюсь как пользователь с ником Kirill. Добавляю данный ник в таблицу.
Теперь интереснее. На фронте кассира, на форме считывания карты, добавляем кнопку «Считать покупателя» и процедуру для нее.
Приступаем писать процедуру проверки. Как вдруг сталкиваемся вот с этой болью:
Да, я знаю, что эту «боль» можно преодолеть используя таблицу значений, но поскольку пишем «на коленке» то просто добавим регистр сведений в который каждый раз при выполнении процедуры будет записываться последнее событие (а все остальные при этом удаляться, итого в базе не может быть более одной записи в данном регистре). Состав регистра при этом состоит всего из двух измерений (id, user) по аналогии с названиями колонок в MySQL. В данном случае id это порядковый номер события за день, то есть чем больше ID тем актуальнее событие. В случае если события записываются в одно и тоже время с точностью до секунды, то ID лучший вариант определения последнего.
В итоге, перед началом проверки наличия виртуальной карты у покупателя, обновляем в регистре сведений последнее событие, и далее работаем по нему. А после этого, проверяем по данному покупателю наличие у него бонусов. В конце, заполняем из запроса значение в реквизит «код карты» (если есть чем заполнить)
Код процедуры получился следующий:
&НаСервере
Процедура СчитатьПокупателяНаСервере()
Запрос1 = Новый Запрос();
Запрос1.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| events.id КАК id,
| events.user КАК user
|ИЗ
| ВнешнийИсточникДанных.Faces.Таблица.events КАК events
|
|УПОРЯДОЧИТЬ ПО
| id УБЫВ" ;
Результат = Запрос1.Выполнить();
Выборка = Запрос1.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
МенеджерЗаписи = РегистрыСведений.АктуальноеЛицо.СоздатьНаборЗаписей();
ТекущийПокупатель = МенеджерЗаписи.Добавить();
ТекущийПокупатель.ID = Выборка.id;
ТекущийПокупатель.User = Выборка.user;
МенеджерЗаписи.Записать();
КонецЦикла;
Запрос2 = Новый Запрос();
Запрос2.Текст =
"ВЫБРАТЬ
| АктуальноеЛицо.User КАК User,
| ВидыКартЛояльностиВладеющиеКартой.НикВладельца КАК НикВладельца,
| ВидыКартЛояльностиВладеющиеКартой.Ссылка КАК Ссылка,
| Карты.Штрихкод КАК Штрихкод
|ИЗ
| РегистрСведений.АктуальноеЛицо КАК АктуальноеЛицо
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ВидыКартЛояльности.ВладеющиеКартой КАК ВидыКартЛояльностиВладеющиеКартой
| ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
| КартыЛояльности.Штрихкод КАК Штрихкод,
| КартыЛояльности.Владелец КАК Владелец
| ИЗ
| Справочник.КартыЛояльности КАК КартыЛояльности
| ГДЕ
| КартыЛояльности.Владелец.Наименование ПОДОБНО ""Лицо"") КАК Карты
| ПО ВидыКартЛояльностиВладеющиеКартой.Ссылка.Ссылка = Карты.Владелец.Ссылка
| ПО АктуальноеЛицо.User = ВидыКартЛояльностиВладеющиеКартой.НикВладельца";
Результат2 = Запрос2.Выполнить();
Выборка2 = Запрос2.Выполнить().Выбрать();
Пока Выборка2.Следующий() Цикл
ЭтаФорма.КодКарты = Выборка2.Штрихкод;
КонецЦикла;
Сообщение = Новый СообщениеПользователю();
Если ЭтаФорма.КодКарты = NULL Тогда
Сообщение.Текст = "Покупатель не опознан"
Иначе Сообщение.Текст = "Обпознан покупатель с ником" + Выборка2.user;
КонецЕсли
КонецПроцедуры
Ошибок нет, пробуем в режиме предприятия.
Платформа распознавания лиц в это время работает примерно так:
То есть каждые несколько секунд «узнает» лицо в кадре и пишет в базу событий и записывает в базу результаты. А еще утверждает, что покупатель «чёт приуныл».
Запускаем фронт кассира, добавляем в покупки двух «белочек» (просто для данной номенклатуры настроены цены в демонстрационной базе).
Нажимаем «Считать карту» и новую кнопку «Считать покупателя»
It works! При нажатии код карты определился как «18» (тот самый код который присвоился карте). Нажимаем «Готово» и «Рассчитать скидки» на фронте кассира.
Скидка на «белочек» учитана. ЧИТД.
Выводы:
В целом, все это максимально просто с точки зрения реализации, поэтому сомнений что идея «взлетит» не было. Опасения вызывала скорость работы 1С с внешними источниками, то есть что пока он получит данные, в базе создастся еще несколько событий и то что получит 1С будет уже не актуальным. Но по-факту запрос 1С вытащил актуальное событие из БД MySQL.
Как это можно использовать еще? На скриншотах видно, что помимо «узнавания» система также пытается определить пол, возраст и эмоции человека. Исходя из этого кассир также может попытаться определить возраст. Это актуально в случаях если на продукцию стоит ограничение 18+. Конечно есть вероятность того что система неправильно определит человека. Но можно усложнить логику - в зависимости от уровня соответствия человека в объективе тому что в базе. Если уровень соответствия не высок, но система определяет что это «именно тот покупатель» то можно задавать вопрос кассиру – учитывать ему скидку или нет? Но это размышления из серии – «а что, если»?
Работа с распознаванием осуществляется на стороне другой системы, а 1С только получает данные из базы. Лично я думаю, что это наиболее правильный вариант работы, поскольку типовые 1С и без того сильно перегружены функционалом, да и чем меньше изменений в типовой конфигурации, тем проще ее администрировать. А хранить в базе 1С еще дополнительные данные о покупателях (даже обезличенные) тоже неоднозначный вопрос особенно учитывая, что счет может вестись на много-много тысяч записей.
Насколько подобное решение может быть эффективно для бизнеса? Не важно, мы же кодеры)). Лучики добра всем в лапки!