Всем привет! Этот материал я хотел бы посвятить работе функции code_executor в конструкторе чат-ботов SaleBot позволяющей запускать код на языке программирования Python.
Без долгих прелюдий, когда сталкиваешься с чем-то новым и необъяснимым в первую очередь нужно заглянуть в документацию. Вот здесь и посмотрим, что за зверь такой этот code_executor и что он может делать.
Как Вы можете заметить, документация не блещет подробностями. На сколько нужны все эти детали мы еще разберемся, но пока поработаем с тем, что есть.
К сожалению, так или иначе, стандартных возможностей самого языка программирования Python в общем-то не так уж и много. И серьезно усложнить программу и сделать нечто действительное полезное средствами только ЯП на практике сложно. А по тому часто применяются разного рода библиотеки. Это, если не вдаваться в подробности, уже реализованные кем-то определённые функции упакованные в нечто похожее на расширения которые можно подключать (импортировать) в проект.
При работе с проектом на языке Python у программиста есть такой инструмент как pip, который позволяет скачивать разного рода библиотеки, интегрировать их в окружение, что бы разработчик имел возможность использовать функции библиотеки в своем коде. В SaleBot такого инструмента нет, точнее он не доступен нам, простым смертным пользователям. Но разработчики конструктора уже подготовили окружение Python с определенным набором библиотек. Взглянув на этот список можно примерно понять, для чего пригодна функция code_executor, а с чем она работать не будет в принципе.
requests — библиотека позволяет нам легко и с минимальным количеством кода взаимодействовать с веб-приложениями
logger — библиотека для логирования кода, что бы можно было отслеживать ошибки (скорее всего добавлена в SaleBot только дабы не ломать код уже написанный с использованием библиотеки, результат работы этой библиотеки без терминала мы не увидим никак)
gspread — библиотека для работы с Google-таблицами
oauth2client — библиотека упрощающая клиентскую авторизацию по протоколу OAuth2
numpy — библиотека для манипуляции с сложными математическими ф-ми. Подробнее здесь
pyzbar — библиотека для работы с QR-кодом
fuzzywuzzy — библиотека для нечёткого сравнения. Расстояние Левенштейна. В основном используется для анализа текста, поиска в нем неточных совпадений.
python-Levenshtein — почти тоже самое, что и fuzzywuzzy
re — позволяет работать с регулярными выражениями regular expression (or RE)
urllib — модуль Python, который можно использовать для открытия URL-адресов. Он определяет функции и классы для обработки URL-адресов.
time — модуль для работы со временем в Python.
telethon — крутейшая библиотека для взаимодействия с Telegram. Умеет работать с аккаунтами, а не только с ботами.
json — позволяет кодировать и декодировать данные в формате JSON.
hmac — хэширование с ключом для аутентификации сообщений.
hashlib — реализует интерфейс для множества различных безопасных алгоритмов хеширования.
beautifulsoup4 — извлечения данных из файлов HTML и XML, сгодится для скраппинга.
pandas — программная библиотека на языке Python для обработки и анализа данных.
base64 — кодирование и декодирование строк Base64.
xmltodict — преобразовать XML в словари Python и к формату JSON.
mysql-connector-python — библиотека для работы с базой данный MySQL (MariaDB).
zeep — взаимодействия между информационными системами через web посредством SOAP.
google-api-python-client — библиотека для работы с Google-таблицами.
В общем даже беглого осмотра достаточно, что бы понять, что возможностей в целом достаточно много. Особенно доставляет возможность работы с QR-кодами, выполнять запросы которые требуют хэш-подписи (через API-блок в SaleBot такие не сделаешь), есть возможность очень гибкой работы с датой и временем, присутствует много возможностей по анализу текста и даже работа с базой данных MySQL/MariaDB.
1. Пишем первую функцию
И так, после того как мы выяснили, на что эта штука в принципе способна, пора бы написать первую пробную функцию, заодно разберемся с требованием к этой функции что бы она работала в рамках code_executor.
Первое и самое важное условие. Код пишем в отдельном файле с расширением *.py, это стандартное расширение для всех файлов исходного года на языке Python.
Второй момент. Файл с нашим кодом нужно разместить на ресурсе который позволяет получить доступ по прямой ссылке. Разного рода Яндекс Диск или Google Диск тут совсем не подойдут. Зато подойдет хранилище GetCourse, хостинг для php (там еще наверняка будет база данных MySQL/MariaDB) или любой другой ресурс на который можно загрузить файл и получить прямую ссылку на его загрузку.
Третий момент. В файле с нашим исходным кодом обязательно должна быть функция handle принимающая один аргумент data. В переменную data будут приходит данные в формате JSON.
Четвертый момент. Эта функция handle обязательно должна возвращать данные в формате JSON.
1 2 3 4 5 6 7 |
import json def handle(data): data = json.loads(data) sb_var = data["userdata"] status = json.dumps({"status": "ok", "result": 'Python: Со стороны SaleBot получено => ' + sb_var}) return status |
В конечном итоге самая простая, так называемая эхо-функция выглядит так как указано выше. Для работы с JSON мы импортируем одноименную библиотеку. В нашем файле есть функция handle с аргументом data. В 4й строке кода мы преобразовываем текст в формате JSON в словарь, в 5й строке по ключу userdata мы извлекаем данные которые отправляет SaleBot. Затем мы создаем переменную status в которую передаем JSON-объект в поле result которого содержится строка Python: Со стороны SaleBot получено => и дальше будет тот текст, который мы получили в поле userdata в объекте который пришел аргументом функции handle.
Для тестирования соберем элементарную схемку с двух блоков в SaleBot
В блоке состояния, в разделе калькулятор необходимо указать следующее:
Соответственно файл с кодом у меня был назван test.py (да да, очень оригинально) и размещен у меня на сервере. В переменную params мы записываем JSON-объект с полем userdata и содержимым переменной #{сообщение}. В этой переменной будет текст, который ввел пользователь. Естественно нужно не забыть эту переменную вписать в стрелку перед блоком и включить слайдер «Пользователь ввел данные». В дальнейшем результат работы функции handle будет записан в переменную result и в 4-й строке нашего калькулятора, мы получим значение поля result в переменной result (нет, не разу не запутано =) ) и запишем его в переменную r.
Оба значения, и переменной и поля в этой переменной отправим пользователю в блоке сообщение.
Вот теперь можно запустить бот и протестировать результат нашей работы.
В результате мы видим, что после подписи «Скрипт вернул данные:» у нас есть текст ответа функции в формате JSON. На абракадабру внимание можно не обращать, это кириллический текст в формате Unicode. Нормальная практика при кодировании кирилици в JSON. И соответственно в поле «Декодировано:» мы получили ту же строку, что ввели выше, но с подписью «Python: Со стороны SaleBot получено =>«, что является доказательством того, что мы всё сделали абсолютно правильно.
Практическое применение
Теперь казалось бы все замечательно и мы собрали эхо-бот с использованием code_executor. Однако во первых это можно было гораздо проще сделать штатными средствами SaleBot, да и взаимодействие с большинством сервисов можно наладить и с использованием более простых API-блоков. Но как бы не так и дальше поймете почему.
В качестве примера представим себе задачу: у нас есть отдел продаж который активно пользуется телефонией Zadarma. И было бы не плохо, что бы менеджеры отдела продаж могли оперативно просмотреть баланс на сервисе, но давать доступ к профилю Zadarma нам нельзя. Более того, нам нужно дать возможность просматривать баланс и через Telegram и ВКонтакте и, например, в WhatsApp.
Естественно в Zadarma/Новофон как и в большинстве подобных сервисов есть собственное API. Было бы логично посмотреть документацию Zadarma на предмет наличия нужного нам метода.
И вот да, у Zadarma есть метод позволяющий получить нам информацию о балансе. Осталось всего-то сделать запрос. Но здесь начинается самое интересное. Казалось бы, обычный GET-запрос без каких-либо даже параметров. Ответ в формате JSON. Берем в блоке SaleBot подставляем нужные значения и всё, но нет. Что бы понять, почему этот способ не сработает, нужно перейти в раздел «Примеры» документации сервиса телефонии.
Каждый запрос к API сервиса должен сопровождаться подписью в заголовке. Не смотря на то, что SaleBot умеет писать в заголовки, но читая документацию Zadarma дальше становится понятно, что для получения подписи нужно сделать несколько шагов. В частности для получения подписи необходимо выполнить ряд криптографических функций. Нужно рассчитать md5-хэш от строки запроса, а затем все полученные поверх прохэшировать с использованием hmac шифром sha1. На этом этапе становится ясно, что никакой функции хэширования в стандартном исполнении в SaleBot нет и близко. Следовательно нужно что-то изобретать. Например написать php скрипт реализующем нужную логику, залить его на хостинг, сделать запрос к этому скрипту….
Или взять функцию code_executor и написать всю необходимую логику там.
При более детальном изучении документации, можно узнать, что оказывается Zadarma предоставляет несколько библиотек для упрощенной работы с API сервиса. В списке библиотек, среди прочего, оказывается есть и библиотека написанная на языке Python, что собственно идеально нам подходит.
Подходит да не подходит, по тому, что в списке установленных в окружении функции code_executor нет и намека не на какую Zadarma. Тем не менее более внимательно рассмотрев код становится понятно, что по сути всю библиотеку сервиса мы можем упаковать прям в файл который отдадим на обработку функции code_executor. Необходимо будет только чуть-чуть дописать своего код.
Для этого перейдем на GitHub библиотеки
Далее следует нажать на зеленую кнопку Code и выбрать Download ZIP.
Скачиваем архив с библиотекой, распаковываем и сразу переходим в каталог zadarma. Собственно там и находится файл с нашей библиотекой. Файл api.py я для удобства сразу переименовал в zadarma.py
После нужно открыть этот файл в любом удобном вам текстовом редакторе и удалить первые две строчки с него.
А после дописать в этот файл функцию handle как того требуется документацией SaleBot. В этой функции реализуем требуемый аргумент data. В него мы передадим ключ и секрет полученные в разделе Интеграции и API сервиса Zadarma/Новофон
Так же в полученный файл скрипта мы импортируем библиотеки json (для коммуникации с SaleBot) и библиотеку logging. Общий вид измененного файла скрипта будет иметь следующий вид.
На скриншоте выше в желтом прямоугольнике я подсветил дополнительные библиотеки которые мы подключили к нашей модифицированной библиотеке Zadarma. В красном блоке показан непосредственно пример использования библиотеки сервиса. В 20й строке происходит инициализация. В 21й строке мы делаем запрос к сервису и записываем ответ API Zadarma в формате JSON в переменную r. Содержимое этой переменной и будет передано в SaleBot. Остальной код в функции handle это практически тоже самое что мы рассматривали в примере эхо-бота. Осталось только загрузить файл скрипта на GetCourse или любой другой сервис поддерживающий прямые ссылки. Я же загружу файл на свой сервер.
Теперь можно перейти в SaleBot. В конструкторе мы создадим аж целый один блок для обработки этой функции.
Для разнообразия возьмем блок типа «Не состояние с условием», вдруг в боте уже реализована еще какая-то клиентская логика или логика для работы ОП, что бы ей не мешать выберем такой блок.
В условиях запуска укажем команду balance
В тексте сообщения напишем, что будет отправлять бот в ответ на команду и воспользуемся дополнительными двумя переменными. А эти переменные будут записываться как раз в блоке калькулятор на скриншоте ниже.
Всего 5 строк в калькуляторе и наша функция позволяют полностью закрыть задачу с получением баланса аккаунта Zadarma.
Теперь можно сохранить все настройки и протестировать.
В результате мы получили информацию о балансе и валюте аккаунта. А вся задача, не считая времени на написания статьи заняла у меня максимум 15 минут. Благодаря использованию Python-скриптов функциональность SaleBot становится практически ничем не ограниченной. Конечно для таких подходов нужно понимание языка Python хотя бы на начальном уровне, понимания того, что такое JSON и т.д Но ввиду того, какое огромное кол-во обучающих материалов, включая бесплатные, сейчас существует изучение основ Python не должны стать большой проблемой. Тем более сам язык, его синтаксис достаточно простой для понимания.
Напоследок покажу как эта же функция работает в других мессенджерах подключенных к SaleBot.