Como criar imagens de HTML para a criação dinâmica de rich card

Um dos tipos mais poderosos e versáteis de conteúdo no RCS Business Messaging é o rich card. Com um rich card, você pode enviar blocos de informações relacionadas em uma única mensagem, incluindo uma imagem ou vídeo, título, descrição e até quatro respostas ou ações sugeridas.

Rich cards independentes e carrosséis de rich card são recursos poderosos que podem ajudar a criar experiências envolventes para os usuários. Eles funcionam muito bem, desde que as imagens que você precisa compartilhar sejam estáticas, como cupons ou produtos. Mas o que acontece se você precisar enviar conteúdo dinâmico com base em informações sobre o usuário, como um cartão de embarque?

Neste artigo, mostrarei como criar imagens rapidamente com HTML e incorporá-las aos Rich Cards que seu agente envia. Vamos começar vendo como converter HTML em uma imagem.

Do HTML à imagem

O HTML é ótimo para dispor combinações de texto e mídia. Como desenvolvedores, se precisarmos criar um produto para enviar ao usuário algo como um cartão de embarque, um gráfico de uso de dados ou qualquer outro tipo de informação específica do usuário, o HTML gerado dinamicamente provavelmente será a ferramenta que usaremos. No RCS Business Messaging, os Rich Cards são compatíveis apenas com tipos de mídia de imagem e vídeo. Portanto, para aproveitar o poder do HTML na geração de conteúdo dinâmico, o HTML primeiro precisa ser convertido em uma imagem.

Felizmente, a maioria das linguagens de programação modernas é compatível com bibliotecas para fazer capturas de tela de páginas da Web ou componentes que podem renderizar pelo menos HTML básico (por exemplo, JEditorPane), que pode ser usado para gerar uma imagem.

Também há APIs disponíveis para tirar fotos de páginas da web. Por exemplo, a API Page Insights do Google pode gerar automaticamente capturas de tela de um URL.

Exemplos

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

A seguir, usamos um aplicativo Express do Node.js para gerar um cartão de embarque específico do usuário com HTML, convertê-lo em uma imagem, fazer o upload dele para um URL acessível publicamente e anexar a imagem a um card avançado para enviar ao usuário.

Como criar um cartão de embarque dinâmico

Para começar, precisamos do HTML para gerar um cartão de embarque, como a imagem abaixo.

Exemplo de cartão de embarque

Há muitas maneiras de fazer isso, mas vamos definir um endpoint de URL em um app Node.js chamado /getTicket?msisdn=+12223334444, que renderiza o HTML necessário para o cartão de embarque usando o mecanismo de visualização EJS.

Vamos supor que há uma função chamada getUserTicket que usa o número de telefone do usuário e retorna um objeto de ingresso com informações como horário de partida, assento, tipo de ingresso, local de partida etc.

No roteador do app Express, definimos o endpoint getTicket, chamamos a função getUserTicket e transmitimos o tíquete para o modelo 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});
});

O modelo EJS de tíquetes define o seguinte HTML para renderizar o exemplo de ingresso da 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>

Como criar uma imagem a partir do HTML

Definimos o HTML para construir o cartão de embarque, mas precisamos de uma maneira de convertê-lo em uma imagem.

Há muitos módulos Node.js de código aberto disponíveis para converter HTML e URLs brutos em imagens. Neste exemplo, usaremos o node-webshot, um wrapper leve em torno de PhantomJS.

O PhantomJS é um navegador headless scriptável que pode renderizar HTML em imagens. Como o PhantomJS depende do WebKit para renderização, ele pode lidar com páginas complexas com imagens, CSS e JavaScript.

Depois de instalar o webshot do nó (npm install --save node-webshot), a conversão do HTML em uma imagem é simples.

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
});

Como armazenar arquivos em um URL acessível ao público

Para usar a imagem gerada pela webshot, precisamos de um URL acessível publicamente. Se você estiver gerando a imagem em um servidor da Web dedicado, poderá salvar o arquivo em uma pasta pública. Neste exemplo, vamos fazer upload do arquivo no Google Cloud Storage.

A função abaixo recebe um local da imagem local e o envia para o Google Cloud Storage, retornando o link de mídia recém-criado.

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);
            });
    });
}

Em seguida, precisamos substituir o TODO comentado anteriormente por uma chamada para usar essa função 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
      });
});

Como enviar um rich card com a imagem

Estamos quase lá. Para concluir a etapa final, definimos a função sendBoardingPass(imageUrl, msisdn), que cria um rich card do RBM usando a imagem criada na etapa anterior e a envia ao usuário.

Para enviar o rich card com o RBM, uso o mesmo SDK do Node.js disponível na Amostra de primeiro agente (em inglês).

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);
}

Veja abaixo uma captura de tela do resultado final.

Imagem dinâmica em um rich card

Conclusão e TL;DR

A maneira mais simples de tornar os rich cards mais versáteis é usar o HTML dinâmico e converter o HTML em imagens. A maioria das linguagens de programação modernas é compatível com bibliotecas ou APIs que ajudam a concluir a conversão. Talvez você precise testar o dimensionamento da imagem para criar o visual certo para seu caso de uso, mas é uma abordagem fantástica para criar recursos visuais mais atraentes nos seus agentes do RBM.

Boa sorte e uma boa codificação!