Watson으로 쉽게 만드는 카카오톡 ChatBot

이 포스팅은 3. 대화 내용으로 회의실 예약하기에 이어지는 포스팅입니다. 이 단계에서는 어플리케이션을 카카오톡과 연동하기 위한 API를 생성합니다.

< 이 포스팅과 연결된 글 목록 >

4. Node.js 어플리케이션 카카오톡과 연동하기

4.1 옐로아이디 생성

카카오톡은 옐로아이디라는 서비스를 제공하고 있는데, 이 서비스를 통해서 플러스친구를 생성할 수 있습니다. 옐로아이디의 생성은 카카오톡 옐로아이디 공식 홈페이지를 통해 가능하며 서비스 관리자의 승인 후 완료되는데 2-3일에서 최대 일주일 소요된다고 합니다. 저의 경우는 2일정도 걸렸습니다.

옐로아이디 생성이 완료된 후에는 내 옐로아이디 관리 화면을 사용할 수 있습니다. 관리화면의 좌측에 보면 자동 응답이란 메뉴가 있는데, 우리는 이 기능을 사용하여 Watson Converation과 연동할 것입니다.

카카오톡의 옐로아이디는 1개의 메세지에 대해 1개의 응답을 설정할 수 있습니다. 다시 말하면, 사용자가 카카오톡을 통해 말을 걸면 그에 대한 응답을 하도록 설정이 가능합니다. 반대로 서비스가 먼저 말을 걸도록 설정하는 것은 카카오톡에 문의한 결과 옐로아이디가 아닌 카카오톡 비즈메세지를 통해서 가능하다고 합니다. 혹시 관련 기능에 관심이 있으신 분은 비즈메세지 서비스를 참조하십시오.

4.2 카카오톡 연동을 위한 테스트 API 생성

이 튜토리얼은 3. 대화 내용으로 회의실 예약하기에 이어집니다. Tutorial 3을 완료하지 못하신 분은 tutoral4를 checkout 합니다.

git checkout tutorial4

카카오톡과 연동을 테스트하기 위해 dummy API를 생성합니다.

카카오톡의 자동응답 서비스와 연동하기 위해서는 /keyboard/message API를 구현해야합니다.

1) /api 밑에 kakao 폴더를 생성합니다.

2) /api/kakao 밑에 keyboard.js를 생성하고 다음 코드를 입력합니다.

'use strict';

let getKeyboard = (req, res) => {
  res.setHeader('Content-Type', 'application/json; charset=utf-8');

  return res.json({
    "type" : "text"
  })
};

module.exports = {
  'initialize': function(app, options) {
    app.get('/api/kakao/keyboard', getKeyboard);
  }
};

3) /api/kakao 밑에 message.js를 생성하고 다음 코드를 입력합니다.

'use strict';

let postMessage = (req, res) => {
  res.setHeader('Content-Type', 'application/json; charset=utf-8');

  return res.json({
    "message" : {
      "text" : "test"
      }
  })
};

module.exports = {
    'initialize': function(app, options) {
        app.post('/api/kakao/message', postMessage);
    }
};

4) /api/index.js를 아래와 같이 수정합니다. 굵은글씨로 된 코드를 추가합니다.

'use strict';

console.log('APIs initialize');

const conversation = require('./message');
const kakao_keyboard = require('./kakao/keyboard');
const kakao_message = require('./kakao/message');

module.exports = {
    'initialize': (app, options) => {
        conversation.initialize(app, options);
        kakao_keyboard.initialize(app, options);
        kakao_message.initialize(app, options);
    }
};

5) 수정한 코드를 블루믹스에 디플로이합니다. 프로젝트의 최상위 폴더에서 다음 명령을 수행합니다.

cf push

4.3 옐로아이디로 자동응답 설정하기

yellowid03

카카오톡 옐로아이디의 자동응답 기능은 키워드형 자동응답과 API형 자동응답이 있습니다. 우리는 우측에 위치한 API형 자동응답을 통해 서비스를 연동 하려합니다.
설정하기 버튼을 눌러 설정을 시작합니다.

제가 설정한 정보를 참조하되 App URL에는 각자의 url 뒤에 /api/kakao를 붙여 입력하십시오.

yellowid04

API 테스트 버튼을 클릭하여 정상 동작을 확인합니다.
설정을 완료한 뒤에는 서비스 시작 버튼을 눌러 서비스를 시작합니다.

