Python-скрипты

Telegram Agent можно расширять своими скриптами на Python. Скрипт — обычный файл рядом с настройками, который подключается к конвейеру продукта и берёт на себя то, чего не хватает готовым средствам. Достаточно положить файл — пересобирать и перезапускать приложение не нужно. Так подключают сервис, для которого нет готового источника, относят сообщения к категориям и тегам по своим правилам, чистят и дополняют текст перед публикацией или отправляют комментарий своим способом.

Это возможность для тех, кто готов писать код; остальные разделы продукта в скриптах не нуждаются, и часто скрипт — это десяток строк.

Где лежат скрипты

Все определения живут в папке настроек /project/apps/telegram/scripts/ — в том же постоянном томе, что остальные настройки. Один скрипт — один файл настроек с числовым именем (например, 1.yml):

id: 1
name: Разбор по ключевым словам
description: Зачем этот скрипт — видно в разделе «Скрипты»
isActive: true
timeoutSec: 30
passEnv: [HTTP_PROXY]
env:
  API_TOKEN: секрет
code: |
  import json, sys
  ctx = json.load(sys.stdin)
  print(json.dumps({"categoryIds": []}))
  • название и описание — чтобы через полгода было понятно, что это и зачем;
  • включение — выключенный скрипт не обслуживает подключённые к нему места: конвейер ведёт себя так, будто подключения нет, а в журнале остаётся отметка «пропущено»;
  • предельное время — сколько секунд ждать ответа (по умолчанию 60, потолок — 10 минут); по истечении процесс останавливается;
  • переменные окружения — постоянные значения для запуска: адреса, ключи доступа. Можно также перечислить, какие переменные окружения сервера передавать скрипту;
  • код — либо прямо в файле настроек, либо отдельным файлом .py рядом с ним: как удобнее. Отдельный файл читается с диска на каждом запуске, поэтому правка в нём видна сразу.

Библиотеки, которые нужны скриптам, перечисляются в одном общем файле scripts/requirements.txt. Рабочее окружение Python приложение готовит само при первом запуске — отдельно его настраивать не нужно. Правка файлов применяется на лету, без перезапуска приложения. Удалить скрипт, на который что-то ссылается, продукт не даст: сначала отключите его от места подключения.

Правила выполнения

Общие правила задаются в отдельном файле script-runner.yml рядом с папкой скриптов и применяются на лету. Если файла нет, действуют значения по умолчанию:

  • общий выключатель — одно переключение запрещает все запуски; каждое подключённое место честно сообщит, что выполнение отключено, а не сделает вид, что всё в порядке;
  • программа Python — какой именно python запускать (по умолчанию python3);
  • предельное время — 60 секунд на запуск, потолок — 10 минут;
  • одновременные запуски — по умолчанию не больше двух процессов сразу, чтобы скрипты не перегружали сервер;
  • предел вывода — 1 МиБ на запуск; данные большего размера остаются в рабочей папке, а скрипт возвращает ссылку на файл.

Семь точек подключения

Скрипт может быть классификатором, сборщиком или преобразователем текста — всего семь мест в конвейере:

Классификация — сообщения сами получают категории и теги:

  • Роутер — скрипт получает сообщение и список ваших категорий, а возвращает те, что подходят: {"categoryIds": [...]}. Это тип роутера «Скрипт» в разделе Маршрутизация. Идентификаторы, которых больше нет в справочнике, просто отбрасываются;
  • Теггер — то же самое, но для тегов: скрипт возвращает {"tagIds": [...]}.

Сбор контента — сообщения приходят из вашего источника:

  • Источник — скрипт сам забирает сообщения из любого сервиса: получает настройки источника и возвращает найденное списком, не больше 500 записей за один запуск. Позиции чтения скрипт хранит в своей рабочей папке. Подробнее — Источники.

