Как создать бота для анализа сообщений в Telegram

Как создать бота для анализа сообщений на Node.js и GigaChat

Рассказываем, как с помощью нейросети создать Telegram-бота, который собирает и обрабатывает информацию с сообщений.

Введение

Есть Telegram-каналы, которые отслеживают определенные события в мире, например, перемещение криптовалют. Если собирать и анализировать данные вручную, процесс будет отнимать много времени и требовать высокой концентрации от человека. Чтобы решить эту проблему, мы решили создать Telegram-бота, который автоматизирует процесс и выдает резюме по собранной информации. 

Пример работы Telegram-бота:


    /sum whale_alert_io Ты - опытный криптоинвестор. Просуммируй мне результат этих сообщений и выдай общую динамику по тому, что происходит

/sum — команда обращения к боту, whale_alert_io — ID канала (можно подставить любой), остальной текст — произвольная команда для робота.

Авторизация

Первым делом нужно авторизовать аккаунт, чтобы получить доступ к сообщениям бота. Через бота такой функционал недоступен, поэтому будем использовать библиотеку GramJS

Заходим на my.telegram.org, открываем API development tools и создаем приложение. 

В ответе получаем параметры apiId и apiHash. Подставляем данные в код авторизации:


    const { TelegramClient } = require('telegram')
const input = require('input')
const { StringSession } = require('telegram/sessions')

const session = new StringSession('')
const apiId = 123 // подставляем данные из Telegram
const apiHash = 'abc' // подставляем данные из Telegram

;(async () => {
  console.log('Loading interactive example...')
  const client = new TelegramClient(session, apiId, apiHash, {
    connectionRetries: 5,
  })
  await client.start({
    phoneNumber: async () => await input.text('Please enter your number: '),
    password: async () => await input.text('Please enter your password: '),
    phoneCode: async () =>
      await input.text('Please enter the code you received: '),
    onError: (err) => console.log(err),
  })
  console.log('You should now be connected.')
  console.log(client.session.save()) // в консоли получим строчку, которую нужно будет сохранить
})()

auth.js.

Консоль попросит номер телефона, пароль и код подтверждения — заполняем данные и получаем строку сессии. Ее нужно сохранить, чтобы не авторизироваться каждый раз. 

Запускаем на Node.js функцию node auth, чтобы получить ключ авторизации и продолжить работу с запросами к Telegram. 

Реализация функционала

Добавим в Telegram-бот функцию поиска непрочитанных сообщений. Для этого инициализируем client с уже сохраненной сессей. После — используем метод getUnreadMessages:


    const { TelegramClient } = require('telegram')
const { NewMessage } = require('telegram/events')
const { session, apiId, apiHash} = require('./config')

const client = new TelegramClient(session, apiId, apiHash, {})

async function getUnreadMessages(channelId, limit = 10) {
  const dialogs = await client.getDialogs({}) // получаем все чаты
  const channel = dialogs.find((d) => d.entity.username === channelId) // находим нужный по ID
  if (channel) { // если канал найдет
    const messages = await client.getMessages(channel.entity, { // получаем список сообщений
      // limit: channel.unreadCount, // можем прочесть количество непрочитанных сообщений
      limit, // сколько сообщений получаем
    })
	  console.log(messages.map((m) => m.message).join(' ')) // выводим в консоль
  } else {
    console.log('Канал не найден')
  }
}

;(async function run() {
  // const channel = 'whale_alert_io'
  // watchNewMessages(channel) // важно, чтоб метод был до client.connect

  await client.connect()

  await getUnreadMessages(channelId, 10)
})()

Чтобы бот анализировал не только непрочитанные, но и новые сообщения в чатах, можно использовать метод watchNewMessages:


    function watchNewMessages(channelId) {
  client.addEventHandler((event) => {
    console.log('new message', event.message.message)
  }, new NewMessage({ fromUsers: [channelId] }))
}

Пропускаем сообщения через нейросеть

Мы будем использовать GPT-модель GigaChat, которая предоставляет бесплатно до 1 млн токенов. Чтобы начать работу с API, нужно узнать значения clientID и clientSecret.

  1. Регистрируемся на сайте GigaChat API и создаем проект. 
  2. В панели справа находится поле Client ID — копируем значение.
Поле Client ID. Источник
  1. Нажимаем Получить Client Secret, чтобы сгенерировать новый секрет. 
Окно с Client Secret. Источник

Алгоритм работы модели простой. Сначала отправляем запрос на получение токена. Затем делаем запрос к чату с имеющимся токенов. Ниже — пример, как реализован функционал в нашем боте: 


    const { gigaAuth } = require('./config')
const { v4: uuidv4 } = require('uuid')
const axios = require('axios')
const qs = require('qs')

