15분이면 모든 질문에 답할 수 있는 텔레그램 봇을 만들 수 있습니다.

소개



지난 기사에서 우리는 ,
좋은 반응으로 인해 저는 15분의 다른 도전을 가져오기로 결정했습니다. 오늘은 Genius라는 텔레그램 봇입니다.

규칙:



- interact with the system by telegram chat (Obviously)
- Searches must be carried out using wikipedia
- The robot must be able to change its response if it is not satisfactory to the user

시작하자


프로젝트 만들기



프로젝트에 폴더를 만들고 터미널에서 다음 명령을 실행합니다.npm init -y && npx ts-inittsconfig.json 파일이 다음과 같은지 확인하십시오.

{
  "compilerOptions": {
    "lib": [
      "es6",
      "DOM"
    ],
    "alwaysStrict": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "esModuleInterop": true,
    "resolveJsonModule": true
  },
  "files": [
    "src/index.ts"
  ]
}


패키지를 받자


  • npm i node-telegram-bot-api --save && npm i @types/node-telegram-bot-api -D node-telegram-bot-api은 Telegram Bot API를 추상화하고 우리의 삶을 더 쉽게 만들어주는 놀라운 라이브러리입니다.
  • npm i wikipedia --save Wikipedia은 위키 끝점을 추상화하는 간단한 라이브러리입니다.

  • 봇 만들기


  • 텔레그램을 열고 다음을 검색하십시오.


  • 대화를 열고 시작을 클릭합니다.

  • 유형 /newBot
  • 텔레그램 지침에 표시된 대로 일반 이름과 로봇 이름을 지정합니다.

  • 나중에 사용할 수 있도록 토큰 키를 특정 위치에 저장합니다.

  • 코딩하자



    우선 사용할 라이브러리를 가져와야 하므로 src/index.ts라는 파일을 만듭니다.

    import telegram from 'node-telegram-bot-api';
    import wikipedia from 'wikipedia';
    
    const TELEGRAM_KEY = "YOUR-API-KEY-HERE";
    


    YOUR-API-KEY-HERE가 쓰여진 위치를 로봇 키로 바꾸는 것을 잊지 마십시오.

    일부 상호 작용 만들기



    이 코드를 src/index.ts 안에 붙여넣으세요.

    ...
    const Bot = new telegram(TELEGRAM_KEY, {polling: true});
    
    Bot.onText(/\/start/, async (msg) => {
        if(!msg.from) return Bot.sendMessage(msg.chat.id, 'I not accept you!');
        Bot.sendMessage(msg.chat.id, 'Wellcome to GeniusAnswer, ask me something');
    });
    


    사용자가 봇을 시작하면 사용자에게 질문을 요청하는 메시지를 보냅니다.

    주요 기능



    이 코드를 src/index.ts 안에 붙여넣으세요.

    ...
    const wikisearch = async (topic: string, pageIndex: number) => {
        const search = await wikipedia.search(topic);
    
        if(pageIndex > search.results.length) throw new Error('Invalid page index');
    
        const page = await wikipedia.page(search.results[pageIndex].title);
    
        const summary = await page.summary();
    
        return {text: summary.extract, pageIndex: 0, pageLength: search.results.length};
    };
    
    Bot.on("text", async (msg) => {
      if (!msg.from) return Bot.sendMessage(msg.chat.id, "I not accept you!");
      if (!msg.text) return Bot.sendMessage(msg.chat.id, "Invalid message");
      if (msg.text[0] === "/") return;
    
      Bot.sendMessage(msg.chat.id, `Searching for ${msg.text} ...`);
    
      const search = await wikisearch(msg.text, 0);
    
      console.log(search);
    
      let options_button = {};
      if (search.pageIndex < search.pageLength) {
        options_button = {
          reply_markup: {
            inline_keyboard: [
              [
                {
                  text: "Next Answer ->",
                  callback_data: JSON.stringify({ topic: msg.text, pageIndex: 1 }),
                },
              ],
            ],
          },
        };
      }
    
      return Bot.sendMessage(
        msg.chat.id,
        `${search.text} \n Answer ${search.pageIndex + 1}/${search.pageLength}`,
        options_button
      );
    });
    
    });
    


    여기서는 Wikipedia에서 검색하고 이 결과의 인덱스를 반환할 수 있는 검색 함수만 만듭니다. 이 질문에 대해 다른 결과가 필요한 경우 함수에 대한 다른 인덱스만 전달하면 됩니다.
    다음 기능에서 봇으로 보내는 문자 메시지를 수신하고 결과에 검색 색인을 변경할 수 있는 버튼을 넣습니다.

    콜백 함수



    이 코드를 src/index.ts 안에 붙여넣으세요.

    ...
    Bot.on("callback_query", async (callback) => {
      if (!callback.data || !callback.message) return;
    
      console.log(callback.data);
    
      const data = JSON.parse(callback.data) as {
        topic: string;
        pageIndex: number;
      };
    
      try {
        const search = await wikisearch(data.topic, data.pageIndex);
    
        console.log(search);
    
        let options_button = {};
        let inline_keyboard_buttons = [];
        if (search.pageIndex + 1 < search.pageLength) {
          inline_keyboard_buttons.unshift({
            text: "Next Answer ->",
            callback_data: JSON.stringify({
              topic: data.topic,
              pageIndex: search.pageIndex + 1,
            }),
          });
    
          if (search.pageIndex > 0) {
            inline_keyboard_buttons.unshift({
              text: "<- Previous Answer",
              callback_data: JSON.stringify({
                topic: data.topic,
                pageIndex: search.pageIndex - 1,
              }),
            });
          }
        } else if (search.pageIndex + 1 === search.pageLength) {
          inline_keyboard_buttons.unshift({
            text: "<- Previous Answer",
            callback_data: JSON.stringify({
              topic: data.topic,
              pageIndex: search.pageIndex - 1,
            }),
          });
        }
    
        if (inline_keyboard_buttons.length > 0) {
          options_button = {
            reply_markup: {
              inline_keyboard: [inline_keyboard_buttons],
            },
          };
        }
    
        return Bot.editMessageText(
          `${search.text} \n Answer ${search.pageIndex + 1}/${search.pageLength}`,
          {
            chat_id: callback.message.chat.id,
            message_id: callback.message.message_id,
            ...options_button,
          }
        );
      } catch (error) {
        return Bot.editMessageText(
          "Sorry, an error seems to have happened, please try again later",
          {
            chat_id: callback.message.chat.id,
            message_id: callback.message.message_id,
          }
        );
      }
    });
    


    콜백 함수가 매우 길지만 이해하기 쉽습니다. 검색 주제를 캡처하고 인덱스를 변경합니다. 다음 또는 이전 페이지가 있는지 여부에 따라 메시지에 해당 버튼을 추가합니다.

    이제 코드는 다음과 같아야 합니다.




    import telegram from "node-telegram-bot-api";
    import wikipedia from "wikipedia";
    
    const TELEGRAM_KEY = "YOUR-TELEGRAM-KEY-HERE";
    
    const Bot = new telegram(TELEGRAM_KEY, { polling: true });
    
    Bot.onText(/\/start/, (msg) => {
      if (!msg.from) return Bot.sendMessage(msg.chat.id, "I not accept you!");
      Bot.sendMessage(msg.chat.id, "Wellcome to GeniusAnswer, ask me something");
    });
    
    const wikisearch = async (topic: string, pageIndex: number) => {
      const search = await wikipedia.search(topic);
    
      if (pageIndex > search.results.length) throw new Error("Invalid page index");
    
      const page = await wikipedia.page(search.results[pageIndex].title);
    
      const summary = await page.summary();
    
      return {
        text: summary.extract,
        pageIndex: pageIndex,
        pageLength: search.results.length,
      };
    };
    
    Bot.on("text", async (msg) => {
      if (!msg.from) return Bot.sendMessage(msg.chat.id, "I not accept you!");
      if (!msg.text) return Bot.sendMessage(msg.chat.id, "Invalid message");
      if (msg.text[0] === "/") return;
    
      Bot.sendMessage(msg.chat.id, `Searching for ${msg.text} ...`);
    
      const search = await wikisearch(msg.text, 0);
    
      console.log(search);
    
      let options_button = {};
      if (search.pageIndex < search.pageLength) {
        options_button = {
          reply_markup: {
            inline_keyboard: [
              [
                {
                  text: "Next Answer ->",
                  callback_data: JSON.stringify({ topic: msg.text, pageIndex: 1 }),
                },
              ],
            ],
          },
        };
      }
    
      return Bot.sendMessage(
        msg.chat.id,
        `${search.text} \n Answer ${search.pageIndex + 1}/${search.pageLength}`,
        options_button
      );
    });
    
    Bot.on("callback_query", async (callback) => {
      if (!callback.data || !callback.message) return;
    
      console.log(callback.data);
    
      const data = JSON.parse(callback.data) as {
        topic: string;
        pageIndex: number;
      };
    
      try {
        const search = await wikisearch(data.topic, data.pageIndex);
    
        console.log(search);
    
        let options_button = {};
        let inline_keyboard_buttons = [];
        if (search.pageIndex + 1 < search.pageLength) {
          inline_keyboard_buttons.unshift({
            text: "Next Answer ->",
            callback_data: JSON.stringify({
              topic: data.topic,
              pageIndex: search.pageIndex + 1,
            }),
          });
    
          if (search.pageIndex > 0) {
            inline_keyboard_buttons.unshift({
              text: "<- Previous Answer",
              callback_data: JSON.stringify({
                topic: data.topic,
                pageIndex: search.pageIndex - 1,
              }),
            });
          }
        } else if (search.pageIndex + 1 === search.pageLength) {
          inline_keyboard_buttons.unshift({
            text: "<- Previous Answer",
            callback_data: JSON.stringify({
              topic: data.topic,
              pageIndex: search.pageIndex - 1,
            }),
          });
        }
    
        if (inline_keyboard_buttons.length > 0) {
          options_button = {
            reply_markup: {
              inline_keyboard: [inline_keyboard_buttons],
            },
          };
        }
    
        return Bot.editMessageText(
          `${search.text} \n Answer ${search.pageIndex + 1}/${search.pageLength}`,
          {
            chat_id: callback.message.chat.id,
            message_id: callback.message.message_id,
            ...options_button,
          }
        );
      } catch (error) {
        return Bot.editMessageText(
          "Sorry, an error seems to have happened, please try again later",
          {
            chat_id: callback.message.chat.id,
            message_id: callback.message.message_id,
          }
        );
      }
    });
    


    이제 코드가 완성되었습니다. 테스트해 볼까요?

    터미널에서 npm run ts를 실행하고 텔레그램을 엽니다.
    봇 이름(이 문서의 시작 부분에서 만든 것과 동일하며 일반적으로 _bot으로 끝남)을 검색하고 START를 누릅니다.

    너 자신을 즐겨!

    이 로봇의 응답 시간을 최적화하는 몇 가지 방법이 있습니다. 관심이 있으시면 나중에 다른 기사에서 보여줄 수 있지만 로봇 아이디어를 좋아하는 사람들에게는 이것이 흥미로운 도전이라고 생각합니다. 댓글에 남겨주세요. 당신의 솔루션과 아이디어

    좋은 웹페이지 즐겨찾기