Преобразование текста — текст правится по дороге:

  • Приём сообщения — скрипт правит текст собранного сообщения до сохранения: убрать лишнее, привести к единому виду;
  • Элемент очереди — скрипт правит будущую публикацию в момент, когда она попадает в очередь: дополнить текст или сразу перевести её в нужное состояние;
  • Черновик публикации — скрипт получает готовый текст перед отправкой и заменяет его своим. Так подставляются подпись канала, хэштеги или ссылки. Работает и для предпросмотра, и для самой публикации — текст везде одинаковый;
  • Генерация комментария — скрипт получает готовый текст комментария перед отправкой и заменяет его своим. Подробнее — Комментарии с ИИ.

Обращения со скриптами щадящие и строгие. Классификация и правки на приёме и в очереди щадящие: если скрипт сломался, сообщение (или элемент очереди) сохраняется как есть, а сбой остаётся в журнале — один сбой не должен терять контент. Публикация и комментарий строгие: если скрипт сломался или не вернул текст, отправка не происходит, и попытку можно повторить. Так непереработанный текст никогда не уходит в канал. Сбор контента — отдельный случай: если скрипт не смог собрать сообщения, ошибка записывается в источник, а следующая подкачка повторяет попытку — уже собранное не теряется.

Как проходит запуск

  • каждый запуск — отдельный процесс Python: он запускается, отдаёт ответ и завершается;
  • на вход приходит один документ JSON: точка подключения, имя скрипта, откуда запуск, данные и аргументы. Читается привычным json.load(sys.stdin);
  • ответ — тоже JSON: последний цельный объект, который скрипт напечатал. Сообщения о ходе работы печатать можно, они не мешают;
  • у каждого скрипта своя рабочая папка, которая сохраняется между запусками: там удобно держать файлы, позиции чтения и промежуточные результаты;
  • размер данных ограничен: если данных много, передавайте не сами данные, а ссылку или файл в рабочей папке;
  • процесс не получает секретов приложения: ему доступны только служебные значения и те переменные, которые вы сами перечислили в его настройках.

Раздел «Скрипты»

В боковой панели есть раздел «Скрипты» — страница наблюдения за запусками. Определения здесь читаются, а не правятся: правка файла и есть изменение, а создание и тестовый запуск идут через API.

  • состояние среды сверху: есть ли Python, собран ли набор библиотек, сколько запусков и сбоев было за сутки, что случилось в прошлый раз;
  • список скриптов: включён или выключен, откуда берётся код, к чему подключён, когда запускался в последний раз;
  • история запусков: время, точка подключения, откуда запуск, объект, длительность, код выхода и результат — или понятная причина сбоя. Фильтры — по состоянию и точке подключения;
  • сбой назван по-русски и понятен без расшифровки: «Среда недоступна» (нет рабочего Python или не собрались библиотеки), «Таймаут», «Неверный вывод» (скрипт не напечатал цельный JSON), «Вывод слишком велик», «Отменён», «Отключён», «Скрипт не найден»;
  • журнал хранится 30 дней и чистится сам.

Сбой скрипта никогда не подменяет данные молчанием: у классификации это просто отсутствие совпадения, у правки текста — запись как есть, у строгих точек — отказ отправки с причиной. Во всех случаях запуск остаётся в журнале с точным временем и ошибкой.

Внешний API

Тем же набором команд можно управлять извне — через внешний API с ключом из настроек: посмотреть список скриптов и состояние среды, прочитать определение и историю запусков, создать или изменить скрипт, удалить его и выполнить тестовый запуск. Роутеры и теггеры типа «Скрипт» тоже настраиваются через внешний API; источники и преобразования текста задаются в файлах настроек. Подробнее — Агент.

Граница доверия

Скрипты — это ваш собственный код, и запускаются они с правами приложения: отдельной изоляции между скриптом и сервером нет. Поэтому держите их в системе контроля версий вместе с папкой настроек и не запускайте чужие файлы. Если нужна полная изоляция — разворачивайте всё приложение в отдельном контейнере, что и делает стандартная установка. Секретным переменным скрипта стоит уделять то же внимание, что и паролям подключения.

Читайте также: Маршрутизация, Источники, Очередь контента, Публикации, Комментарии с ИИ.

← Оглавление документации