Cómo crear imágenes a partir de HTML para la creación dinámica de tarjetas enriquecidas

Uno de los tipos de contenido más potentes y versátiles en RCS Business Messaging es la tarjeta enriquecida. Con una tarjeta enriquecida, puedes enviar fragmentos de información relacionada en un solo mensaje, incluidos una imagen o un video, un título, una descripción y hasta cuatro respuestas o acciones sugeridas.

Las tarjetas enriquecidas independientes y los carruseles de tarjetas son funciones potentes que pueden ayudarlo a crear experiencias atractivas para los usuarios. Funcionan muy bien, siempre y cuando las imágenes que compartas sean estáticas, como un cupón o un producto. Pero ¿qué sucede si necesitas enviar contenido dinámico basado en información sobre el usuario, como una tarjeta de embarque?

En este artículo, te mostraré cómo crear imágenes sobre la marcha con HTML y cómo incorporarlas en las tarjetas enriquecidas que envía tu agente. Para comenzar, veamos cómo convertir HTML en imágenes.

De HTML a imagen

El HTML es ideal para distribuir combinaciones de texto y medios. Como desarrollador, si necesitamos crear un producto para enviar a un usuario algo como una tarjeta de embarque, un gráfico de uso de datos o cualquier otro tipo de información específica del usuario, es probable que la herramienta que usemos sea el HTML generado de forma dinámica. En RCS Business Messaging, las tarjetas enriquecidas solo admiten tipos de medios de imagen y video, por lo que, a fin de aprovechar el poder del HTML para generar contenido dinámico, primero es necesario convertir ese código en una imagen.

Afortunadamente, la mayoría de los lenguajes de programación modernos admiten bibliotecas para tomar capturas de pantalla de páginas web o componentes que pueden renderizar al menos el HTML básico (p.ej., JEditorPane), que puedes usar para generar una imagen.

También hay API disponibles para tomar fotos de páginas web. Por ejemplo, la API de estadísticas de páginas de Google puede generar automáticamente capturas de pantalla a partir de una URL.

Ejemplo:

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

En la siguiente sección, usamos una app Express de Node.js para generar una tarjeta de embarque específica de un usuario con HTML, convertirla en una imagen, subirla a una URL de acceso público y, luego, adjuntarla a una tarjeta enriquecida para enviarla a un usuario.

Cómo crear una tarjeta de embarque dinámica

Para comenzar, necesitamos el código HTML a fin de generar una tarjeta de embarque, como se muestra en la siguiente imagen.

Muestra de tarjeta de embarque

Existen muchas formas de lograrlo, pero vamos a definir un extremo de URL en una app de Node.js llamada /getTicket?msisdn=+12223334444, que renderiza el HTML que necesitamos para la tarjeta de embarque con el motor de vista EJS.

Supongamos que hay una función llamada getUserTicket que toma el número de teléfono del usuario y muestra un objeto de ticket que contiene información como la hora de salida, el asiento, el tipo de boleto, la ubicación inicial, etcétera.

Dentro del router de la app de Express, definimos el extremo getTicket, llamamos a la función getUserTicket y pasamos el ticket a la plantilla 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});
});

La plantilla EJS del ticket define el siguiente código HTML para procesar el ejemplo de ticket de 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>

Cómo crear una imagen a partir de HTML

Definimos el código HTML para construir la tarjeta de embarque, pero necesitamos una forma de convertirlo en una imagen.

Hay muchos módulos de código abierto de Node.js disponibles para convertir HTML y URL sin procesar en imágenes. Para los fines de este ejemplo, usaremos node-webshot, que es un wrapper liviano alrededor de PhantomJS.

PhantomJS es un navegador sin interfaz gráfica con secuencias de comandos que puede renderizar HTML en imágenes. Dado que PhantomJS depende de WebKit para el procesamiento, puede controlar páginas complejas con imágenes, CSS y JavaScript.

Después de instalar el nodo webshot (npm install --save node-webshot), la conversión de HTML a una imagen es sencilla.

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

Almacenar archivos en una URL de acceso público

Para usar la imagen generada por Webshot, necesitamos una URL de acceso público. Si va a generar la imagen en un servidor web dedicado, tal vez pueda simplemente guardar el archivo en una carpeta pública, pero en este ejemplo, vamos a subir el archivo a Google Cloud Storage.

La siguiente función toma una ubicación de imagen local y la sube a Google Cloud Storage para mostrar el vínculo multimedia que acaba de crear.

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

A continuación, debemos reemplazar el TODO comentado antes por una llamada para usar esta función 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
      });
});

Envío de una tarjeta enriquecida con la imagen

Ya casi terminamos. Completemos el paso final definiendo la función sendBoardingPass(imageUrl, msisdn), que crea una tarjeta enriquecida de RBM con la imagen creada en el paso anterior y la envía al usuario.

Para enviar la tarjeta enriquecida con RBM, uso el mismo SDK de Node.js disponible en la muestra del primer agente.

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

A continuación, se muestra una captura de pantalla del resultado final.

Imagen dinámica en una tarjeta enriquecida

Conclusión y resumen

La forma más simple de lograr que las tarjetas enriquecidas sean más versátiles es aprovechar el HTML dinámico y convertirlo en imágenes. La mayoría de los lenguajes de programación modernos admiten bibliotecas o APIs que te ayudarán a completar la conversión. Es posible que deba probar el tamaño de la imagen a fin de que todo se vea bien para su caso de uso, pero es un enfoque fantástico para crear imágenes más atractivas dentro de sus agentes de RBM.

¡Buena suerte y buena programación!