Node.js로 카카오톡 학식 채팅봇 만들기 (1) - 서버 설정, 간단한 앱 작성
원래 Python3 + Django2 조합으로 카카오톡 챗봇을 만들어 운영하고 있었는데요. (관련 튜토리얼)
이제 노드에 전념해보고자 기존에 운영하던 챗봇을 Node.js로 똑같이 구현해보기로 결심했습니다.
바빠서 조금 미뤄두다가 아주 사소한 계기로 시작하게 됐는데 생각보다 만드는 데 시간이 별로 안 걸립니다. 파이썬보다 쉽기도 하고요. 자바스크립트를 주로 쓰시는 분들은 노드로 카카오톡 i 오픈빌더 스킬 챗봇을 쉽게 만들 수 있다는 것을 이 글 통해 알 수 있으시리라 생각합니다.
이 시리즈는 Amazon EC2로 서버 컴퓨터를 받은 뒤 실제로 학식봇의 기본이 되는 서버 설정을 하고 간단한 스킬을 만드는 과정까지 세세하게 다룹니다. 만들어둔 챗봇은 서버 구축 후에 어떤 코드를 짜느냐에 따라 중고교 급식, 대학교 학식, 날씨, 주가, 미세먼지, 버스 도착 시간 등 다양하게 사용할 수 있습니다.
(!) 필요한 것
- 자바스크립트 기초 지식 + Node.js와 express.js 기초 지식
- Linux 명령어 (cd, mkdir, rm, cat, vi, pwd, ls, clr 등..)
- vim 편집기 명령어 (i, d, q, q!, wq, wq!, p, y 등..)
- 카카오 i 오픈빌더 OBT 계정 받아두기
- Amazon EC2에서 서버 받아두기, 윈도우라면 putty 설치해서 접속 성공까지 (참고)
(!) 본인의 환경
- Amazon EC2 Linux Ubuntu 18.04.5 LTS
- Node 14.7.0
- npm 6.14.7
- nginx/1.14.0 (ubuntu)
참고로 Node.js와 express.js 기초가 어느 정도냐 물으신다면 생활코딩 express.js 까지 들으셔서 강의나 모범 코드를 보지 않고 직접 CRUD를 구현하고 HTTP 요청 메소드와 경로에 따라 라우팅을 잘 해주실 수 있는 정도라는 생각이 듭니다. 제가 초보자라 딱 그 수준을 웃돕니다. ㅎㅎ
만약 기존에 파이썬으로 운영하셨거나 웹서버로 apache를 쓰셨는데 nginx로 옮기고 싶다면 기존에 설치되어 있던 것들을 삭제하고 진행하는 게 좋을 수 있습니다. 8G라는 자그마한 디스크 용량 때문이지요 ㅎㅎ.. df 명령어로 얼마나 더 쓸 수 있는지 확인해보고 괜찮다 싶으면 그냥 진행하셔도 되고 삭제가 필요하다 싶으면 apt-get purge 명령어로 관련 설정까지 싹 밀어버리시는 걸 권합니다.
1. node, npm 설치
처음 접속했다면 pwd 를 해봅니다. /home/ubuntu 라고 나올 건데 이게 최초 접속했을 때의 경로입니다.
경로를 확인했다면 ls 를 입력합니다. 아무것도 없는 걸 확인할 수 있습니다. 이 무(無)의 환경에서 착착 쌓아나가 자동 채팅봇을 만드는 것이 이 시리즈의 목표입니다.
이제 시작해봅시다. 다음을 입력합니다.
$ sudo apt-get update
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
$ sudo apt-get install -y nodejs
$ sudo npm install -g npm
일단 apt는 리눅스의 advaned pakaging tool의 약자로 쉽게 말해 패키지 매니저입니다. 우리 Node.js에서 npm으로 이것저것 의존성들 설치하고 삭제하고 업데이트하고 뭐 그러잖아요? 리눅스에서는 apt와 apt-get로 패키지들을 관리합니다. apt와 apt-get의 차이는 크게 없으나 자세한 차이점이 궁금하시다면 이 포스팅을 참고하시기 바랍니다.
apt-get update 명령어로 기본적으로 설치된 패키지들의 사용 가능한 새 버전과 그 리스트를 가져오게 됩니다. 그 다음 curl 명령어를 이용해 14.x 버전의 최신 node를 설치합니다. 제가 이 방법 쓰기 전에 그냥 apt-get install node 해봤는데 6 버전이 다운로드되더군요 -_-
그런 다음 apt-get install -y nodejs를 하면 14.x 버전의 최신 node가 설치됩니다. -y 옵션을 붙인 건 중간에 뭘 설치할 건데 몇 KB가 필요하다, 설치하겠냐 하면 y나 n를 입력해야 하는데 어차피 설치하려면 y 눌러야 하니까 그냥 자동으로 모든 질문에 y를 입력할 수 있도록 해 주기 위함입니다.
node 설치 후 npm도 설치해줘야겠죠? 전역 의존성으로 깔아 줍니다.
여기까지 node와 npm 최신 버전 설치가 완료되었습니다.
2. 프로젝트 폴더 만들기, 포트 인바운드 보안 규칙 설정
이제 프로젝트 베이스가 되는 폴더를 만들고 거기서 앱을 하나 작성해볼 건데요. 그 전에 할 일이 하나 있습니다. 보통 node 앱은 3000 포트를 많이들 엽니다만 ec2 최초 보안 규칙상 인바운드 포트로 3000이 없고 22, 80 정도만 있는 경우가 많습니다. 사실 3000이 됐든 5000이 됐든 여러분의 앱이 쓰고자 하는 포트를 사용하려면 보안 규칙에서 해당 포트를 인바운드로 열어줘야 합니다. 여기서는 3000번 포트를 쓰기로 합니다.
AWS 홈페이지로 가서 계정에 로그인하고 EC2 대시보드로 이동합니다. '네트워크 및 보안 > 보안 그룹'을 클릭하면 다음과 같은 화면이 나옵니다.
여기서 첫 번째 보안 그룹 ID를 클릭하면 보안 그룹 정보와 함께 인바운드/아웃바운드 규칙, 태그 탭이 나오는데요. 여기서 인바운드 규칙 편집 버튼을 눌러 규칙 편집을 하면 됩니다.
규칙 추가 버튼을 눌러 사용자 지정 TCP 유형을 선택한 다음 포트 범위에서 앱이 사용할 포트 번호를 입력해 줍니다. 사실 이건 범위라서 3000-3010 뭐 이런 식으로 지정해도 되지만 앱이 하나라서 굳이 여러 개 지정할 필요 없으므로 3000 포트만 열어 주기로 합니다. 소스는 그냥 0.0.0.0/0 해서 규칙 저장을 해 줍니다.
다시 우리 EC2 환경으로 돌아옵니다. /home/ubuntu 위치에서 다음 명령어를 입력합니다.
$ mkdir [folder_name] && cd [folder_name]
$ npm init -y
$ npm i express
folder_name 은 만들고 싶으신 앱의 이름대로 임의로 정하시면 됩니다. 그런 다음 npm init으로 node 프로젝트를 시작합니다. package.json에서 따로 설정해줄 것이 있다면 -y 옵션을 떼고 실행하시면 됩니다.
express.js를 사용하기 위해 express를 설치합시다. 카카오톡 챗봇에서 사용자가 보낸 메시지들은 POST 방식으로 붙어서 오기 때문에 그냥 node.js를 쓰는 것보다 POST 방식 데이터를 처리하는데 유리한 점이 있습니다.
3. 간단한 앱 작성
아니 벌써 앱 작성을 한다고?? 그렇습니다. node로 만들면 일이 너무나 쉬워집니다. 제가 node에 반한 이유입니다. 물론 동의하지 못하는 분들도 계시겠지만 전 django로 작업하다가 node로 넘어오니 간단하게 느껴지더라구요.
$ vi app.js
//app.js
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.get('/keyboard', (req, res) => {
const data = {'type': 'text'}
res.json(data);
});
app.listen(3000, () => console.log('node on 3000'));
이렇게만 입력하면 됩니다. 왜 이렇게 짧냐구요? 아직 /message 경로 부분을 처리하지 않았기 때문입니다. 일단 /keyboard 경로로 되는지부터 확인하고 다음 일을 진행하도록 합니다.
express.js에 익숙하신 분들이라면 이 코드를 읽는 게 그리 어렵지 않으실 거라는 생각이 듭니다.
express.urlencoded 는 POST 요청으로 들어오는 데이터를 req.body로 받아주기 위함인 것 다들 아실 거구요.
express.json 미들웨어는 body-parser 방식에 기반해 JSON 페이로드(payload)와 함께 들어오는 요청을 파싱해 준다고 docs에 적혀 있는데 쉽게 말하면 request body를 JSON으로 파싱해주는 역할입니다. JSON 형식으로 들어오는 요청 body를 처리하기 위한 것이죠.
/keyboard 경로로 들어오는 GET 요청은 JSON 데이터를 response로 돌려주는 방식으로 처리하게 됩니다.
그런 다음 3000 포트로 listen을 합니다.
저장하고 나와서 실행해 봅니다.
$ node app
뭔가 틀리지 않았다면 콘솔에 'node on 3000'이 나올 겁니다. 이제 여러분이 받은 IP:3000/keyboard 로 접근해 보세요.
다음과 같은 화면이 나온다면 잘 되고 있는 것입니다. Ctrl + C 버튼을 눌러 실행을 중단할 수 있습니다.
4. 사용자의 메시지에 따라 응답하기
이제 사용자가 보내는 메시지에 따라 다른 응답을 주는 작업도 해봅시다. 다시 app.js 파일을 엽니다.
//app.js
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.get('/keyboard', (req, res) => {
const data = {'type': 'text'}
res.json(data);
});
app.post('/message', (req, res) => {
const question = req.body.userRequest.utterance;
const goMain = '처음으로';
if (question === '테스트') {
const data = {
'version': '2.0',
'template': {
'outputs': [{
'simpleText': {
'text': '테스트'
}
}],
'quickReplies': [{
'label': goMain,
'action': 'message',
'messageText': goMain
}]
}
}
}
res.json(data);
});
app.listen(3000, () => console.log('node on 3000'));
app.post('/message') 부분이 추가되었습니다.
카카오 i 오픈빌더 도움말을 참고하면 POST 요청으로 넘어오는 데이터의 userRequest.utterance가 사용자 발화를 의미한다는 것을 알 수 있습니다. 이것을 question에 할당해 줬습니다. 이 발화를 기준으로 분기문을 작성하게 됩니다.
저는 '테스트'라는 발화가 들어오면 '테스트'라는 말을 메아리로 돌려주도록 했습니다. quickReplies는 응답을 돌려주면서 초기 메뉴로 가는 숏컷 버튼을 주는 것입니다. 이 글은 카카오 i 오픈빌더 사용법을 다루지 않기 때문에 이 부분은 넘어가겠습니다. 마지막에 res.json(data)로 응답을 돌려주는 걸 잊지 마세요.
5. 카카오 i 오픈빌더에서 스킬 설정
이제 정말 기초적인 봇을 만들었으니 테스트를 해봐야겠죠? 카카오 i 오픈빌더 홈페이지에 가서 카카오톡 채널 챗봇을 만듭니다. 채널 챗봇 만드는 건 쉬우니 여기서는 넘어가겠습니다.
설정 탭으로 가서 카카오톡 채널 연결을 합니다. 미리 만들어둔 카카오톡 채널을 연결하고 저장 버튼을 누르면 됩니다.
시나리오 탭으로 넘어와서 시나리오를 추가하거나 기존에 있는 시나리오 01에 블록을 추가합니다. 저는 '테스트'로 이름을 정했습니다. 그리고 사용자 발화에 '테스트'를 입력한 뒤 봇 응답에서 '스킬데이터 사용'을 누른 다음 저장합니다.
그 다음 스킬 탭으로 가서 생성 버튼을 눌러 스킬을 하나 만들어 줍니다. 설명은 선택이지만 URL은 필수로 입력해야 하는데요. EC2 IP 주소:3000/message를 넣어준 뒤 기본 스킬로 설정을 체크해주고 저장하면 됩니다.
한 단계가 더 남았습니다. 배포 탭으로 이동해 배포 버튼을 눌러야만 챗봇에 수정 사항이 반영됩니다. 잠깐 배포를 기다려주고 테스트해봅시다. 테스트 전 EC2 인스턴스에서 node app 으로 앱을 실행해주는 걸 잊지 마세요.
잘 동작한다면, 축하합니다! 벌써 챗봇을 완성하셨습니다.
물론 쓰임새에 따라 해줄 작업이 좀 있지만 제일 기본적인 작업을 할 수 있으니 다른 작업도 할 수 있습니다.
해결해야 할 문제점은 2가지입니다.
- putty를 종료했을 때 챗봇이 멈춤. 즉, node app이 계속 실행되어야 함 -> pm2로 해결 가능
- 구체적인 작업을 실행하기 위한 세부 작업
- 학식봇의 경우 학교 홈페이지 크롤링 작업이 필요 -> cheerio, puppeteer로 해결 가능
cheerio와 puppeteer, pm2 및 nginx를 다루는 방법은 다른 포스팅에서 쓰겠습니다.
감사합니다.
다음 글 보기
Reference
- Expressjs 에서 JSON Request Body 파싱하기
- req 객체와 res 객체, 그리고 res.send와 res.json의 비교
- Express res.json과 res.send 비교