체인의정석

텔레그램 봇 기본 틀 만들어 보기 (기본 템플릿, 깃허브 소스코드 및 사용방법 포함, javascript & typescript) 본문

개발/frontend

텔레그램 봇 기본 틀 만들어 보기 (기본 템플릿, 깃허브 소스코드 및 사용방법 포함, javascript & typescript)

체인의정석 2023. 7. 29. 22:35
728x90

요즘 우리 팀에서는 텔레그램 봇을 통해 다양한 DAPP 관리나 모니터링 등을 하고 있다.

보아하니 매우 유용하게 사용이 가능할거 같다는 판단이 들어 이에 따라 나도 한번 텔레그램 봇을 학습해보려고 한다.

 

* 일단 해당 내용의 경우 아래 깃허브 브랜치에 만들어 두었다.

https://github.com/hyunkicho/telegrambot/tree/demo/telegrambot

1. 텔레그램에서 bot father 계정 찾고 봇 계정 만들기

먼저 텔레그램 아이디로 봇 파더 계정에게 말을 걸어서 계정을 할당받아야 한다.

/start 로 말을 걸면 각 종 명령어들이 나온다.

/newbot 명령어로 새로운 봇을 만들도록 시키게 되면 이름을 만들라고 시키는데

bot으로 끝이 나는 이름이면 다 오케이다.

그리고 그 다음

Use this token to access the HTTP API: 

이런 문구와 함께 접근 토큰을 하나 주는데 이 코드는 외부 노출이 되면 안된다.

 

2. 다른 사람 1명과 단톡을 파고 그 안에 봇 계정 초대하기

그 후 단톡을 판 다음에 그 단톡에 봇 계정을 초대한 후 API 키를 사용해 명령어를 내리면 된다.

단톡에는 나랑 봇 2명만 있어도 된다.

이때 한 봇이 여러 채팅방에 있을 수 있기에 할당된 채팅방 아이디를 체크 한 후 해당 채팅방 아이디에 명령어를 내려주어야 활용이 가능하다.

 

https://api.telegram.org/bot123456789:jbd78sadvbdy63d37gda37bd8/getUpdates

챗 아이디를 찾는 방법은 위의 링크에서 bot 뒤에 위에 적혀있는 토큰번호가 아닌 내 토큰 번호를 넣어주면 된다.

그럼 json 형태의 응답값이 나오는데 여기에서 챗 아이디를 확인할 수 있다.

쳇 아이디는 큰 숫자일수도 음수 일수도 있다. 여기서 채팅방 이름에 해당하는 챗 아이디까지 찾아주었다면 이제 다음단계로 넘어 갈 수 있다.

* 그러나 챗 아이디 없이도 전체 채팅 대상으로 봇이 작동하기 때문에 챗 아이디가 필요하지 않다면 (하나의 대화방만 관리하는 것이 아니라면) 굳이 안 넣어줘도 된다.

3. node 모듈로 텔레그램 봇 프로그램 만들기

API와 챗 아이디만 있다면 모듈을 통해서 쉽게 봇을 만들 수 있다.

https://www.npmjs.com/package/node-telegram-bot-api

 

node-telegram-bot-api

Telegram Bot API. Latest version: 0.61.0, last published: 7 months ago. Start using node-telegram-bot-api in your project by running `npm i node-telegram-bot-api`. There are 329 other projects in the npm registry using node-telegram-bot-api.

www.npmjs.com

내가 사용해 볼 모듈은 위의 모듈이다.

 

npm install --save-dev @types/node-telegram-bot-api

먼저 모듈을 설치해주자.

그리고

const TelegramBot = require('node-telegram-bot-api');

// replace the value below with the Telegram token you receive from @BotFather
const token = 'YOUR_TELEGRAM_BOT_TOKEN';

// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, {polling: true});

// Matches "/echo [whatever]"
bot.onText(/\/echo (.+)/, (msg, match) => {
  // 'msg' is the received Message from Telegram
  // 'match' is the result of executing the regexp above on the text content
  // of the message

  const chatId = msg.chat.id;
  const resp = match[1]; // the captured "whatever"

  // send back the matched "whatever" to the chat
  bot.sendMessage(chatId, resp);
});

// Listen for any kind of message. There are different kinds of
// messages.
bot.on('message', (msg) => {
  const chatId = msg.chat.id;

  // send a message to the chat acknowledging receipt of their message
  bot.sendMessage(chatId, 'Received your message');
});

이 기본 템플릿을 사용하면된다. 해당 코드는 위의 npm 설치 페이지에 있는 코드 인데 직접 사용해 보면서 어떤 기능을 하는지 살펴보도록 하겠다.

그리고 프로젝트를 이제 막 시작하는 것이기에 딱 봐도 필요한 모듈들을 몇개 설치해주자.

일단 토큰이 개인정보이기 때문에 노출되면 안되므로 .env를 사용할것이다.

