Создаем чат бота с командами

Просмотров: 27 862. 16 комментариев

В одной из прошлых статей мы создавали простой скрипт для переписки. Были рассмотрены базовые возможности. На этот раз мы напишем чат-бот с командами. Реализуем такие команды:

  • город [название города]. Данной командой задается город собеседника, бот запомнит его, сохранит в файл. Эти данные будут доступны даже после перезапуска программы.
  • погода. Бот отправляет текущую температуру в городе собеседника.
  • пробки. Бот получает скриншот Яндекс.Карт с состоянием пробок и отправляет картинку.
  • события. Бот отправляет список событий в городе собеседника.
  • пришли на email [email]. Бот сохраняет email собеседника в файл.

Город

Город собеседника мы будем хранить в текстовом файле. Для каждого скрипта создается отдельная папка в которой он может хранить произвольные файлы, которые будут переживать перезапуск программы. Папка будет создана рядом со скриптом. Рассмотрим фрагмент кода по обработке команды город.

  
  var cityFile = profile + "__" + contact;

  if (content.startsWith("город ")) {
    var city = content.substring(6);
    log.info("Saving city for contact " + contact);
    tools.writeToFile(cityFile, city);
    return "Теперь я знаю твой город.";
  } 

В переменную cityFile мы сохраняем имя файла. Далее с помощью вызова метода tools.writeToFile(file, data) мы сохраняем город в файл. Обратите внимание, что функцией writeToFile пользоваться небезопасно в случае если несколько анкет выполняют один и тот же скрипт и обращаются к одному и тому же файлу. Поэтому мы используем id анкеты в имени файла, чтобы исключить такие конфликты.

Для чтения из файла используется метод tools.readFromFile(file). Данная функция читает весь файл и возвращает содержимое. Если файла не существует, функция возвращает пустую строку.

    var city = tools.readFromFile(cityFile);
    if (city.isEmpty()) {
      return "Я не знаю твой город :(";
    }

Выбор имени файла

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

  var profile = hist.localContact().getID().toString();
  var contact = hist.externalContact().getID().toString();

  var cityFile = profile + "__" + contact;

Здесь мы получаем данные об анкете в боте через метод hist.localContact(). Далее методом getID() получаем внутренний идентификатор анкеты (выглядит примерно так profile_www.vk.com_+79129192508). Аналогично получаем идентификатор собеседника (id361493719). В результате в переменной cityFile получаем profile_www.vk.com_+79129192508__id361493719. Поскольку имя содержит идентификатор анкеты, добавленной в бот, другая анкета не сможет сгенерировать такое же имя файла и конфликтов не будет.

Погода

Для получения данных о погоде воспользуемся сервисом openweathermap.org. Нужно зарегистрироваться и получить бесплатный ключ для доступа к API. Далее отправить HTTP-запрос с названием города и получить в ответ JSON с данными.

function getWeather(city, tools) {
  city = city.replace(" ", "%20");
  var apiKey = "43599b515694631087a103907284116d";
  var url = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=" + apiKey + "&units=metric";
  return JSON.parse(tools.httpGet(url));
}

Для выполнения HTTP-запроса используем метод tools.httpGet(url). Метод возвращает тело HTTP-ответа. Обратите внимание, что пробелы в названии города мы заменяем на специальный код.

Пробки

Получать данные о пробках будет с Яндекс.Карт также через выполнение HTTP-запроса.

function getTraffic(city, file, log, tools) {
  log.info("Getting coordinates for city " + city);
  city = city.replace(" ", "%20");
  var url = "https://geocode-maps.yandex.ru/1.x/?geocode=" + city + "&format=json";
  var resp = JSON.parse(tools.httpGet(url));
  var coord = resp["response"]["GeoObjectCollection"]["featureMember"][0]["GeoObject"]["Point"]["pos"].replace(" ", ",");
  log.info("Coordinates are: " + coord + ", getting traffic pic");

  var url = "https://static-maps.yandex.ru/1.x/?ll=" + coord + "&spn=0.1,0.1&l=map,trf";
  return tools.download(url, file);
}

Сервис Яндекс.Карт возвращает данные о пробках по географической координате. У нас же есть только строковое название города. Поэтому сначала мы отправляем HTTP-запрос на получение данных о городе на другой сервис. Среди прочего в ответе есть данные о координате. Координату используем для другого HTTP-запроса. Обратите внимание, что для получения картинки с пробками мы используем метод tools.download(url, file). Этот метод также выполняет HTTP GET запрос, но сохраняет бинарный результат в файл. Метод получает URL и имя файла для сохранения ответа. Обратите внимание, что в имени файла должно быть только имя, без путей. Метод возвращает полный путь к этому файлу.

