2018. 06. 04 수정

처음 Node를 접했을 때부터 채팅 프로그램에 관심이 많았고 인공지능이 화두이다 보니 간단한 챗봇을 만들어 보고 싶었습니다.

여러 플랫폼에서 챗봇을 개발할 수 있는데, 저는 Facebook이 끌리기 때문에 Facebook Messenger를 이용한 챗봇 개발을 구현해보려고 합니다.


이 글은 Getting Started의 예제 코드를 최대한 간단하게 수정하여, 작성되었습니다.





1. 페이스북 계정과 페이스북 페이지 생성

페이스북 챗봇은 페이스북 페이지에 유저가 메시지를 보내면 이에 대한 응답을 하는 방식입니다.

때문에 페이스북 페이지가 있어야 하므로 먼저 페이스북 페이지를 만들어 보겠습니다.



페이스북을 로그인 하시면 우측 상단에 "페이지 만들기"가 있습니다.

페이지를 만드는데 어려움은 없으므로 과정은 생략하겠습니다.





2. 개발 환경 구축

챗봇을 잘 이용하려면 DB를 연동해야 하지만, 지금은 간단하게 예제를 살펴볼 목적이기 때문에 DB는 사용하지 않겠습니다.

우선 express-generator로 프로젝트를 생성합니다.

( express가 없어도 app.js에서 구현이 가능하지만 express를 기준으로 말씀드리겠습니다. )


그리고 도메인이 필요한데, 빠르고 간단하게 할 목적으로 ngrok을 사용하도록 하겠습니다.

ngroklocalhost를 공공IP로 forwarding 해주는 프로그램입니다.

ngrok은 8시간 동안만 세션이 유지되므로, 안정적인 호스팅을 원한다면 Heroku를 사용하시면 됩니다.

( ngrok에 대한 자세한 설명은 여기를 Heroku로 호스팅하는 방법은 여기를 참고해주세요. )



커맨더 창에서 아래의 명령어를 실행하여 ngrok을 실행합니다.

# ngrok http 3000



ngrok으로부터 받은 URL은 https://8818582a.ngrok.io이며, 위의 URL을 통해 페이스북으로부터 인증을 받을 것이고, 메시지가 전송됩니다.





3. 페이스북 개발자 - 앱 생성

페이스북 개발자 사이트에 들어가셔서 방금 만든 페이스북 페이지에 앱을 설치하기 위해 앱을 만들어야 합니다.


위의 링크를 클릭하시면 우측 상단에 "앱 만들기"가 있습니다.

입력란을 작성해주시면 아래 사진과 같은 페이지가 나옵니다.



여기서 Messenger의 "설정"을 클릭해주세요.





4. 페이스북 개발자 - 토큰 생성



토큰 생성 항목까지 내려가신 뒤, "페이지 선택"을 클릭하여 페이지를 선택하면 자동으로 토큰이 생성될 것입니다.

이 토큰이 있어야 페이지 관리자로서 인증이 되는 것이므로 외부에 노출되어서는 안됩니다.

일종의 권한 같은 것이라고 보시면 됩니다.


토큰을 생성하셨으면 당장은 할 일이 없으므로 그냥 내버려 두겠습니다.





5. 페이스북 개발자 - Webhooks 설정

바로 아래에 Webhooks 항목에서 "webhooks 설정"을 클릭해주세요.


그리고 위의 사진과 같이

  • 콜백 URL
    • ngrok의 URL주소/webhook을 작성합니다.
  • 확인 토큰
    • 아무 이름을 작성해도 되며, 예제에서는 "VERIFY_TOKEN"으로 작성하겠습니다.
  • 그리고 모든 항목을 체크 합니다.

아직 서버를 실행시키지 않았으므로 확인 버튼을 누르지 않고 이 상태에서 대기합니다.





6. 코드 작성

이제 페이스북에서 제공하는 Getting Started의 코드를 조금 수정해서 작성해볼 것입니다. ( 참고 )

위 링크의 "봇 빌드 (1) 핸들러 함수 해제 ~ (5) 보내기 API를 사용하여 메시지 보내기" 과정을 작성하겠습니다.


routes/index.js

const express = require('express');
const request = require('request');
const router = express.Router();

const PAGE_ACCESS_TOKEN = '4번에서 생성된 토큰을 작성';
const VERIFY_TOKEN = "VERIFY_TOKEN";

router.get('/webhook', (req, res) => {
console.log(req.query['hub.verify_token'])
if (req.query['hub.verify_token'] === VERIFY_TOKEN){
return res.send(req.query['hub.challenge'])
}
res.send('wrong token')
})


