app.js 8.01 KB
const TelegramBot = require('node-telegram-bot-api');

const config = require('./config');

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

var request = require('request');

// Translation api url
const translate_api_url = 'https://openapi.naver.com/v1/papago/n2mt';

// Language detection api url
const languagedetect_api_url = 'https://openapi.naver.com/v1/papago/detectLangs'

// Initialize database
const db = require('./db');
db.init();

// /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);
});

/**
 * Translate given message and return the result as a parameter of Promise.
 *
 * @param {*} user    Info of user that sent the message (msg.from)
 * @param {*} message Message to translate
 */
function translate(user, message) {
  return new Promise(function (resolve, reject) {
    const userId = user.id;
    const userLang = user.language_code;

    // Language detection options
    var lang_detect_options = {
      url: languagedetect_api_url,
      form: { 'query': message },
      headers: {
        'X-Naver-Client-Id': config.papago.client_id,
        'X-Naver-Client-Secret': config.papago.client_secret
      }
    };

    // Papago language detection
    request.post(lang_detect_options, function (error, response, body) {
      console.log(response.statusCode);
      if (!error && response.statusCode == 200) {
        var detect_body = JSON.parse(response.body);
        var source = '';
        var target = '';
        var result = { type: 'text', text: '' };

        // Check if detection was successful
        console.log('Language detected: ' + detect_body.langCode);

        // Translate using papago
        // Try to grab source lang and target lang from user's preference first.
        // If preference is not found, source default to detected language, and
        // target defaults to English for Korean source, or Korean for all other langs.
        if (detect_body.langCode != 'unk') {
          db.findPref(userId, "pref", (dbResult) => {
            source = detect_body.langCode;

            if (source == userLang) {
              // User wants to translate his language into another
              // Leave target untouched, which is his desired destination language

              // Check if user target language exists in db, if not default to English
              console.log('Translating to target');
              target = (dbResult != undefined && dbResult.target != undefined)
                ? dbResult.target : 'en';
            } else {
              // source != userLang
              // User wants to translate another language into his
              // Then destination should be his language
              console.log('Translating to userLang');
              target = userLang;
            }

            console.log(source + ' => ' + target);

            // Papago translation options
            var translate_options = {
              url: translate_api_url,
              form: {
                'source': source, // Before translation
                'target': target, // After translation
                'text': message // Message to translate
              },
              headers: {
                'X-Naver-Client-Id': config.papago.client_id,
                'X-Naver-Client-Secret': config.papago.client_secret
              }
            };

            // Send translatation request
            request.post(translate_options, function (error, response, body) {
              var objBody = JSON.parse(response.body);
              if (!error && response.statusCode == 200) {
                // On success
                result.text = objBody.message.result.translatedText;

                console.log('Before: ' + message);
                console.log('After: ' + result.text);
              } else {
                // On failure
                result.text = '[' + objBody.errorCode + '] ' + objBody.errorMessage;
              }
              resolve(result.text);
            });
          });
        }
        // Language not detected
        else {
          result.text = '언어를 감지할 수 없습니다.';
          reject(result.text);
        }
      }
    });
  });
}

// [Any normal message which is not a command (not starting with '/')]
bot.onText(/^(?!\/)((.|\n)+)/, (msg, match) => {
  const user = msg.from;
  const chatId = msg.chat.id;
  const chatType = msg.chat.type;
  const received_msg = match[1];

  // Ignore if we are not on a private chat,
  // since direct translation is to be used only on private chats.
  if (chatType != 'private') {
    return;
  }

  translate(user, received_msg).then(function (result) {
    bot.sendMessage(chatId, result);
  }).catch(function (error) {
    console.log(error);
  });
});

// /t(ranslate) [Whatever]
// Translate the 'whatever' and show the result in any kind of chatroom.
// Also, if the given '/t' message is a reply to another message,
// translate the reply target message as well.
bot.onText(/^\/(t|translate)($| ((.|\n)+))/, (msg, match) => {
  const user = msg.from;
  const chatId = msg.chat.id;
  const chatType = msg.chat.type;
  const received_msg = match[3];
  // Whether the given '/t' message is a reply to another message
  const isReply = msg.reply_to_message != undefined;
  // Whether a message has been given after '/t' command
  const msgExists = received_msg != undefined;

  // Translate the reply's target message
  if (isReply) {
    const replyMsg = msg.reply_to_message.text;
    translate(user, replyMsg).then(function (result) {
      bot.sendMessage(chatId, result);
    }).catch(function (error) {
      console.log(error);
    });
  }

  // Translate the message after '/t' if exists
  if (msgExists) {
    translate(user, received_msg).then(function (result) {
      bot.sendMessage(chatId, result);
    }).catch(function (error) {
      console.log(error);
    });
  }
});

// /l(anguage)
// Let user select the language he wants his message to translate to.
// When triggered, bot will send an inline keyboard message with a list
// of available langauges. For an example of an inline keyboard message,
// see https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating.
bot.onText(/^\/(l|anguage)/, (msg, match) => {
  const chatId = msg.chat.id;
  const msgId = msg.message_id;

  const inlineKeyboard = {
    inline_keyboard: [
      // Languages supported by papago language detection
      // One array per line
      [
        { text: '한국어', callback_data: 'ko' },
        { text: '영어', callback_data: 'en' },
        { text: '일본어', callback_data: 'ja' }
      ],
      [
        { text: '중국어 간체', callback_data: 'zh-CN' },
        { text: '중국어 번체', callback_data: 'zh-TW' },
        { text: '스페인어', callback_data: 'es' }
      ],
      [
        { text: '프랑스어', callback_data: 'fr' },
        { text: '독일어', callback_data: 'de' },
        { text: '베트남어', callback_data: 'vi' }
      ],
      [
        { text: '인도네시아어', callback_data: 'id' },
        { text: '태국어', callback_data: 'th' }
      ],
      [
        { text: '러시아어', callback_data: 'ru' },
        { text: '이탈리아어', callback_data: 'it' }
      ],
    ]
  }
  const options = {
    reply_to_message_id: msgId,
    reply_markup: inlineKeyboard
  }

  bot.sendMessage(chatId, '무슨 언어로 번역할까요? 선택은 기억됩니다.', options);
});

bot.on('callback_query', (query) => {
  const queryId = query.id;
  const userId = query.from.id;
  const langCode = query.data;

  db.updatePref(userId, { "pref": { "target": langCode } }, (result) => {
    const options = {
      text: 'From now on, your messages will be translated into ' + langCode
    }

    bot.answerCallbackQuery(queryId, options);
  })
});