Нейрокурятник часть 2: про бота, который постит фотографии
- пятница, 19 мая 2017 г. в 03:15:39
Сначала немного про питоновский скрипт из прошлой статьи. Скрипт претерпел изменения, например, мы отказались от контуров совсем, поправили некоторые баги, связанные со счетчиком движения, который игнорировался, и связанные со временем аплода. Но это все вещи простые и при желании легко правятся.
Ранее я упоминала про то, как я запускаю этот скрипт. Делала я это при помощи вечных ssh-сессий, но вот проблема: мне нужно уехать и взять с собой ноутбук, на это время я не могу поддерживать ssh-сессию. Очевидное решение — сделать демона в бекграунде, где он будет работать независимо.
Оказалось, что просто отправить процесс в бекграунд недостаточно, при смерти сессии процесс тоже погибает. Для того, чтобы сделать полноценного демона, процесс нужно отвязать от терминала-оунера. Для этого есть несколько способов и вот тут есть подборка методов и дополнительная информация.
Вторая проблема заключалась в виртуальной среде. Мне был нужен питон из виртуальной среды для работы скрипта. Решение оказалось безумно простым, достаточно просто прописать путь к виртуальной среде при вызове. В итоге для превращения моего процесса в демона оказалось достаточным запустить его вот так:
/home/sshuser/.virtualenvs/cv/bin/python3 /home/sshuser/chickencoop/pi_surveillance_mod2.py --conf /home/sshuser/chickencoop/conf.json </dev/null &>/dev/null &
Теперь про бота, который спамит моей маме фотографии кур из курятника в режиме реального времени. Там пока нет никакой аналитики и распознаваний, и бот просто постит фотографии по детекции движения. И там все еще криво висит камера, и вместо куриных голов наблюдаются сплошные хвосты.
Бот неказистый и простой. По событию создания файла на сервере проверяются его расширение и домашняя директория, и в случае успеха, вызывается питоновский скрипт, который делает реквест в API мессенджера (постит фотографию на канал) и пишет логи в обычный текстовый файл (можно парсить ответ и складывать в базу, но нет надобности).
Чтобы сделать такого бота в Telegram, вам нужно:
С первыми двумя пунктами все просто, третий тоже прост до скучноты с учетом того, что у телеграма хорошо документированное API и вам понадобится всего один метод.
Для отслеживания события создания файла я использую bash-скрипт, события слушает inotify-tools. Скрипт отправки вызывается не сразу, а после 10-ти секундного ожидания. Сделано это потому, что файл загружается еще некоторое время после создания, а с учетом прекрасной скорости интернета в курятнике, опытным путем установлено, что 10 секунд — самое оно.
#!/bin/sh
DIR="/your/directory"
inotifywait -m -r -e create --format '%w%f' "$DIR" | while read f
do
PARDIR="$(dirname $f)"
PARFOLD="$(basename $PARDIR)"
FBASENAME="$(basename $f)"
FILEEXT="${FBASENAME##*.}"
EXT="jpg"
FOLD="resized"
if [ $FILEEXT = $EXT ]; then
if [ $PARFOLD = $FOLD ]; then
# sleep til file is uploaded
sleep 10
python3 /your/directory/bot_request.py --params /your/directory/params_public.json -f $f
fi
fi
done
bot_request.py:
import requests
import json
import datetime
import argparse
import warnings
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--params", required=True,
help="params json. chat, token")
ap.add_argument("-f", "--file", required=True,
help="file path")
args = vars(ap.parse_args())
# filter warnings, load the configuration and check if we are going to use server
warnings.filterwarnings("ignore")
params = json.load(open(args["params"]))
# set url and post data
payload = {"chat_id": params["chat"],
"caption": "motion detected {ts}".format(ts=datetime.datetime.now().strftime("%A-%d-%B-%Y-%I:%M:%S%p"))}
url = "https://api.telegram.org/bot" + params["token"] + "/sendPhoto"
files = {'photo': open(args["file"], "rb")}
# post request
request = requests.post(url, files=files, data=payload)
# log the output
with open("/path/to/your/botlogs/{dt}-{chat}.txt".format(dt=datetime.datetime.now().strftime("%d-%B-%Y"), chat=params["type"]), "a") as logfile:
logfile.write("\n" + request.text)
params_public.json:
{
"chat": "@your_chat",
"token": "your_tocken",
"type": "public"
}
Вот, собственно, и все, максимально простое и работающее решение готово.
Немного болтовни. Кто-то сочтет за нытье — go ahead and do whatever you want. Главный посыл этой части статьи — если кто-то критикует вас, не предлагая в ответ хотя бы направления, в котором надо искать ответ, не расстраивайтесь. Нет, делать прототипы и решать задачи, получать опыт можно и без знания всего и вся. Человек не может знать все. Я не верю, что есть люди, которые не ошибаются, и которым знания спускаются в виде откровений с небес.
Я кратенько расскажу, что я думаю по этому поводу. Надо добавить, что я просто делюсь своим мнением, никому не навязывая, никого не призывая принимать его за чистую монету.
Начну, пожалуй, с того, что я не разработчик. Может быть, я им когда-нибудь стану, как знать. Вследствие того, что я не разработчик, языки программирования в большей степени я использую сугубо как инструмент для прототипирования и решения задач, для которых не требуется реализовывать робастную систему, проходящую через множество итераций разработки, поддержки, обрастания всяким инструментом отслеживания состояния, отчетами и аналитикой и т.д. В общем, мне редко приходится задумываться об архитектуре. Простейший пример: нужно почистить конкретный датасет. Проще сделать это в питоне, сделать один раз и выкинуть код на помойку.
Поэтому, когда я пишу код, мне всегда очень не хочется выкладывать его в паблик. Потому что я знаю, что я сделала что-то неправильно, не по канону. И, самое важное, я всегда знаю, что будет критика. Найдется хотя бы один человек, который знает, как нужно сделать, но он не предложит решение, не даст никакого ключа к пониманию, он просто скажет что-то из разряда «У вас все неправильно, все не работает, вы никчемный человек (а я Д'Артаньян, но я не скажу, почему, и не предложу ничего взамен вашей коряво написанной статье, потому что не хочу)».
Из моего кода, который действительно попал на бой, можно выделить разве только хранимые процедуры бд и систему рассылки аналитических отчетов в компании по крону. Она была написана на php, и там было некое подобие архитектуры.
Теперь, когда гордые джава сокола закрыли статью, php приматы, и я среди них, почесали низкий покатый лоб (на этом моменте статью закрыли ещё и они), я продолжу.
Нужно читать документацию, статьи, книги, но это не поможет без решения реальных задач. А если вы каждую задачу будете решать по канону — вы никогда не сделаете даже работающего прототипа. Серьезно. Никогда.
Не забывайте, что все сложные системы начинались с простого. И когда вводили что-то еще, они знали, ЗАЧЕМ они это ввели. Если вы пытаетесь изучить систему, которая уже обросла этими нововведениями настолько, что сложность зашкаливает, вы зачастую не знаете, зачем в ней присутсвуют те или иные явления, процессы, функционал. Это черные ящики, и временами их изучение напоминает зубрежку похуже, чем гуманитарные предметы. А все потому, что вы не знаете, ЗАЧЕМ. Вы не видите логику.
Если вам говорят, что это вы тупой, не понимаете, что к чему, не разобрались в этой элементарщине, там и так все понятно (провидцы и пророки, как я их называю), не переживайте. Вы не пророк, вы не можете знать, что взбрело в голову людям, которые эту систему писали, какие костыли (отход от канонов во имя работающего функционала) они туда позасовывали и зачем. Если еще и нет документации (адекватной документации, а не трех слов про то, что есть такой метод в лучшем случае), как это частенько бывает, то вообще невозможно ничего понять, не пройдя сквозь ведра помоев, которые пророки будут лить на вас в ответ на каждый ваш вопрос (вместо полезной информации). Я не знаю, почему, но почему-то в IT это правило с редкими исключениями.
Нейрокурятник — пример системы, которая рождается прототипом и никогда не станет полноценной системой и полноценным продуктом. Это просто хобби, обучение на реальной задаче, у которой нет монетизируемого применения. Она не будет масштабироваться.
Я не знаю Python. Я просто его использую в данном случае, попутно узнавая. Точно так же я не умею писать bash-скрипты. Но если я буду вопринимать всерьез комментарии, что мне не нужно писать код, не нужно ничего подобного делать, то я никогда ничему не научусь.