router.post('/webhook', (req, res) => {
let body = req.body;
if (body.object === 'page') {
body.entry.forEach(function(entry) {
let webhook_event = entry.messaging[0];
console.log(webhook_event);

let sender_psid = webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);

if (webhook_event.message) {
handleMessage(sender_psid, webhook_event.message);
}
else if (webhook_event.postback) {
handlePostback(sender_psid, webhook_event.postback);
}
});
res.send('EVENT_RECEIVED');
}
else {
res.sendStatus(404);
}

});


function handleMessage(sender_psid, received_message) {
let response;
if (received_message.text) {
response = {
"text": `You sent the message: "${received_message.text}". Now send me an image!`
}
}
callSendAPI(sender_psid, response);
}

function callSendAPI(sender_psid, response) {
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}

request({
"uri": "https://graph.facebook.com/v2.6/me/messages",
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!')
}
else {
console.error("Unable to send message:" + err);
}
});
}

module.exports = router;

코드가 상당히 긴데, 어려운 내용은 없습니다.


1) PAGE_ACCESS_TOKEN, VERIFY_TOKEN 상수

  • PAGE_ACCESS_TOKEN
    • 준비 작업 단계에서 생성한 토큰의 값을 입력하면 됩니다.
  • VERIFY_TOKEN
    • webhook에서 설정한 확인 토큰의 값을 입력하면 됩니다.



2) /webhook GET 라우터 미들웨어

설정한 webhook 정보에 대한 검증을 수행하는 라우터 함수입니다.

페이스북은 URL에 다음과 같이 3개의 파라미터를 전송하며, 라우터에서는 hub.challenge의 값을 응답하면 됩니다.

/webhook?hub.mode=subscribe&hub.challenge=526922530&hub.verify_token=VERIFY_TOKEN




3) /webhook POST 라우터 미들웨어

페이스북 페이지에 누군가가 메시지를 작성하면 /webhook에 post방식으로 요청이 들어옵니다.

webhook을 설정할 때 콜백 URL을 그렇게 작성했기 때문이죠.


라우터 함수에서는 메시지 내용을 읽어서 handleMessage() 메서드를 호출합니다.

이 때 sender_psid 변수를 인자로 넘겨주는데, 이는 챗봇이 메시지를 보낼 때 페이스북 페이지를 식별하는 용도입니다.




4) handleMessage() 메서드

handleMessage() 메서드는 챗봇이 응답할 메시지를 작성합니다.

여기서는 echo 메시지를 응답하려고 합니다.


실제 발송을 하는 callSendAPI() 메서드를 호출할 때 메시지가 담겨있는 response 객체를 인자로 넘겨줍니다.




5) callsendAPI() 메서드

callSendAPI() 메서드는 "페이스북 Messenger 플랫폼의 보내기 API"를 사용하기 위한 코드를 작성합니다.

이 때 토큰, 응답할 페이스북 페이지 번호, 메시지 내용이 request() 함수를 통해 전달됩니다.

request() 함수를 사용하기 위해서는 request 모듈을 설치해야 하며, 이를 require 해줍니다.

# npm install request

const request = require('request');





7. 테스트

이제 테스트를 해보도록 하겠습니다.


먼저 서버를 실행하여, 브라우저에서 ngrok IP 주소가 접근 가능한지 확인해봅니다. ( 저 같은 경우는 https://8818582a.ngrok.io )

접속이 가능하면,  5단계 Webhooks 설정 화면에서 "확인 및 저장" 버튼을 눌러주세요.



그러면 Webhooks 항목이 위의 사진처럼 바뀌었을 것입니다.

"페이지 선택" 클릭 > 페이지 선택 > "받아보기"를 클릭하면, 페이스북 페이지에서 메시지를 입력했을 시 서버에 전송이 될 것입니다.



마지막으로 테스트를 진행할 페이스북 페이지에 들어가셔서 메시지를 보내면 됩니다.






이어지는 2단계에서 Messeneger 플랫폼을 선택하시면 됩니다.







이제 메시지를 보내보세요 !





이상으로 페이스북 Messenger를 이용해서 챗봇을 만들어보았습니다.

이 밖에 세세한 기능은 페이스북 개발자 사이트의 공식 문서를 참고하시면 될 것 같습니다.

이 글에서는 간단히 하기 위해 DB를 사용하지 않았지만 정말 챗봇처럼 동작하려면 DB까지 있어야 할 것입니다.