Как создавать изображения из HTML для динамического создания расширенных карт

Одним из самых мощных и универсальных типов контента в RCS Business Messaging является расширенная карточка . С расширенной карточкой вы можете отправлять фрагменты связанной информации в одном сообщении, включая изображение или видео, заголовок, описание и до четырех предлагаемых ответов или действий.

Отдельные расширенные карточки и карусели с расширенными карточками — это мощные функции, которые помогут вам создавать привлекательные впечатления для пользователей. Они отлично работают, если изображения, которыми вы хотите поделиться, являются статическими изображениями, такими как купон или продукт. Но что произойдет, если вам нужно отправить динамический контент на основе информации о пользователе, например, посадочный талон?

В этой статье я покажу вам, как создавать изображения на лету с помощью HTML и вставлять эти изображения в расширенные карточки, которые отправляет ваш агент. Начнем с того, как преобразовать HTML в изображение.

От HTML к изображению

HTML отлично подходит для размещения комбинаций текста и мультимедиа. Как разработчикам, если нам нужно создать продукт для отправки пользователю чего-то вроде посадочного талона, диаграммы использования данных или любого другого типа пользовательской информации, мы, вероятно, будем использовать динамически генерируемый HTML. В RCS Business Messaging расширенные карточки поддерживают только типы мультимедиа изображений и видео, поэтому, чтобы использовать возможности HTML для создания динамического контента, HTML сначала необходимо преобразовать в изображение.

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

Также доступны API для фотографирования веб-страниц. Например, Google Page Insights API может автоматически генерировать скриншоты из URL-адреса.

Пример:

https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=https://www.google.com&screenshot=true

Далее мы используем экспресс-приложение Node.js для создания пользовательского посадочного талона с помощью HTML, конвертируем его в изображение, загружаем на общедоступный URL-адрес, а затем прикрепляем изображение к расширенной карточке для отправки на пользователь.

Создание динамического посадочного талона

Для начала нам нужен HTML для создания посадочного талона, как на изображении ниже.

Образец посадочного талона

Есть много способов сделать это, но мы собираемся определить конечную точку URL-адреса в приложении Node.js с именем /getTicket?msisdn=+12223334444 , которое отображает HTML-код, необходимый для посадочного талона, с помощью механизма просмотра EJS.

Предположим, что есть функция getUserTicket , которая берет номер телефона пользователя и возвращает объект билета, который содержит такую ​​информацию, как время отправления, место, тип билета, место отправления и т. д.

В маршрутизаторе экспресс-приложения мы определяем конечную точку getTicket , вызываем функцию getUserTicket и передаем билет шаблону EJS.

router.get('/getTicket', function(req, res, next) {
    // Get the passed in phone number
    let msisdn = req.body.msisdn;

    // Get the ticket object for this user
    let ticket = getUserTicket(msisdn);

    // Render the ticket in HTML using an EJS template
    res.render('ticket', {ticket: ticket});
});

EJS-шаблон билета определяет следующий HTML-код для отображения образца билета Bonjour Rail.

<div>
  <div>
    <div class="left"><img width="200" src="/images/bonjour-rail-logo.png" /></div>
    <div class="right muted-text"><%= ticket.dateOfDeparture; %></div>
    <div class="cl"></div>
  </div>
  <div>
    <div class="left highlighted-text-color"><h2><%= ticket.startingLocation.city %></h2><br/><%= ticket.startingLocation.station %></div>
    <div class="right highlighted-text-color"><h2><%= ticket.endingLocation.city %></h2><br/><%= ticket.endingLocation.station %></div>
    <div class="cl"></div>
  </div>

  <div>
    <div class="left">
        <h3>PLATFORM <%= ticket.platform %></h3>
      <div>
        <div class="left">
          <div><h4>DEPART</h4></div>
          <div><%= ticket.departureTime %></div>
        </div>
        <div class="left">
          <div><h4>ARRIVE</h4></div>
          <div><%= ticket.arrivalTime %></div>
        </div>
        <div class="cl"></div>
      </div>
      <div>
        <div class="left">
          <div><h4>TICKET TYPE</h4></div>
          <div><%= ticket.ticketType %></div>
        </div>
        <div class="left">
          <div><h4>SEAT</h4></div>
          <div><%= ticket.seat %></div>
        </div>
        <div class="cl"></div>
      </div>
    </div>
    <div class="right">
      <img src="<%= ticket.qrCode %>" width="170" />
    </div>
    <div class="cl"></div>
  </div>