События

Для получения событий в конкретном городе воспользуемся API timepad.ru.

function getEvents(city, tools) {
  city = city.replace(" ", "%20");
  var url = "https://api.timepad.ru/v1/events.json?limit=10&skip=0&cities=" + city + "&fields=location&sort=+starts_at";
  return JSON.parse(tools.httpGet(url));
}

Пришли на email

Воспользуемся методом tools.appendToFile(file, line). Метод добавляет строку line в файл file (только имя файла, без путей). Данный метод является безопасным для использования из нескольких анкет с одним и тем же именем файла. Таким образом удобно собирать какие-то сообщения или фрагменты сообщений от пользователей в одном файле. В данном скрипте мы будем собирать email адреса пользователей.

  if (content.startsWith("пришли на email ")) {
    var email = content.substring(16);
    tools.appendToFile("emails", email);
  }

Весь скрипт

Приведем весь код скрипта.

function getTemplates() {
return [];
}
function getWeather(city, tools) {
city = city.replace(" ", "%20");
var apiKey = "43599b515694631087a103907284116d";
var url = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=" + apiKey + "&units=metric";
return JSON.parse(tools.httpGet(url));
}
function getTraffic(city, file, log, tools) {
log.info("Getting coordinates for city " + city);
city = city.replace(" ", "%20");
var url = "https://geocode-maps.yandex.ru/1.x/?geocode=" + city + "&format=json";
var resp = JSON.parse(tools.httpGet(url));
var coord = resp["response"]["GeoObjectCollection"]["featureMember"][0]["GeoObject"]["Point"]["pos"].replace(" ", ",");
log.info("Coordinates are: " + coord + ", getting traffic pic");
var url = "https://static-maps.yandex.ru/1.x/?ll=" + coord + "&spn=0.1,0.1&l=map,trf";
return tools.download(url, file);
}
function getEvents(city, tools) {
city = city.replace(" ", "%20");
var url = "https://api.timepad.ru/v1/events.json?limit=10&skip=0&cities=" + city + "&fields=location&sort=+starts_at";
return JSON.parse(tools.httpGet(url));
}
function handle(content, profile, contact, log, tools) {
log.info("Got message: " + content + " from " + contact + " to " + profile);
var cityFile = profile + "__" + contact;
if (content.startsWith("город ")) {
var city = content.substring(6);
log.info("Saving city for contact " + contact);
tools.writeToFile(cityFile, city);
return "Теперь я знаю твой город.";
} else if (content.startsWith("погода")) {
var city = tools.readFromFile(cityFile);
if (city.isEmpty()) {
return "Я не знаю твой город :(";
}
log.info("Getting weather for city " + city);
var weather = getWeather(city, tools);
return "Температура: " + weather["main"]["temp"];
} else if (content.startsWith("пробки")) {
var city = tools.readFromFile(cityFile);
if (city.isEmpty()) {
return "Я не знаю твой город :(";
}
var trafficFile = profile + "__" + contact + ".png";
var fullFileName = getTraffic(city, trafficFile, log, tools);
return "такие пробки [image:" + fullFileName + "]";
} else if (content.startsWith("пришли на email ")) {
var email = content.substring(16);
tools.appendToFile("emails", email);
return "Спасибо! Я напишу.";
} else if (content.equals("события")) {
var city = tools.readFromFile(cityFile);
if (city.isEmpty()) {
return "Я не знаю твой город :(";
}
log.info("Getting events for city " + city);
var events = getEvents(city, tools)["values"];
log.info("Got " + events.length + " events");
var result = "";
for (var i = 0; i < events.length; ++i) {
var dateTime = events[i]["starts_at"];
var dateTimeStr = dateTime.substring(0, 10) + " " + dateTime.substring(11, 17);
var name = events[i]["name"];
result += (i + 1) + ". " + dateTimeStr + " " + name + "\n";
}
return result;
}
return "";
}
function getAnswer(hist, log, tools) {
var profile = hist.localContact().getID().toString();
var contact = hist.externalContact().getID().toString();
var toReply = hist.unansweredMessages();
var result = "";
for(var i = 0; i < toReply.size() ; ++i) {
var message = toReply.get(i);
var content = message.content().toLowerCase();
var dup = false;
for(var j = 0; j < i && !dup; ++j) {
dup = content.equals(toReply.get(j).content().toLowerCase());
}
if (!dup) {
result += handle(content, profile, contact, log, tools) + " ";
}
}
return result;
}

