Мы в Smart Engines занимаемся системами распознавания документов и в особенности много понимаем про распознавание документов, удостоверяющих личность. Систему мы поставляем в виде SDK - набора библиотек и программных интерфейсов, позволяющих на стороне заказчика внедрить функциональность распознавания в свою инфраструктуру.

Вообще мы, скорее, приверженцы нативной интеграции. Библиотеки всех наших продуктов разрабатываются изначально на C/C++ и их основной интерфейс, включающий в себя наиболее полный набор функциональности, всегда на C++. Мы к этому привыкли, и поэтому, когда возникает необходимость создать какой-то простой пример интеграции, рефлекторно хочется просто написать короткую программу на C++ (можно заметить это, например, в том как мы описывали создание простого DOCX-шаблонизатора). Наши клиенты используют набор предоставляемых нами оберток, чтобы более просто интегрироваться со своими системами: главным образом это автоматически сгенерированные при помощи SWIG обертки для Java, C#, Python и PHP.

Однако интеграция системы распознавания документов как нативной библиотеки с прямым программным вызовом – не всегда самый оптимальный путь, сразу по нескольким причинам:

  • Во-первых, для решения простых задач, таких как банальное извлечение ФИО из файла со сканом паспорта на десктопах точек обслуживания клиентов, хочется использовать максимально простую интеграцию. О том, что такие простые задачи часто возникают говорит, например, то, что некоторые клиенты просили нас предоставить простое консольное приложение или службу, которая бы “следила” за директорией и при появлении нового файла с изображением документа в этой директории проводила бы распознавание и заносила результат в некоторую таблицу.

  • Во-вторых, иногда в рамках одной информационной системы (или в рамках одного автоматизированного рабочего места) функциональностью распознавания документов (одних и тех же или разных) нужно пользоваться сразу в нескольких приложениях, и, соответственно, возникает желание организовать доступ к системе распознавания как к некоторой локальной службе.

  • В-третьих, в более сложных случаях простота интерфейса интеграции позволяет легко проводить прототипирование для того, чтобы отработать изменение бизнес-процессов, неизбежное при автоматизации.

Все это привело нас к тому, чтобы сделать вариант взаимодействия пользователя с системой распознавания как с простой локальной REST службой.

Описание API службы

API REST-службы системы распознавания документов, удостоверяющих личность, Smart ID Engine, устроен максимально просто. Он обладает тремя группами методов:

1. Служебные и информационные методы:

  • (GET) /doc - документация службы в виде HTML (Swagger)

  • (GET) /help - документация службы в виде JSON (OpenAPI)

  • (GET) /diagnostics - информация о статусе службы в виде JSON

  • (GET) /version - информация о версии Smart ID Engine

2. Простое распознавания одного изображения:

  • (POST) /api/recognize/simple : производит распознавания заданного в теле запроса изображения (допускаются изображения JPG и PNG, а также одноканальный или RGB-буфер 8-битных пикселей, закодированный в base64)

В качестве параметров метода распознавания обязательно задать режим распознавания mode (по умолчанию default, но в зависимости от поставки могут быть доступны режимы автоматического выбора типа документа - anypassport (паспорт любой страны), anydoc (любой идентификационный документ любой страны), anyrus (любой документ РФ) и т.п.) и маску типов документа mask (например, rus.passport.national для распознавания паспорта РФ, или звездочку * для включения всех документов в рамках текущего режима).

Также есть ряд необязательных булевых параметров, влияющих на то, какая информация будет упаковываться в JSON с результатами распознавания документа (например, флаг get_img_fields регулирует возврат графических полей, флаг get_field_attr регулирует возврат дополнительных атрибутов реквизитов и т.п.).

Результатом вызова будет являться JSON-объект с результатами распознавания документа. К примеру, в таком виде приходит ответ при распознавании тестового изображения паспорта РФ в режиме, когда требуются только результаты распознавания текстовых полей:

{
  "response": {
    "recog_res": {
  	  "props": {
        "authority": {
      	  "confidence": 0.9933671355247498,
      	  "is_rejected": false,
      	  "value": "ОТДЕЛОМ ВНУТРЕННИХ ДЕЛ ОКТЯБРЬСКОГО ОКРУГА ГОРОДА АРХАНГЕЛЬСКА"
    	},
    	"authority_code": {
      	  "confidence": 0.9970306158065796,
      	  "is_rejected": false,
      	  "value": "292-000"
    	},

    	// ... часть полей скрыта для краткости ...

    	"name": {
      	  "confidence": 0.999942421913147,
      	  "is_rejected": false,
      	  "value": "ЕВГЕНИЙ"
    	},
    	"patronymic": {
      	  "confidence": 0.9998761415481567,
      	  "is_rejected": false,
      	  "value": "АЛЕКСАНДРОВИЧ"
    	},
    	"surname": {
      	  "confidence": 0.9999336004257202,
      	  "is_rejected": false,
      	  "value": "ИМЯРЕК"
    	}
  	  },
  	  "type": "rus.passport.national"
	}
  },
  "status": "ok"
}

3. Методы, связанные с сессионным распознаванием.

Сессионное распознавание - это механизм, позволяющий распознавать документы, представленным несколькими изображениями. В случае, если распознаваемый документ содержит несколько шаблонов, находящихся на разных изображениях (к примеру, раздельное сканирование лицевой и обратной стороны ID-карты), механизм сессий позволяет распознать каждый из шаблонов и свести их в единый результат распознавания документа. А в случае, если мы располагаем несколькими разными изображениями одного и того же документа (к примеру, если мы попросили пользователя сфотографировать документ несколько раз, или если у нас есть несколько кадров видеопоследовательности) - то сессионное распознавание позволяет нам улучшить качество распознавания за счет межкадрового комбинирования.

