Как я создал HR Slack Bot из Node и Botkit

1656537252 kak ya sozdal hr slack bot iz node i botkit

Зачем производить Slack Bot?

Я специалист по персоналу. Вернее, я консультант информационной системы человеческих ресурсов (HRIS). Я работаю с системами отслеживания приложений, системами управления обучением и Core HR. Но мне никогда не приходилось работать с HR-ботом. Каково может быть будущее HR.

Я много читал о ботах у Slack и Messenger и использовал некоторые из них в своей повседневной жизни – Product Hunt, GitHub и Trello. Но для HR у меня никогда не было возможности работать с инструментом, приспособленным к моим потребностям.

Потому я решил поработать над собственным ботом.

1*cyhNkd0jd7Zd3zBDLaKpSg
Я начинаю работать

Мои цели

Мой бот должен быть в состоянии управлять всеми потребностями небольшой компании в Slack:

  • Онбординг
  • Связывание людей
  • Напоминание
  • Объявления
  • Дни рождения / Юбилей
  • И многое другое

Просмотр оснований

Для этой программы я буду использовать:

  • боткит
  • Узел JS
  • Экспресс-сервер
  • MongoDB
  • Slack API и, конечно

Боткит – это:

Одним из простых способов создания пользователей-ботов, особенно если вы уже работаете с Node.js, является Howdy’s боткит. Боткит – это фреймворк, обслуживающий большинство этих API гимнастики, поэтому вы можете сосредоточиться на поведении своего бота.

Именно то, что я искал 🙂

Боткит дает шаблон для Slack. Но я решил начать с нуля, чтобы лучше понять свой бот. Однако это хорошая идея потренироваться с помощью бота, созданного на Glitch.

Как работают боты Slack?

Я не эксперт. Я снова и снова читал официальную документацию Slack и Botkit. Я все еще не уверен, что все понял. Вот мое понимание поведения бота Slack:

Каждая программа Slack имеет «сферу», которая является периметром, на котором программа может читать или выполнять действия. Бот является частью программы, созданной и установленной на Slack.

Поэтому, когда вы устанавливаете программу Slack, вы предоставляете доступ к определенной информации и разрешения к ней. Для вашего бота вы хотите, чтобы он мог по крайней мере отправлять сообщения другим пользователям и отвечать на них.

Тогда есть два случая:

  1. Вы хотите, чтобы ваш бот реагировал на события непосредственно в Slack
  2. Вы хотите, чтобы ваш бот реагировал на события на вашем сервере

Мы рассмотрим их обоих в этой публикации!

Начинаем

Прежде всего вам понадобится сервер. В моем случае Экспресс.

Ниже вы найдете мой файл server.js:

var express = require('express');
var app = express();
var http = require('http').Server(app);
var dotenv = require('dotenv');

// configuration ===========================================
//load environment variables,
dotenv.load();

// public folder for images, css,...
app.use(express.static(__dirname + '/public'))

//parsing
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({
    extended: true
})); //for parsing url encoded

// view engine ejs
app.set('view engine', 'ejs');

// routes
require('./routes/routes')(app);

//botkit
require('./controllers/botkit')


//START ===================================================
http.listen(app.get('port'), function() {
    console.log('listening on port ' + app.get('port'));
});

Этот порт должен быть общедоступным и доступным, а не только на локальном хосте.

На данный момент сервер является пустой страницей, которая ничего не показывает и не обрабатывает.

Тогда вам понадобится приложение Slack: просто перейдите по этой ссылке, чтобы создать его.

Затем вам придется настроить свой контроллер. Контроллер – это мозг вашего бота. Он содержит все навыки и конфигурацию. Ниже представлен мой файл botkit.js. Он имеет почти то же содержимое, которое можно найти в стартовом наборе Botkit, доступном здесь: https://github.com/howdyai/botkit-starter-slack

var mongoUri = 'mongodb://localhost:27017/nameofyourDB'
var database = require('../config/database')({
    mongoUri: mongoUri
})
var request = require('request')

if (!process.env.SLACK_ID || !process.env.SLACK_SECRET || !process.env.PORT) {
    console.log('Error: Specify SLACK_ID SLACK_SECRET and PORT in environment');
    process.exit(1);
}

var controller = Botkit.slackbot({
    storage: database,
    clientVerificationToken: process.env.SLACK_TOKEN
})

exports.controller = controller
   
//CONNECTION FUNCTIONS=====================================================

exports.connect = function(team_config) {
        var bot = controller.spawn(team_config);
        controller.trigger('create_bot', [bot, team_config]);
    }
    // just a simple way to make sure we don't
    // connect to the RTM twice for the same team
var _bots = {};

function trackBot(bot) {
    _bots[bot.config.token] = bot;
}

controller.on('create_bot', function(bot, team) {
    if (_bots[bot.config.token]) {
        // already online! do nothing.
        console.log("already online! do nothing.")
    } else {
        bot.startRTM(function(err) {
            if (!err) {
                trackBot(bot);
                console.log("RTM ok")
                controller.saveTeam(team, function(err, id) {
                    if (err) {
                        console.log("Error saving team")
                    } else {
                        console.log("Team " + team.name + " saved")
                    }
                })
            } else {
                console.log("RTM failed")
            }
            bot.startPrivateConversation({
                user: team.createdBy
            }, function(err, convo) {
                if (err) {
                    console.log(err);
                } else {
                    convo.say('I am a bot that has just joined your team');
                    convo.say('You must now /invite me to a channel so that I can be of use!');
                }
            });
        });
    }
});

//REACTIONS TO EVENTS==========================================================
// Handle events related to the websocket connection to Slack