Пример работы

2016-11-12_20-43-04

Что еще можно получить из истории

Из истории переписки в скрипте можно получить некоторую дополнительную информацию об анкете и собеседнике. А именно:

hist.localContact().getLogin() логин анкеты в боте
hist.localContact().getPassword() пароль анкеты в боте
hist.localContact().getHomePageUrl() ссылка на анкету в боте (например, https://vk.com/id381559011)
hist.localContact().getProxy() прокси анкеты в боте или пустая строка, если прокси не задан
hist.localContact().getUserAgent() User-Agent анкеты в боте
hist.externalContact().getAlias() имя собеседника (например, Иван Иванов)

 

Хотите получить БроБот бесплатно?

Присылайте нам кейсы своих успешных проектов с БроБотом, мы опубликуем его в историях успехов и мы поделимся с Вами безлимитным тарифом!

Прислать свой кейс
Комментарии
  • Ответить

    Функционал БроБота | Бесплатная программа бот для ВКонтакте (Vk) и Одноклассниках (Ok)., https://brobot.ru/functions-overview/ - 14 ноября, 2016 Ссылка

    […] реализации любого по сложности бота для переписки. Вот тут можно посмотреть […]

  • Ответить

    dusha1808, - 10 декабря, 2016 Ссылка

    у меня проблема с ботом, когда я пытаюсь создать скриптованного бота, он не находит файлы скрипта, а если вводить имя файла в ручную то он выдает ошибку

    • Ответить

      Команда BroBot, - 11 декабря, 2016 Ссылка

      Это вам на форум или на почту — к сожалению, в комментариях не саппортим больше.

  • Ответить

    Олег, - 28 декабря, 2016 Ссылка

    В каком файле это сохранять?блокнот или что?!

  • Ответить

    Настройка параметров переписки | Бесплатная программа бот для накрутки ВКонтакте, Инстаграм и Одноклассников., https://brobot.ru/42b42a1b-f097-479d-90e7-a23e4534740b/ - 18 февраля, 2017 Ссылка

    […] Создаем чат бота с командами […]

  • Ответить

    dmitriy, - 19 февраля, 2017 Ссылка

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

    • Ответить

      Команда BroBot, - 20 февраля, 2017 Ссылка

      Работает все.
      И в директе и в комментариях, если опцию указать в настройках задания

  • Ответить

    Сергей, - 11 марта, 2017 Ссылка

    Простите у меня вопрос: Как настроить его на переписку? Я уже всё сделал а он не отвечает на сообщения, помогите пожалуйста.

    • Ответить

      Команда BroBot, - 13 марта, 2017 Ссылка

      А пришлите сообщение об ошибке через программу, посмотрим, разберемся. Программа — сообщить об ошибке.

  • Ответить

    Илья, - 16 марта, 2017 Ссылка

    Можно ли совместить скрипт и обучаемого бота?

  • Ответить

    Владислав, - 9 апреля, 2017 Ссылка

    Я копирую этот код, сохраняю в файле формата .js и когда моему боту пишут пробки, мне в логе событий выдаёт что не удалось отправка сообщения, ошибка на 48 строчке temp. Как исправить?

    • Ответить

      Команда BroBot, - 13 апреля, 2017 Ссылка

      в саппорт напишите плиз, мы там оказываем поддержку

  • Ответить

    Обучение бота | Бесплатная программа бот для накрутки ВКонтакте, Инстаграм и Одноклассников., https://brobot.ru/window-bot-teaching/ - 13 апреля, 2017 Ссылка

    […] Создаем чат бота с командами […]

  • Ответить

    Константин, http://ubego.ru - 3 сентября, 2017 Ссылка

    Почему то Date() ни бум бум. Как получить дату?

Прежде чем оставить комментарий:
Попробуй воспользоваться поиском. На 80% вопросов уже есть ответы.
Скорее всего, сообщество на форуме даст ответ намного быстрее нас ;)
Открыть форум
Добавить комментрий

двадцать + 6 =


Каждый раз, когда кто-то подписывается на БроБота, наши боты становятся все умнее!