설정을 테스트 하기 위해서는 카카오톡에서 플러스 친구를 등록한 후 아래 스크린샷처럼 아무 메세지나 남겨봅니다.

KakaoTalk_20170219_205430774

4.4 Watson Conversation과 카카오톡 연동하기

이 단계에서는 Watson Conversation과 카카오톡 api를 연결하기 위해 각 api의 input/output을 맞춰줍니다. /api/kakao/message.js를 수정하여 카카오톡으로 부터 오는 메세지를 Watson Conversation 서비스의 input으로 하고 Watson Conversation 서비스의 output을 response로 하여 카카오톡의 응답으로 노출되도록 설정합니다. 이 과정에서 context를 유지하기 위해, 카카오톡 api가 주는 user_key 값을 id로 하여 context를 cloudant에 저장합니다.

1) 먼저 .env 파일에 cloudant의 credential 정보를 설정합니다. cloudant의 credential 정보 중 cloudantUrl은 cloudant에 접근할 수 있는 url을, cloudantDB는 database 이름을 의미합니다. cloudantUrl 값은 Bluemix dashboard에서 Cloudant 서비스를 선택한 후 서비스 신임 정보 메뉴를 통해 확인할 수 있습니다. cloudantDB의 값은 예시와 동일하게context로 설정합니다.

# Cloudant
CLOUDANT_URL=https://XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX-bluemix:XXXXXXXXXXXX@XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX-bluemix.cloudant.com
CLOUDANT_CONTEXT_DB=context

2) /util/db.js를 확인합니다. 이전 단계에서 설정한 환경변수를 이용하여 database를 생성하고 연결하도록 되어있습니다.

process.env.CLOUDANT_URL
process.env.CLOUDANT_CONTEXT_DB

3) /api/kakao/message.js를 수정하여 Conversation Service를 호출하도록 구현합니다. 먼저 파일 상단에 필요한 module을 import 합니다.

const conversation = require('../message');
const cloudant = require('../../util/db');
const db = cloudant.db;

4) postMessage() 함수를 다음과 같이 수정합니다.

let postMessage = (req, res) => {
  res.setHeader('Content-Type', 'application/json; charset=utf-8');

  //{ user_key: 'DBpb8t6y66U2', type: 'text', content: 'Hello' }
  let user_key = req.body.user_key;
  let type = req.body.type;
  let content = {
    'text' : req.body.content
  };

  //user_key를 사용하여 db에 저장된 context가 있는지 확인합니다.
  db.get(user_key).then(doc => {
    //저장된 context가 있는 경우 이를 사용하여 conversation api를 호출합니다.
    conversation.getConversationResponse(content, doc.context).then(data => {
      // context를 업데이트 합니다.
      db.insert(Object.assign(doc, {
        'context': Object.assign(data.context, {
          'timezone' : "Asia/Seoul"
        }),
      }));

      return res.json({
        "message" : {
          "text" : getOutputText(data)
        }
      });
    }).catch(function(err){
      return res.json({
          "message" : {
            "text" : JSON.stringify(err.message)
          }
      });
    });
  }).catch(function(err) {
    // 처음 대화인 경우 context가 없습니다. 이러한 경우 context 없이 conversation api를 호출합니다.
    conversation.getConversationResponse(content, {}).then(data => {
      // context를 저장합니다.
      db.insert({
        '_id' : user_key,
        'user_key' : user_key,
        'context': data.context,
        'type' : 'kakao'
      });
          
      return res.json({
          "message" : {
            "text" : getOutputText(data)
          }
      });   
    }).catch(function(err){
      return res.json({
          "message" : {
            "text" : JSON.stringify(err.message)
          }
      });
    });
    
  });
};

5) getOutputText() 함수를 추가합니다. 카카오톡의 api 포맷에 맞추기 위해 conversation이 주는 Array 타입의 output.text에서 String 값을 추출합니다.

let getOutputText = data => {
  let output = data.output;
  if(output.text && Array.isArray(output.text)){
    return output.text.join('\\n');
  }
  else if(output.text){
    return output.text;
  }
  else return "";
}

4.5 카카오톡으로 테스트하기

코드작성이 완료되었으면 카카오톡으로 다음과 같이 테스트합니다.

KakaoTalk_20170219_205418205

이어지는 포스팅은

Watson으로 쉽게 만드는 카카오톡 ChatBot 5. [응용] 회의실 예약 조회 및 취소 기능 추가하기

입니다.