// метод для получение токена
async function getToken() {
// конфиг запроса
  const config = {
    method: 'post',
    maxBodyLength: Infinity,
    url: '<https://ngw.devices.sberbank.ru:9443/api/v2/oauth>',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Accept: 'application/json',
      RqUID: uuidv4(),
      Authorization: `Basic ${gigaAuth}`,
    },
    data: qs.stringify({
      scope: 'GIGACHAT_API_PERS'
    }),
  }

  try {
    const response = await axios(config)
    const { access_token: accessToken, expires_at: expiresAt } = response.data

    return { accessToken, expiresAt }
  } catch (error) {
    console.log(error)
  }
}

// выполняем запрос к модели уже с токеном
async function giga(content = '', system = '') {
  if (!content) return

  // получаем токен
  const token = await getToken()

  const messages = []

	// если передавали контекст, то добавляем его как системное сообщение.
  // здесь мы говорим как чату себя вести
  if (system) {
    messages.push({ role: 'system', content: system })
  }

	// формируем данные для обращения
  const data = JSON.stringify({
    model: 'GigaChat',
    messages: messages.concat([
      {
        role: 'user',
        content,
      },
    ]),
    temperature: 1,
    top_p: 0.1,
    n: 1,
    stream: false,
    max_tokens: 512,
    repetition_penalty: 1,
    update_interval: 0,
  })

	// настраиваем запрос
  const config = {
    method: 'post',
    maxBodyLength: Infinity,
    url: '<https://gigachat.devices.sberbank.ru/api/v1/chat/completions>',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      Authorization: `Bearer ${token.accessToken}`,
    },
    data,
  }

	// выполняем запрос возвращая ответ самого чата
  try {
    const response = await axios(config)
    const message = response.data.choices[0].message
    return message.content
  } catch (e) {
    console.log(e)
  }
}

module.exports = { giga }

giga.js.

Устанавливаем Telegraf, чтобы добавить интерфейс программы в Telegram-бот:


    npm i telegraf

Далее получаем токен для @BotFather и создаем Telegram-бота. Вот пример финального файла функционала:


    const { TelegramClient } = require('telegram')
const { Telegraf } = require('telegraf')
const { NewMessage } = require('telegram/events')
const { session, apiId, apiHash, botToken } = require('./config')
const { giga } = require('./giga')

// создаем бота
const bot = new Telegraf(botToken)

const client = new TelegramClient(session, apiId, apiHash)

async function getUnreadMessages(channelId, limit = 10) {
  const dialogs = await client.getDialogs({})
  const channel = dialogs.find((d) => d.entity.username === channelId)
  if (channel) {
    const messages = await client.getMessages(channel.entity, {
      limit,
    })
    return messages.map((m) => m.message).join(' ')
  } else {
    console.log('Канал не найден')
  }
}

;(async function run() {
  await client.connect()

	// слушаем команду sum
  bot.command('sum', async (ctx) => {
		// получаем как параметры ID-канала и сообщение для GPT
    const [, channelId, ...task] = ctx.message.text.split(' ')
    if (!channelId) {
      return ctx.reply(`Вы не указали канал`)
    }

		// получаем строку из сообщений в канале
    const messagesString = await getUnreadMessages(channelId, 10)
		// передаем роль и сообщения из канала в GigaChat
    const gigaResponse = await giga(messagesString, task.join(' '))
		// отправляем пользователю ответ от GigaChat с анализом
    await ctx.reply(gigaResponse)
  })

  bot.launch()
})()

Деплой

Чтобы Telegram-бот был всегда под рукой, задеплоим его в облако Selectel. Для этого переносим шаблон кода в Git:


    git init
git add .
git commit -m “init”
git push -u origin master

Далее заходим в панель управления my.selectel.ru. Переходим из Облачной платформы в Серверы и нажимаем Создать сервер.

Далее настраиваем параметры сервера.

  • Источник: Ubuntu 22.04 LTS 64-bit.
  • Конфигурация: фиксированная, Shared.
  • Доля vCPU: 20% (4 vCPU, 8 ГБ RAM).

После инициализации сервера нужно его настроить. Устанавливаем Git и загружаем репозиторий. 


    apt update
apt install git
git clone REPO_NAME

После устанавливаем Node.js и NPM через NVM. Подробнее об этом рассказывали в предыдущей статье.

Чтобы запустить программу, устанавливаем Node.js на Ubuntu 20.04:


    nvm install 20
nvm use 20
cd REPO_NAME
npm install

Далее устанавливаем PM2 для работы бота в фоновом режиме:


    npm install pm2 -g
pm2 start main

Готово. Теперь бот работает и вы можете анализировать Telegram-каналы и переписки!

Автор: Владилен Минин, создатель YouTube-канала.