動的なリッチカードを作成するための HTML から画像を作成する方法

RCS ビジネス メッセージで最もパワフルで汎用性の高いコンテンツとして、リッチカードがあります。リッチカードを使用すると、画像や動画、タイトル、説明に加え、返信やアクションの候補を 4 つまで提案できます。

スタンドアロンのリッチカードとリッチカード カルーセルは、ユーザーに魅力的なエクスペリエンスを提供するのに役立つ強力な機能です。共有する必要がある画像は、クーポンや商品などの静止画像で構いません。しかし、搭乗券など、ユーザーに関する情報に基づく動的コンテンツを送信する必要がある場合はどうでしょうか。

この記事では、HTML を使って臨機応変に画像を作成し、エージェントから送信されるリッチカードにそれらの画像を埋め込む方法について説明します。まず、HTML を画像に変換する方法から見ていきましょう。

HTML から画像へ

HTML は、テキストとメディアの組み合わせをレイアウトするのに最適です。デベロッパーとして、搭乗券、データ使用量のグラフ、その他のユーザー固有の情報などを送信するために商品を作成する必要がある場合は、おそらく動的に生成される HTML を使用します。RCS ビジネス メッセージでは、リッチカードは画像と動画のメディアタイプのみをサポートします。そのため、動的コンテンツ生成に 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 Express アプリを使用して HTML でユーザー固有の搭乗券を生成し、それを画像に変換して一般公開されている URL にアップロードし、リッチカード内で画像を添付してユーザーに送信します。

動的な搭乗券の作成

まず、HTML を使用して、次の画像のような搭乗券を生成します。

搭乗券のサンプル

方法は多数ありますが、ここでは、EJS ビューエンジンを使用して搭乗券に必要な HTML をレンダリングする、/getTicket?msisdn=+12223334444 という Node.js アプリで URL エンドポイントを定義します。

ユーザーの電話番号を受け取り、出発時刻、座席、チケットタイプ、開始位置などの情報を含むチケット オブジェクトを返す getUserTicket という関数があるとします。

Express アプリのルーター内で、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 テンプレートは、サンプルの Bonjour Rail チケットをレンダリングする次の HTML を定義します。

<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 を定義しましたが、それを画像に変換する方法が必要です。

未加工の HTML と URL の両方を画像に変換するためのオープンソース Node.js モジュールが数多く存在します。この例では、PhantomJS のライトラッパーである node-webshot を使用します。

PhantomJS は、HTML を画像にレンダリングできるスクリプト可能なヘッドレス ブラウザです。PhantomJS はレンダリングに WebKit に依存しているため、画像、CSS、JavaScript など、複雑なページを処理できます。

ノードのウェブカメラ(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 Cloud Storage にアップロードして、新しく作成されたメディアリンクを返します。

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 でリッチカードを送信するには、最初のエージェント サンプルと同じ Node.js SDK を使用します。

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

最終的な結果のスクリーンショットを次に示します。

リッチカードのダイナミック画像

まとめと要約(DR)

リッチカードの汎用性を高める最も簡単な方法は、ダイナミック HTML を活用し、HTML を画像に変換することです。最新のプログラミング言語のほとんどは、変換の完了に役立つライブラリや API をサポートしています。ユースケースに合うように画像サイズを調整してみる必要があるかもしれませんが、これは RBM エージェント内でより魅力的なビジュアルを作成するための素晴らしいアプローチです。

それでは始めましょう。