Вв перезагрузка вконтакте: Sorry, this page can’t be found.
Содержание
Чат-бот для ВКонтакте на Python на Callback API / Хабр
Чат-боты стали уже очень распространенным явлением, и появляются во всех мессенджерах ежедневно.
В этой статье по шагам разберем создание бота с набором простых команд и узнаем, как в дальнейшем можно расширить его функционал. Статья будет полезна для самых новичков, которые никогда не пробовали создавать чат-ботов.
Когда мне захотелось создать бота, я изучила доступные примеры ботов для ВКонтакте и постаралась достигнуть максимального упрощения их структуры.
Для создания бота я использовал Python 3.5 (вероятно, подойдут и другие версии 3-го питона) и дополнительные библиотеки Flask и VK. Их надо будет установить. По установке Flask есть много статей на русском. Если у вас стоит Pycharm, то он, скорее всего, установился вместе с ним.
Начнем с самого API. Для нашего бота будем использовать Callback API, доступный для сообщений групп. Прежде всего, нам нужно создать или уже иметь группу ВКонтакте с подключенными сообщениями.
В разделе управление сообществом → работа с API необходимо создать ключ с доступом к сообщениям сообщества.
Для работы с Callback нужно иметь веб-сервер, который будет принимать запросы о каких-либо событиях от API, обрабатывать их и посылать ответные запросы. То есть мы напишем «сайт», который будет только отвечать на посылаемые ему запросы и посылать свои.
Поскольку пишем на питоне, самое простое, что можно использовать, — это хостинг для питона. Я пользовался бесплатным хостингом для Python. Там нужно зарегистрироваться, а затем создать приложение для питона 3.5 на Flask (создать можно в разделе Web). Будет создан начальный файл:
# A very simple Flask Hello World app for you to get started with...
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello from Flask!'
Единственная функция, которая сейчас есть в файле, отвечает за наполнение страницы по адресу, выданному при регистрации. Если перейти в браузере по адресу username.pythonanywhere.com (со своим ником), то можно увидеть только текст «Hello from Flask!».
В дальнейшем код будет изложен блоками и после завершения целого блока можно будет проверить, а в процессе код может быть помечен средой как ошибочный. Не стоит этого пугаться, лучше просто доделать блок до конца.
Итак, БЛОК 1.
Для обработки запросов, посылаемых сайту, добавим в конце документа следующий код:
Где вместо иксов подставляем «строку, которую должен вернуть сервер». Она указана в управлении группой в разделе Callback API.
Эта функция позволит нам подключить наш сайт для уведомлений к группе.
Теперь можем проверить работу. Только необходимо перезагрузить приложение. На хостинге после того, как файлы были изменены и сохранены, чтобы сайт стал работать с новыми данными, нужно его перезагрузить во вкладке Web.
После добавления этого кода можем ввести соответствующий адрес username.pythonanywhere.com в строку адреса сервера в группе ВКонтакте и нажать «Подтвердить».
Должно появиться зеленое уведомление о том, что адрес сервера успешно подключен.
При нажатии «Подтвердить» ВКонтакте пытается связаться с нашим сервером и убедиться, что он действительно принадлежит владельцу группы, и «ждет», что сервер вернет код подтверждения в ответ на запрос.
БЛОК 2
Можем переходить к следующему шагу. Добавим возможность писать сообщения от имени сообщества. Пришло время установить на хостинге библиотеку VK. В разделе Consoles запускаем bash-консоль и исполняем команду (или соответствующую для выбранной версии питона):
pip3.5 install --user vk
Как устанавливать модули описано
здесь
.
Изменим код нашей функции по обработке входящих запросов:
@app.route('/', methods=['POST'])
def processing():
#Распаковываем json из пришедшего POST-запроса
data = json. loads(request.data)
#Вконтакте в своих запросах всегда отправляет поле типа
if 'type' not in data.keys():
return 'not vk'
if data['type'] == 'confirmation':
return confirmation_token
elif data['type'] == 'message_new':
session = vk.Session()
api = vk.API(session, v='5.110')
user_id = data['object']['message']['from_id']
api.messages.send(access_token=token, user_id=str(user_id), message='Привет, я новый бот!', random_id=random.getrandbits(64))
# Сообщение о том, что обработка прошла успешно
return 'ok'
Сообщение о том, что обработка прошла успешно, нужно серверу ВКонтакте. Если произойдет ошибка, или придет какой-то иной ответ, сервер будет с некоторыми промежутками продолжать посылать уведомление о входящем сообщении (пока мы его не обработаем).
Структура входящего запроса, оповещающего о новом сообщении, такова:
Их надо заменить на ваши токены. Первый мы создали в начале статьи, второй – код подтверждения, чтобы соединить группу с сервером.
Теперь наш бот может на входящие сообщения здороваться и подтверждать свою принадлежность группе, код которой мы ему дали.
Можем его проверить и написать ему какое-нибудь сообщение, только надо подключить в настройках группы в разделе Callback API уведомления о входящих сообщениях.
Чтобы бот стал слать сообщения, нужно перезагрузить приложение. После этого снова пишем боту и, если все в порядке, переходим к следующему шагу.
БЛОК 3
Если все прошло хорошо, и бот с вами поздоровался в ответ на ваше сообщение, переходим к следующему шагу. Вынесем все взаимодействие с библиотекой vk в другой файл, я назвал его vkapi:
Пока там только одна функция и инициализация сессии ВКонтакте, потом добавим другие. Потенциально функция может также отправлять и вложения. Позже мы воспользуемся этой возможностью.
Дальше заведем файл — обработчик сообщений. Он будет обрабатывать входящие сообщения, определять соответствующие команды, когда они появятся, и выдавать нужные ответы.
Осталось подключить наши новые файлы к основному. Изменяем функцию обработки запросов в главном файле:
@app.route('/', methods=['POST'])
def processing():
data = json.loads(request.data)
if 'type' not in data.keys():
return 'not vk'
if data['type'] == 'confirmation':
return confirmation_token
elif data['type'] == 'message_new':
messageHandler.create_answer(data['object']['message'], token)
return 'ok'
И добавляем соответствующий импорт в начало файла:
import messageHandler
Можем проверить, что у нас получилось, перезагрузив приложение.
БЛОК 4
Приступим к созданию команд. Создадим класс команд.
Файл «command_system.py»:
command_list = []
class Command:
def __init__(self):
self.__keys = []
self.description = ''
command_list.append(self)
@property
def keys(self):
return self. __keys
@keys.setter
def keys(self, mas):
for k in mas:
self.__keys.append(k.lower())
def process(self):
pass
У класса есть свойство keys, где будут храниться ключи, по которым можно обратиться к данной команде. Все ключи сохраняются в строчных буквах при задании свойства, и сравнивать их нужно с переведенными в строчную форму сообщениями пользователя, чтобы регистр не влиял на успех вызова команды.
Поле description будем использовать для выдачи информации по командам бота. Функция process будет исполняться для формирования ответного сообщения.
Есть общий список, в который сохраняются все команды при их инициализации. Он находится снаружи класса. Этот список будем использовать для поиска команды, которую запросил пользователь своим сообщением.
Теперь создадим несколько команд для нашего бота. Для удобства загрузки будем помещать файлы, в которых инициализируем команды, в папку «commands».
Я создам несколько файлов, но можно и разместить команды и в одном файле
import command_system
import vkapi
import settings
def cat():
# Получаем случайную картинку из паблика
attachment = vkapi.get_random_wall_picture(-32015300, settings.access_token)
message = 'Вот тебе котик :)\nВ следующий раз я пришлю другого котика.'
return message, attachment
cat_command = command_system.Command()
cat_command.keys = ['котик', 'кошка', 'кот', 'котенок', 'котяра', 'cat']
cat_command.description = 'Пришлю картинку с котиком'
cat_command.process = cat
Для команды, отправляющей котика, нам понадобится новый токен и новая функция и в файле «vkapi», которая возвращает случайную картинку со стены группы или пользователя. В данном случае будем получать случайную фотографию со стены паблика с котами.
Начнем с получения токена. Нам нужен сервисный ключ доступа. Для этого надо создать новое Standalone-приложение. Его можно создать по ссылке. Далее когда приложение будет создано, нужно перейти в его настройки и скопировать то, что находится в поле «Сервисный ключ доступа».
Это нужно внести в наш файл с токенами.
«settings.py»
Дописываем его в файл «vkapi». Также в начало файла «vkapi» надо добавить необходимый импорт:
import random
И последняя команда
«info.py»
import command_system
def info():
message = ''
for c in command_system.command_list:
message += c.keys[0] + ' - ' + c.description + '\n'
return message, ''
info_command = command_system.Command()
info_command.keys = ['помощь', 'помоги', 'help']
info_command.desciption = 'Покажу список команд'
info_command.process = info
Окончательная иерархия файлов:
botFlask — главный файл, который принимает входящие запросы.
Теперь, когда мы описали команды, нужно позаботиться о том, чтобы наш лист команд был наполнен, и мы могли понять, к какой из команд обращался пользователь, так как список “command_list” заполняется только в момент запуска файлов с конкретными командами.
Мы будем автоматически запускать на исполнение все файлы из папки «commands» при запуске нашего бота.
Для этого в файле «messageHandler.py» дописываем функцию:
def load_modules():
# путь от рабочей директории, ее можно изменить в настройках приложения
files = os.listdir("mysite/commands")
modules = filter(lambda x: x.endswith('.py'), files)
for m in modules:
importlib.import_module("commands." + m[0:-3])
В этой функции мы загружаем список файлов из директории с командами, отфильтровываем только файлы питона и импортируем их в нашу программу, что обеспечивает заполнение списка командами.
Вызов этой функции добавляем в «create_answer». Теперь изменим функцию «get_answer» так, чтобы она вызывала соответствующий ответ.
Итоговый вид файла:
import vkapi
import os
import importlib
from command_system import command_list
def load_modules():
# путь от рабочей директории, ее можно изменить в настройках приложения
files = os. listdir("mysite/commands")
modules = filter(lambda x: x.endswith('.py'), files)
for m in modules:
importlib.import_module("commands." + m[0:-3])
def get_answer(body):
# Сообщение по умолчанию если распознать не удастся
message = "Прости, не понимаю тебя. Напиши 'помощь', чтобы узнать мои команды"
attachment = ''
for c in command_list:
if body in c.keys:
message, attachment = c.process()
return message, attachment
def create_answer(data, token):
load_modules()
user_id = data['from_id']
message, attachment = get_answer(data['text'].lower())
vkapi.send_message(user_id, token, message, attachment)
Все, наш бот готов! Теперь вы знаете, как создать основу для бота и добавить для него новые команды.
БЛОК 5
Дальнейшая часть статьи будет про одно улучшение, которое я считаю необходимым. Однако бот будет работать и без этого.
Приблизительное распознавание команд
Если пользователь допустил ошибку в одном символе, скорее всего, он имел в виду максимально похожую команду. Поэтому было бы хорошо, если бы наш бот все равно давал ответ, а не говорил «не понимаю тебя».
Для приблизительного распознавания будем использовать расстояние Дамерау-Левенштейна. Оно показывает, за сколько операций удаления, вставки, замены и перемещения символов можно перейти от одной строки к другой.
Алгоритм нахождения этого расстояния изложен, например, в Википедии.
Добавляем в файл “messageHandler.py” функцию:
def damerau_levenshtein_distance(s1, s2):
d = {}
lenstr1 = len(s1)
lenstr2 = len(s2)
for i in range(-1, lenstr1 + 1):
d[(i, -1)] = i + 1
for j in range(-1, lenstr2 + 1):
d[(-1, j)] = j + 1
for i in range(lenstr1):
for j in range(lenstr2):
if s1[i] == s2[j]:
cost = 0
else:
cost = 1
d[(i, j)] = min(
d[(i - 1, j)] + 1, # deletion
d[(i, j - 1)] + 1, # insertion
d[(i - 1, j - 1)] + cost, # substitution
)
if i and j and s1[i] == s2[j - 1] and s1[i - 1] == s2[j]:
d[(i, j)] = min(d[(i, j)], d[i - 2, j - 2] + cost) # transposition
return d[lenstr1 - 1, lenstr2 - 1]
Она реализует алгоритм нахождения этого расстояния, при желании вы можете его изменить или улучшить.
По данным строкам она будет выдавать количество операций для преобразования одной в другую. Теперь изменим метод «get_answer»:
def get_answer(body):
message = "Прости, не понимаю тебя. Напиши 'помощь', чтобы узнать мои команды"
attachment = ''
distance = len(body)
command = None
key = ''
for c in command_list:
for k in c.keys:
d = damerau_levenshtein_distance(body, k)
if d < distance:
distance = d
command = c
key = k
if distance == 0:
message, attachment = c.process()
return message, attachment
if distance < len(body)*0.4:
message, attachment = command.process()
message = 'Я понял ваш запрос как "%s"\n\n' % key + message
return message, attachment
В этой функции мы вычисляем расстояние для сообщения и каждого из ключей. Если совпадение неточное, пишем, как бот распознал каждую из тех команд, которые ему отправили. В случае, если расстояние превысило 40% от длины поданного сообщения, считаем, что пользователь ошибся слишком сильно и возвращаем сообщение по умолчанию, где предлагаем обратиться к помощи.
На этом все, рабочий (на момент написания статьи) код выложен на гитхабе.
Надеюсь, эта статья немного облегчит вам жизнь, если вы решили создать своего бота для VK.
Лиссабонская перезагрузка
Последние месяцы НАТО была в центре мирового общественного внимания, и неудивительно — этот военный блок оказывает непосредственное влияние на ситуацию в мировой системе. Оттого принятие новой Стратегической концепции альянса на Лиссабонском саммите без преувеличения является событием чрезвычайной важности.
Принятая в Лиссабоне Стратегия определяет долгосрочные цели, характер и основополагающие задачи НАТО в сфере безопасности, формулирует указания для дальнейшей адаптации ее вооруженных сил.
С момента своего образования НАТО занимается регулярным пересмотром собственных целей и задач с учетом изменения стратегической обстановки. Как отмечают сами идеологи НАТО, в 1991 г. началась новая эпоха, когда был повержен главный и «грозный враг, каким когда-то был Советский Союз» (1). Эта эпоха ознаменовала появление несекретных концепций, принятых в ноябре 1991 г. и в апреле 1999 года. Тем не менее обе стратегии сопровождались секретными военными документами: «Директива ВК для вооруженных сил по выполнению Стратегической концепции Североатлантического союза» (ВК «400») от 12 декабря 1991 г. и «Руководящие указания ВК для вооруженных сил по выполнению Стратегии Североатлантического союза» (ВК «400/2») от 12 февраля 2003 года. Я уверена, что и новая Концепция дополнена секретными материалами, о которых публике ничего не сообщат.
Важно также понимать, что каждая новая концепция НАТО была не только ответом на кардинальные изменения в мировой системе (1991 г. — распад советского блока, 1999 г. — превращение альянса по итогам войны в Югославии в структуру, стоящую над ООН), но и определяла основные тенденции развития стран и целых регионов. Именно поэтому генсек НАТО А. Ф. Расмуссен назвал момент принятия новой «дорожной карты» НАТО на ближайшие десять лет историческим.
Исторический смысл новой Стратегии я вижу в ряде фундаментальных положений, самым непосредственным образом затрагивающих национальные интересы России.
Документ зафиксировал новый «стратегический» вектор развития отношений НАТО с Россией. Этот вопрос вызвал очень острые дискуссии внутри Союза. В частности, в первоначальном варианте новой доктрины НАТО наряду с задачей построения стратегического сотрудничества с Россией была зафиксирована необходимость предоставить восточноевропейским странам «дополнительные военные гарантии их безопасности» (2). При этом ни ранее, ни сейчас не уточняется, от кого нужно защищать страны — члены НАТО. Хотя и без того понятно — кто и что имеется в виду.
С тех пор этот документ претерпел ряд изменений и редакций. Новая доктрина НАТО, принятая 19 ноября, констатировала стратегическую роль сотрудничества с Россией, причем весьма специфически.
Однако все по порядку.
Прежде всего, в новом документе впервые зафиксировано: НАТО «не является угрозой для России», на чем особо акцентируют внимание натовские чиновники. То есть до 19 ноября 2010 года НАТО была угрозой для нашей страны. Соответственно, расширение НАТО преследовало стратегическую цель максимально сузить пространство манёвра для России. Для думающих людей это никогда не было тайной. Однако для России перестать «быть угрозой» для НАТО не означает, по моему мнению, действительно сделаться её партнером. И вот почему.
Как отмечается в Концепции, теперь НАТО хочет «видеть реальное стратегическое партнерство между НАТО и Россией» и будет «действовать соответственно, ожидая взаимности от России». Причем, «невзирая на наличие разногласий по отдельным вопросам», страны-члены альянса убеждены, «что безопасность НАТО и России тесно переплетены, и что сильное и конструктивное партнерство, базирующееся на взаимном доверии, транспарентности и предсказуемости может наилучшим образом служить нашей безопасности».
К чему бы такой реверанс в сторону России? Оказывается, есть к чему. Сотрудничать с Россией НАТО готова по весьма определённому кругу тем. Это «противоракетная оборона, борьба с терроризмом, наркотики, пиратство и укрепление международной безопасности». Остановлюсь лишь на некоторых.
Как известно, лидеры стран НАТО одобрили идею создания для евроатлантического региона системы противоракетной обороны, способной защитить территорию всех стран-членов НАТО. Только после этого России предложено «посотрудничать» с альянсом по вопросу ПРО.
Создание полномасштабной, или территориальной, ПРО предполагается на основе противоракетной обороны от баллистических ракет на театре военных действий, реализация которой началась в 2005 году. Одним из компонентов новой ПРО должна стать поэтапная система ПРО США, о которой было объявлено Обамой и которая пришла на смену планам размещения элементов ПРО в Польше и Чехии. Планируется, что новая система будет развернута в четыре этапа в 2011—2020 гг. и покроет все европейские государства НАТО. Однако окончательно решить этот вопрос без России невозможно. Поэтому одним из центральных вопросов саммита Совета Россия — НАТО является участие Москвы в проекте ЕвроПРО.
В то же время имеет смысл внимательно отнестись к словам Расмуссена, который реалистически смотря на вещи, видит «не одну единую систему, а две системы ПРО — НАТО и России, которые тесно взаимодействуют. Главными элементами этого взаимодействия должны стать обмен тактической информацией, обеспечение большего радиуса действия систем, что, в свою очередь, даст большую эффективность» (3). По всей видимости, от российской стороны в очередной раз потребуют «большей прозрачности», что выльется в открытие стратегически важных объектов для натовских генералов.
Еще одна тема — «борьба с терроризмом и наркотиками», непосредственно затрагивающая интересы России, связывается с «постепенной передачей контроля над безопасностью в Афганистане самому афганскому народу» (3). Как сообщил советник Президента США по Афганистану Дуглас Лут, США «планируют завершить этот процесс на территории 34 провинций к концу 2014 г. , начав его в 2011 году», что без помощи России сделать будет очень сложно, если не невозможно.
Высокопоставленные американские чиновники отмечают, что операции НАТО в Афганистане являются неотъемлемой частью общей Стратегической концепции. В результате по итогам саммита Россия — НАТО будет расширено соглашение об упрощенном транзите грузов через территорию РФ для сил НАТО в Афганистане и, что особенно важно, из Афганистана, продолжится дискуссия о приобретении для Афганистана партии российских вертолетов в едином пакете с услугами по их сервисному обслуживанию и подготовке пилотов и техников. Наконец, Россия и НАТО готовы расширить центр в Домодедово по подготовке кадров для антитеррористических структур Афганистана, Пакистана и стран Центральной Азии.
Важным вопросом сотрудничества с РФ НАТО считает также сокращение вооружений. По этому поводу требования, как мне представляется, означают буквально вмешательство во внутренние дела: «В будущем при любом сокращении нам следует добиваться согласия России на увеличение прозрачности ее ядерного арсенала в Европе и передислокации этого оружия подальше от территории членов НАТО. Любые дальнейшие шаги должны принимать во внимание неравенство и наличие у России более крупных запасов ядерного оружия малого радиуса действия (курсив мой — Е.П.)». Вот вам и стратегическое партнёрство! Напомню, что разработка новой концепции проходила на фоне активной работы республиканцев в Сенате США по замораживанию процесса ратификации нового договора по СНВ, и ратификации, скорее всего, в 2010 году не будет. В такой обстановке заявления Б. Обамы о том, что ратификация Договора СНВ-3 является императивом национальной безопасности и краеугольным камнем в отношениях США и России остаются пустым звуком. А «перезагрузка» в отношениях с НАТО, о которой говорил американский президент накануне саммита, означает лишь односторонние уступки со стороны России.
Также остались зафиксированными в Концепции вопросы, вызывающие существенную обеспокоенность России. Прежде всего, это расширение Североатлантического союза, которое трактуется им как исключительно позитивное явление. «Перспектива дальнейшего расширения и дух сотрудничества в обеспечении безопасности способствовали более широкому распространению стабильности в Европе (Особенно это заметно в Боснии, Македонии, Косове, Сербии — Е. П.)». Наша цель — единая и свободная Европа, разделяющая общие ценности. Ее достижению лучше всего будет способствовать возможная интеграция всех европейских стран, которые хотят войти в Евроатлантические структуры». Не могу не привести высказывание Расмуссена по этому поводу, которое лишний раз убеждает в том, что ОНИ и МЫ говорим на разных языках. Генсек НАТО убежден, что «Россия только выиграла от расширения НАТО, поскольку впервые в своей истории получила стабильных и предсказуемых соседей вдоль всей своей западной границы… что было ее мечтой на протяжении веков». Оказывается, расширение НАТО — это реализация многовековой мечты русских! Следующее его мнение заставляет вообще усомниться в его компетентности: «после восстановления безопасности в Восточной Европе впервые с момента падения коммунистической диктатуры в этом регионе начался экономический бум, который, если посмотреть на статистику, также принес России значительные выгоды» (4).
В новой Концепции зафиксировано, что двери НАТО «остаются широко открытыми» для новых членов. С этой целью альянс подтвердил намерение «продолжать и развивать» сотрудничество с Украиной и Грузией «в формате Комиссий Грузия — НАТО и Украина — НАТО». В Концепции не говорится о сроках вступления этих стран, однако уточняется, что сотрудничество должно строиться на базе «решений саммита НАТО в Бухаресте 2008 года, и принимая во внимания евроатлантические устремления и ориентацию каждой из этих стран».
Как известно, в Бухаресте альянс принял несколько туманную политическую декларацию о том, что «Грузия и Украина со временем смогут стать членами НАТО» (5). В связи с этим уместно вспомнить, что еще Вашингтонская стратегия 1999 г. зафиксировала твердую линию НАТО «на дальнейшее укрепление особых отношений партнерства с Украиной (курсив мой — Е.П.)… включая политические консультации по вопросам, представляющим предмет озабоченности для обеих сторон, и по широкому кругу вопросов, касающихся практических аспектов сотрудничества» (пункт 37) (6). И замечу, что от этой линии альянс не отступает. Только к Украине как объекту интереса НАТО добавилась Грузия, не за горами и Молдавия.
И, наконец, последнее, но не менее, а, может, более значимое положение. «Оборона конкретных территорий более не является главной функцией НАТО. Центр внимания перемещается на угрозы и задачи, которые могут возникать в разных местах и в разных формах (курсив мой. — Е.П.). Примеры — терроризм, международная преступность. В Стратегии также упомянута энергетическая безопасность, даже, несмотря на то, что в этой области НАТО не будет играть главную роль. Очень большое значение теперь будет придаваться кибербезопасности» (7). Реализация этих положений также требует участия России.
Итак, заинтересованность НАТО в укреплении взаимодействия с Россией имеет очень простые объяснения. Во-первых, на Россию можно переложить часть материального бремени и моральной ответственности за «афганский вопрос». Во-вторых, без России невозможно запустить проект ЕвроПРО (нужны российские РЛС). В-третьих, Россия пока ещё нужна как постоянный член СБ ООН в обеспечении будущих операций, требующих решений этого органа. В-четвертых, как отмечают сторонники сближения России и НАТО, наша страна «играет важную роль в преодолении так называемого „идентификационного кризиса“ альянса, выйти из которого без налаживания качественно новых отношений с Россией невозможно. Кроме того, укрепление отношений с Россией будет способствовать тому, чтобы показать релевантность альянса в глаза общественности. Наконец, очень существенное улучшение наших отношений позволит преодолеть опасную напряженность на постсоветском пространстве» (8). Иными словами, авторитет России поможет расширению НАТО.
Осознавая всё это, никаких особых преференций России Североатлантический союз тем не менее не предоставил.
Вывод один: никакого действительного, тем более стратегического, партнёрства между Россией и НАТО на условиях новой натовской Концепции быть не может.