npm i dotenv --save

그리고 봇이 죽으면 안되니까 pm2 도 설치해주자. 지금은 사용하지 않겠지만 나중에는 봇이 죽지 않기 위해서 사용할 것이기에 미리 설치만 해주겠다.

npm i pm2 --save

4.  타입스크립트로 바꿔주기

그리고 난 타입스크립트로 한번 해보려고 하니 ts-node도 설치해주겠다.

npm i ts-node --save

타입도 따로 가져오기 위해 모듈을 추가로 받아주고

npm i @types/node-telegram-bot-api --save

ts config 파일도 만들어 준다.

tsc --init

그리고 아래 블로그를 참고해서 ts config를 조금 고쳐주었다.

https://darrengwon.tistory.com/109

 

Typescript 사용 환경 설정, tsconfig의 속성들

Typescript는 js의 슈퍼셋이며 js로 transpile합니다. 동적 타입 언어인 js를 정적 타입 언어로 사용할 수 있게 됩니다. 물론 동적 언어로 발생할 수 있는 에러를 테스트 코드의 커버리지를 높이는 방식

darrengwon.tistory.com

import TelegramBot from 'node-telegram-bot-api';

// replace the value below with the Telegram token you receive from @BotFather
const token = process.env.TOKEN;

// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token!, { polling: true });

// Matches "/echo [whatever]"
bot.onText(/\/echo (.+)/, (msg: TelegramBot.Message, match: RegExpExecArray | null) => {
    if (match === null) {
      return;  // or handle this situation in another appropriate way
    }
  
    // Your existing logic
    const chatId = msg.chat.id;
    const resp = match[1]; // the captured "whatever"
  
    // send back the matched "whatever" to the chat
    bot.sendMessage(chatId, resp);
  });

// Listen for any kind of message. There are different kinds of
// messages.
bot.on('message', (msg: TelegramBot.Message) => {
  const chatId = msg.chat.id;

  // send a message to the chat acknowledging receipt of their message
  bot.sendMessage(chatId, 'Received your message');
});

@types를 다운 받고 ts config 부분에 이를 잘 지정해주면 노드 모듈을 가져올 시 타입이 알아서 지정되기 때문에 큰 문제가 없었다.

{
  "compilerOptions": {
    "baseUrl": ".", // This is the new line
    "target": "ES2019",                                  
    "module": "commonjs",                                
    "moduleResolution": "node",                         
    "esModuleInterop": true,                             
    "strict": true,                                      
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,                                 
    "typeRoots": ["./node_modules/@types", "./types"],
    "paths": {
      "*": ["node_modules/*"]
    }
  }
}

내가 만든 tsconfig.json 파일은 위와 같다.

 

5.  사용해보기

이제 ts-node로 위의 파일을 실행해 보았더니

다음과 같이 모든 채널에서 봇이 잘 돌아가는 것을 볼 수 있었다.

한번 자기소개 하는 로직을 넣어보고 싶어서 넣어보았더니

잘 작동한다.

  bot.onText(/\/intro/, (msg: TelegramBot.Message) => {
    const intro = "my name is demo telegram bot you can ask me to do anything"
    const chatId = msg.chat.id;
    // send back the matched "whatever" to the chat
    bot.sendMessage(chatId, intro);
  });

코드를 조금 더 살펴보자면

// Matches "/echo [whatever]"
bot.onText(/\/help (.+)/, (msg: TelegramBot.Message, match: RegExpExecArray | null) => {
    if (match === null) {
      return;  // or handle this situation in another appropriate way
    }
    console.log(match);
    // Your existing logic
    const chatId = msg.chat.id;
    const resp = match[1]; // the captured "whatever"
  
    // send back the matched "whatever" to the chat
    bot.sendMessage(chatId, JSON.stringify(match));
  });

해당 코드의 경우 msg 안에 챗 아이디가 들어 있어서 메세지가 온 채팅방에 응답값을 줄 수 있으며

메세지를 입력 받을 경우 해당 메세지를 입력받아와서 무언가를 해주거나

match를 통해서 

[
  '/help introducing',
  'introducing',
  index: 0,
  input: '/help introducing',
  groups: undefined
]

이렇게 입력 받은 값을 input으로 받아올 수 도 있다.

여기 안에 그래서 input값을 잘 짜고 이것저것 하면 재밌는 것을 많이 만들 수 있을 것 같다.

여기서는 Msg안에 chat ID가 있기 때문에 여기서 chatID를 가져와서 다시 응답 값을 보내주고 있는데 이에 따라서 해당 메세지를 보낸 채팅방에다가 다시 응답을 보내 줄 수 있다.

(만약 하나의 채팅방에서만 코드를 짠다면 그냥 chatID를 고정해주고 응답을 주어도 상관이 없다.)

 

728x90
반응형
Comments