동적 리치 카드 생성을 위해 HTML에서 이미지를 만드는 방법

RCS Business Messaging에서 가장 강력하고 다양한 유형의 콘텐츠는 리치 카드입니다. 리치 카드를 사용하면 이미지 또는 동영상, 제목, 설명, 최대 4개의 추천 답변 또는 작업과 같은 관련 정보를 하나의 메시지로 보낼 수 있습니다.

독립형 리치 카드와 리치 카드 캐러셀은 사용자의 참여를 유도하는 환경을 만드는 데 도움이 되는 강력한 기능입니다. 공유해야 하는 이미지가 쿠폰이나 제품과 같은 정적 이미지인 경우에 한합니다. 하지만 탑승권과 같이 사용자에 대한 정보를 기반으로 동적 콘텐츠를 전송해야 하는 경우에는 어떻게 해야 할까요?

이 도움말에서는 HTML로 즉시 이미지를 만들고 이러한 이미지를 에이전트가 전송하는 리치 카드 안에 삽입하는 방법을 설명합니다. 먼저 HTML을 이미지로 변환하는 방법부터 살펴보겠습니다.

HTML에서 이미지로

HTML은 텍스트와 미디어의 조합을 배치하는 데 좋습니다. 개발자로서 탑승권, 데이터 사용량 차트, 기타 유형의 사용자별 정보 등을 사용자에게 제공하기 위해 제품을 빌드해야 하는 경우, 동적으로 생성되는 HTML이 저희가 사용하는 도구일 가능성이 높습니다. RCS Business Messaging에서 리치 카드는 이미지 및 동영상 미디어 유형만 지원하므로 HTML에서 동적 콘텐츠 생성을 위해 HTML을 사용하려면 먼저 이미지로 변환해야 합니다.

다행히 대부분의 최신 프로그래밍 언어는 이미지 생성에 사용할 수 있는 최소한 기본 HTML (예: JEditorPane)을 렌더링할 수 있는 웹페이지 또는 구성요소의 스크린샷을 찍기 위한 라이브러리를 지원합니다.

웹페이지를 촬영하는 데 사용할 수 있는 API도 있습니다. 예를 들어 Google의 페이지 통계 API를 사용하여 URL에서 스크린샷을 자동으로 생성할 수 있습니다.

예:

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

다음에서는 Node.js 익스프레스 앱을 사용하여 HTML로 사용자별 탑승권을 생성하고, 이미지로 변환하고, 공개적으로 액세스할 수 있는 URL에 업로드한 다음, 리치 카드 내에 이미지를 첨부하여 사용자에게 전송합니다.

동적 탑승권 만들기

시작하려면 아래 이미지와 같이 탑승권을 생성하기 위해 HTML이 필요합니다.

탑승권 샘플

이 작업은 다양한 방법으로 처리할 수 있지만, Node.js 앱에서 /getTicket?msisdn=+12223334444이라는 URL 엔드포인트를 정의하여 EJS 뷰 엔진을 사용하여 탑승권에 필요한 HTML을 렌더링합니다.

사용자의 전화번호를 가져와 출발 시간, 좌석, 티켓 유형, 시작 위치 등의 정보가 포함된 티켓 객체를 반환하는 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 템플릿은 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, 자바스크립트로 복잡한 페이지를 처리할 수 있습니다.

노드 웹샷 (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에 파일 저장

웹샷으로 생성된 이미지를 사용하려면 공개적으로 액세스할 수 있는 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
      });
});

이미지가 포함된 리치 카드 보내기

거의 완료됐습니다. 이전 단계에서 만든 이미지를 사용하여 RBM 리치 카드를 만들어 사용자에게 전송하는 sendBoardingPass(imageUrl, msisdn) 함수를 정의하여 마지막 단계를 완료하겠습니다.

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

다음은 최종 결과의 스크린샷입니다.

리치 카드의 동적 이미지

요약 및 요약

리치 카드를 다목적으로 만드는 가장 간단한 방법은 동적 HTML을 활용하고 HTML을 이미지로 변환하는 것입니다. 대부분의 최신 프로그래밍 언어는 변환 완료에 도움이 되는 라이브러리 또는 API를 지원합니다. 사용 사례에 맞게 이미지 크기를 조절해야 할 수 있지만 RBM 에이전트 내에서 더 매력적인 시각 자료를 만드는 데 매우 유용합니다.

행운을 빕니다.