controller.on('rtm_open', function(bot) {
    console.log('** The RTM api just connected!')
});

controller.on('rtm_close', function(bot) {
    console.log('** The RTM api just closed');
    // you may want to attempt to re-open
});

Разблокировка первого случая: реагируйте на события, происходящие на Slack

1*51uJInZFmmF_0gD3ICFr9Q

Когда вы предоставляете правильные разрешения своей программе, когда сообщение отправляется на канал, Slacks посылает запрос на ваш сервер с определенной информацией — идентификатор канала, пользователя, отметку времени и, самое главное, содержимое сообщения.

Если мы хотим, чтобы наш бот реагировал на простое сообщение типа «Привет», мы должны предоставить Slack адрес для отправки информации.

В файл routes.js напишите:

var Request = require('request')
var slack = require('../controllers/botkit')
module.exports = function(app) {
 app.post('/slack/receive', function(req,res){
//respond to Slack that the webhook has been received.
    res.status(200);
// Now, pass the webhook into be processed
    slack.controller.handleWebhookPayload(req, res)
  })
}

Теперь у нас есть вебхук: http://your-ip-or-domain:port/slack/receive

Как только Slack получит информацию об этом маршруте на странице подписок на события приложения Slack, он сможет прислать ему JSON. Вы сможете получить его благодаря разбору части файла server.js выше.

Вот (простая) схема, чтобы объяснить стоящий за ней процесс:

1*c-Km3PgTIihfbthJC0BFfw

1- SLACK « Вот файл JSON с последним событием на вашем канале Slack »

2- СЕРВЕР «Хорошо хорошо принято, отправляю в Botkit»

3- БОТКИТ «Вот временный ответ, подождите секунду»

4- БОТОК «Да! Я слышу ключевое слово, вот объект JSON с действием, которое нужно выполнить.

Если мы хотим, чтобы наш бот реагировал каждый раз, когда он слышит Hello, мы можем просто добавить эту функцию .hears() к нашему контроллеру:

controller.hears(['hello', 'hi'], 'direct_message,direct_mention,mention', function(bot, message) {
controller.storage.users.get(message.user, function(err, user) {
        if (user && user.name) {
            bot.reply(message, 'Hello ' + user.name + '!!');
        } else {
            bot.reply(message, 'Hello.');
        }
    });
});

Обратите внимание на storage.users.get() часть этого фрагмента. Боткит совместим почти со всеми системами баз данных, доступными на рынке. Я решил использовать MongoDB, поскольку он был в моем списке обучения в течение длительного времени. Кроме того, документация по Botkit подробная.

Теперь мы должны позволить своему воображению поработать и найти несколько интересных функций для создания.

Второй случай: начните разговор со своим ботом

1*pEUkhsJtGgYrzGvq0xf57Q

Для этой функции я хотел, чтобы мой бот реагировал на события, которые не были инициированы в Slack. К примеру, выполняйте распорядок дня. Если это чей-то юбилей в компании, отправьте ему опрос, чтобы спросить его чувства об их первых месяцах/неделях.

Я решил использовать node-cron: для управления ежедневной проверкой.

Ниже приведена стрельба cronjob каждый будний день в 9:00. Благодаря методу Date() бот получает сегодняшнюю дату и может сравнить ее с «joinedDate» пользователя.

Чтобы получить только нужных пользователей и избежать цикла forEach, мы можем использовать запрос в нашу базу данных:

var dailyCheck = new CronJob('00 00 9 * * 1-5', function() {
        /*
         * Runs every weekday (Monday through Friday)
         * at 09:00:00 AM. It does not run on Saturday
         * or Sunday.
         */
        console.log(`DailyCheck triggered ${new Date()}`)
        
        //Gets today's date
        let d = new Date()
        d.setUTCHours(0, 0, 0, 0)
        
        let threeMonthsAgo = new Date()
        threeMonthsAgo.setUTCMonth(d.getUTCMonth() - 3)
        threeMonthsAgo.setUTCHours(0, 0, 0, 0)


        let sevenDaysAgo = new Date()
        sevenDaysAgo.setUTCDate(d.getUTCDate() - 7)
        sevenDaysAgo.setUTCHours(0, 0, 0, 0)


        controller.storage.users.find({
            "joinedDate": {
                "$eq": +sevenDaysAgo
            }
        }, function(err, user) {
            user.forEach(function(member) {
                console.log(`Message was sent to ${member.name}(${member.id})`)
                bot.startPrivateConversation({
                    user: member.id
                }, Conversations.sendSurvey7)
            })
        })
    }, function() {
        /* This function is executed when the job stops */
    }, true,
    /* Start the job right now */
    timeZone="Europe/Paris" /* Time zone of this job. */ )

И… Тогда!

0*MSZ0zXebVZ_wwCKP
«Робот по имени Пеппер держит iPad» Алекса Найта на Unsplash

Вывод

После более чем года работы в лагере и обучении коду я очень счастлив, что могу начать и закончить такой проект, как этот. Теперь у меня работает бот и выполняет почти все действия, которые я подразумевал на этапе проектирования. А у меня еще много идей!

Я все еще работаю над этим роботом. Репозиторий GitHub доступен здесь: некоторые комиты написаны на французском языке, но кодовая база прокомментирована на английском. 🙂

Кроме того, его достаточно легко развернуть на Heroku с базой данных Mongolab, если у вас сервера нет!

Если у вас есть предложения или вас заинтересовала эта статья и проект, не стесняйтесь оставлять комментарии! Буду рад обсудить с вами.

Добавить комментарий

Ваш адрес email не будет опубликован.