</div>

Создание изображения из HTML

Мы определили HTML для создания посадочного талона, но нам нужен способ преобразовать его в изображение.

Существует множество модулей Node.js с открытым исходным кодом для преобразования необработанного HTML и URL-адресов в изображения. В этом примере мы будем использовать node-webshot , который является легкой оболочкой для PhantomJS .

PhantomJS — это безголовый браузер с поддержкой сценариев, который может отображать HTML в изображения. Поскольку PhantomJS полагается на WebKit для рендеринга, он может обрабатывать сложные страницы с изображениями, CSS и JavaScript.

После установки узла webshot ( npm install --save node-webshot ) преобразование HTML в изображение становится простым.

var webshot = require('node-webshot');
let url = '/getTicket?msisdn=' + msisdn;
let htmlAsImageFileLocation = 'ticket.png';

// Define screenshot options
var options = {
      screenSize: {
            width: 550,
            height: 450
      },
      shotSize: {
            width: 550,
            height: 450
      },
      userAgent: 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.20 (KHTML, like Gecko) Mobile/7B298g'
    };

// Save html as an image
webshot(url, htmlAsImageFileLocation, options, function(err) {
  // TODO: Upload image to a publicly accessible URL
});

Хранение файлов по общедоступному URL-адресу

Чтобы использовать изображение, сгенерированное webshot, нам нужен общедоступный URL-адрес. Если вы создаете изображение на выделенном веб-сервере, вы можете просто сохранить файл в общедоступной папке, но в этом примере мы собираемся загрузить файл в Google Cloud Storage .

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

function uploadImage(imageLocation) {
    const {Storage} = require('@google-cloud/storage');

    // Creates a client
    const storage = new Storage();

    // Define the Cloud storage location and file name
    const bucketName = 'sample-image-uploads';
    const yourFileDestination = 'uploaded-image.png';

    // Set the options for the upload to be readable by anyone
    const options = {
        destination: yourFileDestination,
        predefinedAcl: 'publicRead'
    };

    // Return a promise that includes the storage upload
    return new Promise(function(resolve, reject) {
        // Uploads a local file to the bucket
        storage.bucket(bucketName).upload(imageLocation, options)
            .then(results => {
                // Return the image URL
                resolve(results[0].metadata.mediaLink);
            }).catch(error => {
                reject(error);
            });
    });
}

Затем нам нужно заменить закомментированный TODO вызовом для использования этой функции uploadImage .

// Save html as image
webshot(url, htmlAsImageFileLocation, options, function(err) {
      let uploadRequest = uploadImage(filename);

      uploadRequest.then(function(imageUrl) {
         // TODO: Use the imageUrl in a rich card to send to the user
      });
});

Отправка расширенной карты с изображением

Мы почти у цели. Давайте завершим последний шаг, определив функцию sendBoardingPass(imageUrl, msisdn) , которая создает расширенную карточку RBM с использованием изображения, созданного на предыдущем шаге, и отправляет ее пользователю.

Чтобы отправить расширенную карту с RBM, я использую тот же SDK Node.js, доступный в примере первого агента .

function sendBoardingPass(imageUrl, msisdn) {
    let title = 'Here is your boarding pass.';

    let suggestions = [
                {
                    reply: {
                        text: 'See more options',
                        postbackData: 'more_options',
                    }
                },
            ];

    let params = {
        messageText: title,
        msisdn: msisdn,
        imageUrl: imageUrl,
        suggestions: suggestions,
        height: 'TALL',
    };

    // Send the boarding pass
    rbmApiHelper.sendRichCard(params);
}

Ниже скриншот конечного результата.

Динамическое изображение в расширенной карточке

Подведение итогов и TL;DR

Самый простой способ сделать расширенные карты более универсальными — использовать динамический HTML и преобразовать HTML в изображения. Большинство современных языков программирования поддерживают библиотеки или API, которые помогут вам выполнить преобразование. Возможно, вам придется поиграть с размером изображения, чтобы все выглядело правильно для вашего варианта использования, но это фантастический подход к созданию более привлекательных визуальных эффектов в ваших агентах RBM.

Удачи и счастливого кодирования!