Автор оригинала: Aaron Gerard Franco.
Оглавление
Начиная Принимая веб-капоны Обработка естественного языка Контекст и управление сессией Развертывание AWS. Заключение
Начиная
Вы когда-нибудь задавались вопросом, как сделать бот? Этот прохождение проведет вас через процесс разработки вашего собственного чата для мессенджера с нуля – никаких удобных библиотек или ботов построения платформ. Инструменты, которые мы будем использовать, чтобы сделать Chatbot, включают в себя:
- Node.js 6.x.
- Express 4.x Framework
- Http.
- Редис
- Ec2.
- Mysql? Монгодб?
- Неисполнительно
Предпосылки:
- Опыт работы с JavaScript и Node.js
- Желание работать с HTTP и REST APIS
- Желание построить чатбот на платформе Facebook.
- Приложение Facebook
- неисполнительно
- Node.js.
- Счет с API.ai
- Аккаунт AWS.
- Github или Bitbucket с учетом знаний о том, как использовать Git для управления кодом.
Лучший способ начать работу со зданием Chatbot – создать приложение на Facebook Developer Platform Отказ Это руководство должно приготовить ваше приложение Facebook, но для того, чтобы проверить его, вам нужно будет разработать веб -ook. Это будет главная точка входа для нашего бота. Все сообщения и данные из Facebook придут к нашему приложению через эту конечную точку HTTP. Чтобы проверить веб-капусты, нам нужен сервер для пересылки Live WebHooks к нашему localhost. Для живого тестирования мы будем использовать услугу, называемую NGROK.
Начнем с создания нашего конечной точки Node.js. Во-первых, вам нужно установить Node.js. Вы можете скачать его в nodejs.org Отказ После установки Node.js и NPM мы создадим новую папку для вашего проекта – мы назовем эту папку /База в остальной части поста.
Внутри папки/Base создайте новый файл под названием «Package.json». Скопируйте и вставьте следующий контент в этот файл и сохраните его в папке/Base.
{ "name": "Messenger-Bot-Architecture-and-Design", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { } }
Теперь откройте терминал и введите следующие команды.
> npm install --save express > npm install --save body-parser > npm install --save multer
Откройте редактор кода и создайте новый файл под названием «App.JS.» Это будет сервер Node.js для нашего чата. Добавьте следующий код в свой файл App.js:
var express = require('express'), bodyParser = require('body-parser'), http = require('http'), app = express(); // set port app.set('port', process.env.PORT || 8080); // create a health check endpoint app.get('/health', function(req, res) { res.send('okay'); }); // start the server http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
Откройте терминал и выполните следующую команду.
npm start
Откройте браузер и перейдите в http://localhost: 8080/здоровье – Вы должны увидеть слово «хорошо» напечатано в окно браузера.
Откройте другое окно терминала, поэтому у вас есть два открытых в папке/Base. В терминале 1 запустите свой Node.js Server с этой командой:
npm start
В Terminal 2 выполните эту команду, но замените «
ngrok http 8080
NGROK распечатает информацию о вашей учетной записи и сервере с доменом, который вы можете отправлять запросы.
Теперь, когда вы открываете домен http://xxx.ngrok.io/health Вы должны увидеть слово «хорошо» напечатано на ваш экран.
Итак, теперь у нас есть рабочий сервер, который подвергается общественному доступу. Теперь нам нужна новая конечная точка, которая принимает последующие запросы.
Давайте добавим код на наш сервер и измените свой сервер, чтобы он выглядел как следующий код:
var express = require('express'), bodyParser = require('body-parser'), http = require('http'), app = express(); app.use(bodyParser.json()); // set port app.set('port', process.env.PORT || 8080); // create a health check endpoint app.get('/health', function(req, res) { res.send('okay'); }); app.post('/fb', function(req,res){ res.send(req.body) }) // start the server http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
Принимая веб-капоны
Для того, чтобы Facebook для проверки нашего сервера нам необходимо создать другой Get EndPoint, который проверяет токен Отправить с экрана конфигурации веб-канала Facebook Messenger.
Добавьте этот код на свой сервер:
app.get('/fb', function(req, res) { if (req.query['hub.verify_token'] === 'abc') { res.send(req.query['hub.challenge']); } else { res.send('Error, wrong validation token'); } });
Вы должны использовать более сильный токен, чем «ABC» (как показано выше) – я выбрал «ABC» просто для демонстрационных целей. Когда вы нажимаете «Проверьте и сохранить», ваш WebHook должен быть принят Facebook.
Теперь вы должны увидеть это в вашем приложении Facebook:
В разделе WebHooks выберите страницу из падения, затем нажмите, чтобы подписаться на события Messenger для этой страницы. Вы должны увидеть что-то похожее на следующее в разделе «Веб-вики» вашего конфигурации приложения Facebook:
Теперь в разделе «Генерация токена» выберите страницу, на которую вы только что подписались, и скопируйте генерируемые токен Facebook.
Создайте новую переменную на своем сервере, чтобы сохранить токен.
Var token = "xxxxxxx"
Сервер понадобится этот токен для отправки сообщений в Facebook от имени пользователей, отправляющих сообщения на ваш чатбот. Теперь мы должны иметь возможность отправлять сообщения на нашу страницу и увидеть, как сообщения появляются на консоли нашей сервера, потому что мы добавили строку Console.log (req.body)
на нашу конечную точку WebHook. Когда вы просматриваете журнал, вы должны увидеть что-то вроде этого:
{ object: 'page', entry: [ { id: 'xxx', time: 1489404379192, messaging: [Object] } ] }
Нам пришлось бы добавить Json.stringify
Для просмотра всего объекта из Facebook. Изменить console.log
Строка на вашей конечной точке вашего сообщения, чтобы использовать Json.stringify
Отказ Конечная точка Post должна выглядеть следующим кодом:
app.post('/fb', function(req, res){ console.log(JSON.stringify(req.body)) res.send(req.body) })
Теперь, когда вы отправляете сообщение на свой бот, вы должны увидеть что-то похожее на этот JSON, напечатанный в консоли вашего сервера. Это req .body
В сервере кода.
{ "object": "page", "entry": [ { "id": "137101496360273", "time": 1489404570380, "messaging": [ { "sender": { "id": "xyz" }, "recipient": { "id": "xyz" }, "timestamp": 1489404570341, "message": { "mid": "mid.1489404570341:ce017e2f89", "seq": 72281, "text": "Hi" } } ] } ] }
Вы заметите, что «ввод» ключ объекта является массивом. Вы также увидите, что Вход [0]. Промежуток
это массив. Итак, чтобы добраться до нашего текста и отправителя, мы должны использовать следующую запись JSON.
Отправитель: req.body.entry [0]. Удача [0] .sender.id
Текст: req.body.entry [0]. Удача [0] .message.text
Отправка сообщения ответов
Для того, чтобы наш чатбент ответить на пользователя, нам нужно отправить запрос HTTP Post с токеном доступа страницы в Facebook. Для этого я буду использовать модуль Node.js «Запрос». Остановите свой сервер и выполните следующую команду в свой терминал:.
npm install --save request
Теперь мы можем добавить его на наш сервер. Обновите свой серверный код, чтобы выглядеть так:
var express = require('express'), bodyParser = require('body-parser'), http = require('http'), server = require('request'), app = express(), token = 'xyz'; app.use(bodyParser.json({})); app.post('/fb', function(req, res){ console.log(JSON.stringify(req.body)) res.send(req.body) }) app.get('/fb', function(req, res) { if (req.query['hub.verify_token'] === 'abc') { res.send(req.query['hub.challenge']); } else { res.send('Error, wrong validation token'); } }); // create a health check endpoint app.get('/health', function(req, res) { res.send('okay'); }); // set port app.set('port', process.env.PORT || 8080); // start the server http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
Теперь нам нужно написать асинхронную функцию для обработки входящих сообщений. Для этого важно быть async, чтобы наш чатбент ответить на входящий веб-образ мгновенно с 200 ответ. Эта концепция важна для BoT Messenger, чтобы иметь гладкие и адаптивные функциональные возможности. Добавьте следующий код на свой сервер:
app.messageHandler = function(j, cb) { setTimeout(function(){ cb(true); }, 10000) }
Это простая тестовая функция для демонстрации асинхронизации Node.js. Теперь измените конечную точку вашей почты, чтобы выглядеть так.
app.post('/fb', function(req, res){ console.log(JSON.stringify(req.body)) app.messageHandler(req.body, function(result){ console.log("Async Handled: " + result) }) res.send(req.body) })
Теперь, когда вы отправляете сообщение на свой бот из мессенджера, вы можете отслеживать консоль серверов и увидеть, что приходит сообщение. Через 10 секунд сервер должен печатать «Async обрабатывается: True».
Теперь давайте повторим сообщение по сообщениям пользователю. Модифицируйте функцию « MessageHandler
», чтобы выглядеть следующее:
app.messageHandler = function(j, cb) { var data = { "recipient":{ "id":j.entry[0].messaging[0].sender.id }, "message":{ "text":j.entry[0].messaging[0].message.text } }; var reqObj = { url: 'https://graph.facebook.com/v2.6/me/messages', qs: {access_token:token}, method: 'POST', json: data }; console.log(JSON.stringify(reqObj)) request(reqObj, function(error, response, body) { if (error) { console.log('Error sending message: ', JSON.stringify(error)); cb(false) } else if (response.body.error) { console.log("API Error: " + JSON.stringify(response.body.error)); cb(false) } else{ cb(true) } }); }
Когда вы сообщаете, что бот, он должен ответить вам с тем же отправителем. Наш простой эховый сервер сейчас завершен.
Обработка естественного языка
Следующим шагом к функциональному чатботу является для этого, чтобы понять клиентов. Лучший способ понять сообщение – использовать понимание естественного языка (NLU). Общий инструмент для NLU – Google API.ai Отказ Я буду использовать API.ai, чтобы построить простой q & A бота для этого прохождения.
Создать новый агент на API.ai:
Теперь создайте новое намерение вашего агента:
Назовите вашу целью «AryouaroBot», а затем в разделе «Пользователь говорит», добавьте следующие фразы:
Ты робот? Вы – бот?
Сейчас в разделе «Речь-ответ» «Ответ» о намерениях добавьте следующий текст:
Да, я посланник бот.
После того, как вы сохранили свои намерения, вы можете проверить его на правой панели интерфейса API.AI. Когда вы отправляете вопрос: «Вы робот?» Вашему боту, он должен ответить: «Да, я посланник бот».
Когда вы нажимаете на «Показать JSON», вы должны увидеть следующее.
Из этого документа JSON увидим, что мы получим нашу API.ai речевой реагирование из следующего записи JSON: Json.result.fulfillment.speech
Нам нужно связать это NLU на наш сервер. Для этого нам нужна другая асинхронная функция, которая отправляет входящие сообщения на API.ai. Добавьте следующую функцию на свой сервер:
app.speechHandler = function(text, id, cb) { var reqObj = { url: 'https://api.api.ai/v1/query?v=20150910', headers: { "Content-Type":"application/json", "Authorization":"Bearer 4485bc23469d4607b19a3d9d2d24b112" }, method: 'POST', json: { "query":text, "lang":"en", "sessionId":id } }; request(reqObj, function(error, response, body) { if (error) { console.log('Error sending message: ', JSON.stringify(error)); cb(false) } else { console.log(JSON.stringify(body)) cb(body.result.fulfillment.speech); } }); }
Эта функция отправит ASYNC HTTP-запрос на конечную точку API.ai. Конечная точка API.ai вернет JSON, нам нужно ответить на любое входящее сообщение. Теперь нам нужно изменить нашу async MessageHandler
функция к следующему коду.
app.messageHandler = function(text, id, cb) { var data = { "recipient":{ "id":id }, "message":{ "text":text } }; var reqObj = { url: 'https://graph.facebook.com/v2.6/me/messages', qs: {access_token:token}, method: 'POST', json: data }; console.log(JSON.stringify(reqObj)) request(reqObj, function(error, response, body) { if (error) { console.log('Error sending message: ', JSON.stringify(error)); cb(false) } else if (response.body.error) { console.log("API Error: " + JSON.stringify(response.body.error)); cb(false) } else{ cb(true) } }); }
Наконец, нам нужно изменить нашу конечную точку пост, чтобы использовать наш обработчик речевого обработчика с помощью функции обработчика сообщений. Измените конечную точку вашего сообщения, чтобы выглядеть следующим кодом:
app.post('/fb', function(req, res){ var id = req.body.entry[0].messaging[0].sender.id; var text = req.body.entry[0].messaging[0].message.text; console.log(JSON.stringify(req.body)) app.speechHandler(text, id, function(speech){ app.messageHandler(speech, id, function(result){ console.log("Async Handled: " + result) }) }) res.send(req.body) })
Теперь перезапустите свой сервер и отправьте сообщение «Вы робот?» Вашу чатбот в Facebook Messenger. Бот должен ответить с сообщением: «Да, я мессенджер».
Ваш бот теперь интегрирован с API.ai. Вы заметите, что если вы отправите бот любое сообщение, он не знаком, он не поймет, как справиться с этим. Чтобы расширить знание вашего бота, вы можете включить «Домены» на панели инструментов API.ai.
Используя домены, вы можете легко расширить знания вашего четкого. Теперь добавьте свой код в репозиторий GIT и нажмите «Код» в GitHUB для безопасного хранения.
Контекст и управление сессией
Наш текущий чат очень прост и легко развиваться. Q & Bots, как это не требует удержания сеанса. Однако, если вы хотите сделать бот, что люди могут на самом деле использовать, вы, скорее всего, должны потребовать сохранения заседания и некоторой памяти контекста. API.ai имеет функцию «контекста» для их напряжения, которая позволяет чатбом поддерживать нить разговора. Лучшее использование для этой функции – это концепция сбора информации от пользователя. Чтобы продемонстрировать это, мы добавим вопрос 3 шага к нашему боту. Когда пользователь говорит: «Сохранить мою задачу», бот ответит следующей последовательности вопросов:
Какой предмет это для? Когда надо?
Пользователю будет предложено ответить на вопросы. Когда вопросы будут решены, Thatbot сообщит пользователю домашнее задание было сохранено.
Создайте новую «объект» на API.ai, который выглядит как следующее изображение:
Мы создадим намерение, которое использует эту сущность, чтобы понять, что на самом деле пытается сказать сообщение. Создайте намерение на API.ai, который выглядит как следующее изображение:
Добавьте еще один параметр на срок. Ваши намеренные параметры должны выглядеть следующее изображение:
Наконец, добавьте речевой ответ, который говорит «Ваше домашнее задание на сумму было сохранено». Наше новое намерение завершено! API.ai автоматически использует тему и срок выполнения в ответ, потому что мы использовали переменную «» в нашем тексте реагирования речи. Поскольку наш сервер уже интегрирован, и мы передаем «идентификатор отправителя» из Facebook на API.ai в качестве «идентификатора сеанса» API.ai уже может управлять контекстом и сеансом для нас. Дайте своему боту, попробуем, сказав «Сохранить свою домашнюю работу» на него в Messenger.
Развертывание AWS.
Первое, что нужно сделать, это запустить новый образ Ubuntu на облаке EC2. Войдите в AWS, перейдите к консоли EC2 и запустите новый экземпляр.
Выберите изображение Ubuntu 16.04 LTS 64bit из списка AMIS.
Выберите тип экземпляра T2.Micro, затем перейдите в «Настроить данные экземпляра». Детали экземпляра должны быть в порядке на настройках по умолчанию. Нажмите «Добавить хранилище», затем выберите магнитный тип хранения.
Использование SSD будет загружаться быстрее, однако использование магнитного хранилища сэкономит деньги в долгосрочной перспективе. Поскольку мы развертываем распределенную инфраструктуру, нам не понадобится файловая система. При развертывании масштабируемой инфраструктуры вы можете не захотеть сохранять файлы непосредственно на сервере. Для хранения файлов вам нужно будет использовать услугу, как S3 Отказ
Перейдите к добавлению тегов и дайте свой сервер «Имя» тег. После добавления имени перейдите к конфигурации группы безопасности. Создайте конфигурацию вашей группы безопасности так:
Теперь нажмите «Обзор и запустить», затем нажмите «Запуск». Создайте новую ключевую пару, дайте ей имя и загрузите его в свою/базовую папку. После того, как вы загрузите пару ключей, запустите свой экземпляр. Вернитесь к панели инструментов EC2 и выберите свой вновь созданный экземпляр. Вы увидите, что у него есть публичный адрес IPv4. Это адрес, который мы будем использовать для SSH в машину Ubuntu.
Откройте новый терминал в базовой папке и введите следующую команду
sudo chmod 400.pem
Это обеспечит ключевой файл для SSH. Теперь вы можете выполнить следующую команду для входа в систему.
ssh -i.pem ubuntu@
Это войдет на вас в машину Ubuntu. Первое, что нужно сделать, это установить Node.js. Запустите эту команду на машине Ubuntu:
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - sudo apt-get install -y nodejs
Теперь вы можете использовать Git для установки вашего кода, потянувшись из репозитория на GitHub или Bitbucket. Для этого учебника я собираюсь загрузить ZIP-файл с помощью SCP. Создайте ZIP-архив вашей/базовой папки, затем добавьте ZIP-файл в свою/базовую папку. Теперь запустите следующую команду:
scp -i.pem ./base.zip ubuntu@ :base.zip
Вы должны увидеть загруженную загрузку файла в терминале.
Теперь SSH обратно на свой сервер.
ssh -i.pem ubuntu@
Запустите следующие команды.
unzip apt-get unzip unzip base.zip cd base sudo rm.pem sudo rm -rf node_modules
Мы удаляем все node_modules
А потом перестроили их, используя родную систему Ubuntu. В противном случае мы, вероятно, будем испытывать ошибки. Запустите следующие команды.
npm install npm start
Другая важная вещь, которую нам нужна, это сертификат SSL. Facebook позволяет только ботам работать над зашифрованными соединениями SSL. Мы можем получить сертификат SSL бесплатно, используя Давайте шифровать Certbot Отказ Запустите следующую команду:
sudo apt-get install letsencrypt
Теперь введите эту команду.
wget https://dl.eff.org/certbot-auto chmod a+x ./certbot-auto
Нам также нужно доменное имя. Вы можете получить бесплатное доменное имя здесь Отказ
Направьте рекордный домен для @ и www в адрес IPv4 вашего экземпляра EC2.
Нам нужно включить SSL на порту 443 для нашего сервера. Нажмите на группу безопасности вашего экземпляра EC2 с помощью приборной панели.
Затем добавьте так, как это правило SSL.
Теперь запустите эту команду.
./certbot-auto certonly --standalone --email aaron@nimblestack.io -d-d www.
Эта команда выводит путь к вашему ключу и ваш новый сертификат. Вы можете найти путь к сертификату в «важной информации», что Certbot отпечатывает после создания сертификата. Обязательно прочитайте это внимательно. Теперь измените свой серверный код для использования SSL. Конечный серверный код должен выглядеть так.
var express = require('express'), bodyParser = require('body-parser'), https = require('https'), request = require('request'), app = express(), fs = require('fs'), token = 'XXXXXXXXXXXXXXXXXXXXXXXXXX', sslOpts = { "key":fs.readFileSync("/etc/letsencrypt/keys/0000_key-certbot.pem"), "cert":fs.readFileSync('/etc/letsencrypt/live//fullchain.pem') } // accept JSON bodies. app.use(bodyParser.json({})); // accept incoming messages app.post('/fb', function(req, res){ var id = req.body.entry[0].messaging[0].sender.id; var text = req.body.entry[0].messaging[0].message.text; console.log(JSON.stringify(req.body)) app.speechHandler(text, id, function(speech){ app.messageHandler(speech, id, function(result){ console.log("Async Handled: " + result) }) }) res.send(req.body) }) app.messageHandler = function(text, id, cb) { var data = { "recipient":{ "id":id }, "message":{ "text":text } }; var reqObj = { url: 'https://graph.facebook.com/v2.6/me/messages', qs: {access_token:token}, method: 'POST', json: data }; console.log(JSON.stringify(reqObj)) request(reqObj, function(error, response, body) { if (error) { console.log('Error sending message: ', JSON.stringify(error)); cb(false) } else if (response.body.error) { console.log("API Error: " + JSON.stringify(response.body.error)); cb(false) } else{ cb(true) } }); } app.speechHandler = function(text, id, cb) { var reqObj = { url: 'https://api.api.ai/v1/query?v=20150910', headers: { "Content-Type":"application/json", "Authorization":"Bearer XXXXXXXXXXXXX" }, method: 'POST', json: { "query":text, "lang":"en", "sessionId":id } }; request(reqObj, function(error, response, body) { if (error) { console.log('Error sending message: ', JSON.stringify(error)); cb(false) } else { console.log(JSON.stringify(body)) cb(body.result.fulfillment.speech); } }); } // verify token to subscribe app.get('/fb', function(req, res) { if (req.query['hub.verify_token'] === 'abc') { res.send(req.query['hub.challenge']); } else { res.send('Error, wrong validation token'); } }); // create a health check endpoint app.get('/health', function(req, res) { res.send('okay'); }); // set port app.set('port', process.env.PORT || 443); // start the server https.createServer(sslOpts, app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
Чтобы постоянно хранить наше приложение, нам нужно использовать менеджер процессов. В этом проходе мы будем использовать PM2 Отказ Запустите следующую команду.
sudo npm install -g pm2
Затем запустите:
sudo pm2 start app.js
PM2 удостоверится, что ваше приложение всегда в сети. Чтобы проверить состояние и просмотреть файлы журнала, вы можете запустить эту команду:
sudo pm2 show app
Теперь, когда у нас есть сервер, работающий на нашем IP-адресе на порту 443, мы можем проверить, что он работает, открывая наше доменное имя под HTTPS.
https:///health
Вы должны увидеть «хорошо» напечатаны на экране браузера.
Теперь вернитесь к своему приложению Messenger Facebook, и укажите конечную точку вашего веб -ook в доменном имени вашего сервера:
https:///fb
Затем это перенаправляет весь трафик Messenger Boot на ваш сервер, который работает на AWS.
Заключение
Настройка местной среды для разработки бота непросто. Теперь, когда вы настроили базовую среду бота, вы сможете повторно использовать эту настройку для других четков. Вы можете обновить конфигурацию API.ai и разверните его в другом приложении Facebook, чтобы создать новые частых чатей. К сожалению, это было бы слишком много, чтобы покрыть в одном блоге. С этим сказанным, я работаю по крайней мере по крайней мере один последующий пост, который прогуляет добавление базы данных, настроить EC2 для масштаба и добавления сложности в NLU с API.AI.
Часть 2 настоящего Учебника, которое касается сохранения контекста и отслеживания данных, можно найти здесь.