텔레그램 챗봇 DalPic_bot 개발기

 

완성본

  • ID : @Dalpic_bot
  • Link : t.me/DalPic_bot

main

구상

원하는 사진을 단순히 채팅을 입력해 다운로드할 수 있다면 정말 편하겠다! 라는 생각에서 시작했다.
먼저, 이 아이디어의 구현에 제일 중요한 요소는 채팅사진 이였다.

채팅 은 메신저앱을 이용하기로 생각을 했고, 텔레그램과 카카오톡 그리고 라인 중 어떤 것을 이용할 지 고민을 해야했다. 일단, 카카오톡은 경험이 없어서 패스. 라인은 로컬에서 테스트를 하기 어려워서 쉬운 Telegram으로 최종 선택했다.

사진 은 저작권이 프리한 사이트로 검색한 결과 Pixabay와 Unsplash를 찾았고, 두 곳 모두 API를 제공함을 확인하고, 결론적으로 한국어를 지원하는 Pixabay를 이용하기로 했다.

픽사베이

픽사베이 API 를 이용하기 위해 가입 후 API key를 발급받았다. API를 이용할 때 가장 중요한 것은 사용조건을 꼼꼼히 읽어보는 것이다. 픽사베이 API를 사용할 때는 사진과 출처를 같이 제공해야하고, 사진은 핫링크가 아닌 서버에 다운을 받은 후 유저에게 전송해야한다.

API에 GET 방식으로 요청하며, 다양한 파라미터들도 제공하고 있다.
기본 파라미터 외에 사용한 파라미터들이다.

  • lang : 한국어로 검색가능하도록 ko
  • safesearch : 전 연령에 적합한 이미지만 가져오도록 true
https://pixabay.com/api/?key=" + API_KEY + "&q=" + encodeURIComponent(text) + "&lang=ko&safesearch=true

응답은 JSON으로 받을 수 있으며, Response Key 와 Description은 API docs에 자세히 설명되어있다.

JSON.parse(body)

텔레그램

Token

텔레그램봇을 생성하려면 @BotFather를 통해 HTTP API 토큰 을 발급받아야한다. 토큰을 발급받는 과정은 [Node.js로 텔레그램 챗봇 만들기](https://dalhav.github.io/2019/03/23/nodejs-chatbot-telegram/) 를 참고바란다.

Module

익숙한 Node.js 기반으로 서버를 작성하기로 했고, 모듈을 여러개 살펴보다가 Github Star가 가장 많은 node-telegram-bot-api 를 선택했다.

구현

/start & /help

텔레그램에서 봇을 추가해서 시작하면 자동으로 /start 가 입력된다. 그래서 제일 먼저 작성한 코드는 /start 를 입력받았을 때 출력되는 내용이다.
처음 출력되는 말풍선이라 어떤 요소를 넣을지 고민하다가 인삿말과 모든 사진의 출처 그리고 제작자를 출력하기로 했다.
그리고 보편적으로 도움말로 사용하는 /help/start 와 같은 내용으로 출력되도록 하였으며, 내용은 마크다운으로 작성했다.

1

text = "반갑습니다. :)\n*키워드를 입력하면 사진을 보내드립니다.*\n\n"
        +"모든 사진의 출처는 [Pixabay](https://pixabay.com/ko/)입니다.\n\n"
        +"❤ 제작자 `Dalha.v` ❤";
        
bot.sendMessage(chatId, text, {parse_mode: "Markdown"});

Request

모든 메시지에 대하여 키워드로 인식하고, 사진을 검색하여 제공하도록 코드를 작성하였다.

 var URL = "https://pixabay.com/api/?key=" + API_KEY + "&q=" + encodeURIComponent(text) + "&lang=ko&safesearch=true";
        request(URL, function (err, res, body) { ...

2개 이상의 키워드는 + 로 묶어야해서 replace를 이용해 공백이 있으면 + 로 치환하였다.

msg.text.toString().replace(" ", "+");

Error 1

테스트를 하는 중 명령어인 /start/help 는 검색에서 제외하도록 처리를 하지 않아서 두 명령어에 대해서도 결과가 출력이 되었다.
더 좋은 방법이 있을 듯하지만 당장 떠오르는 방법인 if로 해결하였다.

if(msg.text.toString().toLowerCase().indexOf("/help")!==0 && msg.text.toString().toLowerCase().indexOf("/start")!==0)

Random

똑같은 키워드를 여러번 입력하여도 매번 다른 결과가 나오도록 사진을 랜덤으로 출력하면 더 재밌고, 유용할 것이라고 생각했다.
일단, 파라미터에 per_page=30 을 줘서 30개의 이미지만 가져오도록 하고, Math함수를 이용해 0 ~ 30 사이의 랜덤정수값 num 을 만든 뒤, 배열의 n번째 사진을 출력하도록 하였다.

var num = Math.floor(Math.random() * 30);

Error 2

랜덤으로 사진이 잘 출력되는지 위의 코드를 테스트하는 도중 야옹이를 입력을 하니, 콘솔에 에러가 찍혔다.
먼저, 검색결과가 없을 경우에 대해서는 이미 처리를 해두어서 야옹이에 대한 사진이 있다고 판단을 하고 Pixabay에서 야옹이를 검색했다. 검색결과를 본 뒤, 바로 파악한 에러의 원인은 결과물이 30개보다 적어서였다.
파라미터 per_page=30 는 제거하고, 랜덤정수값 num 의 최대값은 응답으로 받은 배열의 길이로 변경하여서 에러를 해결하였다.

var num = Math.floor(Math.random() * (data.hits.length));

SendPhoto

sendPhoto 를 사용하면 사진이 자동으로 텔레그램서버에 저장된 후 유저에게 전송되는 방식이라 핫링크에 대한 문제도 쉽게 해결했다.
사진의 출처는 캡션으로 달아서 사진과 함께 전송되도록 하였다.

user = "Photo by [" + data.hits[num].user.toString() + "](https://pixabay.com/users/" + data.hits[num].user.toString() + "-" + data.hits[num].user_id.toString() + ")\n";
source = "Source page on [Pixabay](" + data.hits[num].pageURL + ")";
bot.sendPhoto(chatId, url, {caption: user + source, parse_mode: "Markdown"},);                                

2

배포

텔레그램봇의 경우 로컬에서도 서버를 띄워서 작동시킬 수 있다는 장점이 있지만 실제 지속적인 서비스를 하기 위해 계속 컴퓨터를 켜둘 수 없기 때문에 PaaS인 Heroku를 이용했다.
하지만 Heroku를 무료로 이용할 경우 30분마다 서버가 슬립상태가 되어서 챗봇서비스를 제공하기에 어려움이 있었으나 25분마다 핑을 날려서 서버가 잠들지 않게 해주는 서비스를 이용하기로 했다. Non-Sleep을 위해 사용될 Http End Point를 Express.js로 간단하게 만들었다.

var express = require('express');
var packageInfo = require('./package.json');

var app = express();

app.get('/', function (req, res) {
    res.send("Hi! DalPic_bot! Web for Heroku Not Sleep!")
});

app.listen(process.env.PORT, function () {
    console.log('Server Start!');
});

마치며

챗봇은 결과물이 눈에 바로 보이고, 다양한 플랫폼에 얹을 수 있어서 구현하면서 재미있었다.

@DalPic_bot의 전체 소스는 깃허브에서 볼 수 있다.

github.com/dalhav/DalPic_bot

+유익했다면 깃허브레포에 별을 달아주길 바라며… 감사합니다!