В этой группе есть методы:

  • (POST) /api/recognize/session/start - создает новую сессию распознавания, принимает обязательные параметры mode и mask, с тем же смыслом, что и /api/recognize/simple, и возвращает JSON с идентификатором сессии

  • (GET) /api/recognize/session/list позволяет получить список всех активных сессий

  • (POST) /api/recognize/session/{id} - в рамках сессии с заданным идентификатором распознает заданное (также как и в /api/recognize/simple) в теле запроса изображение и возвращает текущий накопленный результат сессии. Принимает такой же набор модификаторов вывода, как и /api/recognize/simple.

  • (POST) /api/recognize/session/{id}/stop - останавливает и удаляет сессию с заданным идентификатором

  • (POST) /api/recognize/session/{id}/reset - возвращает сессию с заданным идентификатором в начальное состояние (которое было на момент ее создания)

  • (GET) /api/recognize/session/{id}/result - возвращает результат распознавания сессии с заданным идентификатором. Принимает такой же набор модификаторов вывода, как и /api/recognize/simple.

Пример использования

Рассмотрим такой простой пример использования: нужно сделать локальную HTML-страничку, на которую можно перетащить файл с фотографией или сканом паспорта, чтобы программа прочитала ФИО, отобразила его на этой же странице, так, чтобы пользователь мог его скопировать. Такой “игрушечный” кейс хорошо демонстрирует возможность интеграции с локальной REST-службой.

Для начала установим и запустим саму службу. Тест производим на машине с Arch Linux, для линуксов REST-служба Smart ID Engine поставляется в виде systemd-демона. После того, как мы распаковали архив и выполнили скрипт install.sh, у нас доступна служба idengine_rest_daemon:

$ sudo systemctl status idengine_rest_daemon
● idengine_rest_daemon.service - idengine rest api daemon
  Loaded: loaded (/etc/systemd/system/idengine_rest_daemon.service; enabled; preset: disabled)
  Active: active (running) since Fri 2024-04-26 09:37:51 +04; 6s ago
Main PID: 1482719 (idengine_rest)
   Tasks: 9 (limit: 77030)
  Memory: 29.3M (peak: 30.8M)
     CPU: 22ms
  CGroup: /system.slice/idengine_rest_daemon.service
          └─1482719 /home/user/install-directory/idengine_rest ...

Apr 26 09:37:51 hostname systemd[1]: Started idengine rest api daemon.
Apr 26 09:37:51 hostname idengine_rest[1482719]: Version: 2.3.0
Apr 26 09:37:51 hostname idengine_rest[1482719]: Bundle path: /home/user/install-directory/...

По умолчанию служба слушает 8082-й порт (разумеется, эти настройки можно поменять в конфигурационном файле службы перед ее запуском). Проверяем, что служба работает:

$ curl localhost:8082/version
{"response":{"drogon_version":"1.8.4","idengine_version":"2.3.0"},"status":"ok"}⏎	

Выводятся версии движка распознавания Smart ID Engine, а также версия библиотеки drogon - понравившейся нам С++-библиотеки, которая используется внутри бинарника для оборачивания нашего движка в вид REST-службы.

Теперь, собственно, можно перейти к созданию самой HTML-страничку. Пусть drag-n-drop цель, при обработке события drop, достает файл из события и вызывает функцию processFile(file):

processFile = async(file) => {
  // Проверяем расширение файла и запоминаем Content-Type для файлов изображений
  content_type = null

  if (file.name.toLowerCase().endsWith("jpg") ||
  	file.name.toLowerCase().endsWith("jpeg")) {
	content_type = "image/jpeg"
  } else if (file.name.toLowerCase().endsWith("png")) {
	content_type = "image/png"
  } else {
	displayError("Можно только JPG/JPEG и PNG")
	return
  }

  // Отображаем индикатор того, что мы начали работу
  displayThinking();

  // Создаем запрос на распознавание изображения в умолчательном режиме,
  // с поддержкой всех доступных типов документов и с возвратом текстовых полей
  const response = await fetch('http://localhost:8082/api/recognize/simple?mode=default&mask=*&get_text_fields=true', {
	method: "POST",
	headers: {
  	  "accept": "application/json",
  	  "Content-Type": content_type
	},
	"body": file
  });

  // Ожидаем выполнения запроса
  const responseJson = await response.json();

  // Отображаем результат распознавания либо ошибку
  if (responseJson.status == "ok") {
	displayResult(responseJson.response);
  } else {
	displayError("Ошибка обработки картинки");
  }
}

Собственно… все. Все остальные функции относятся напрямую к верстке и к отображению тех или иных строк в HTML-элементах страницы. Если добавить к этому коду верстку, то получится вот такая страничка:

Вместо заключения

Описанный вариант интеграции продукта Smart ID Engine предназначен для использования именно как локальной службы (в рамках одной системы). Тут мы остаемся верными своим принципам преимущества нативной интеграции. REST API как способ общения с системой распознавания имеет преимущества простоты взаимодействия, однако нужно помнить про то, что при работе с чувствительными документами необходимо каждый раз думать о том, как максимально обезопасить данные. Именно поэтому мы продолжаем производить именно библиотеки и системы распознавания, и не собираемся делать сервис распознавания, принимающий и передающий данные документов по каким-либо каналам связи.

Безопасность данных мы считаем, пожалуй, самым важным аспектом работы с документами, удостоверяющими личность, и призываем всех строить свои решения так, чтобы минимизировать любые риски, связанные с передачей изображений или результатов распознавания куда-либо. Но в случае, если требуется реализовать удобную и эффективную обработку изображений документов в локальном контуре (например, на десктопе в пункте обслуживания клиентов) - REST API может оказаться оптимальным способом встроить наш продукт.

Спасибо за внимание!

Комментарии (0)