Как я написала чат-бот для телеги на питоне и задеплоила его на удаленную машину за один день

от автора

Всем привет! Меня зовут Катя и я backend разработчик. Пишу в основном на java, иногда на kotlin. В один прекрасный день мне пришла в голову мысль написать чат-бота для телеги. В силу специфики своей работы я начала с написания spring boot приложения на java, потом меня понесло в прикручивание БД, медленно все перетекло в тему создания сервиса как такового и до момента собственно вызова рестов ботом телеграмм не дошло ?.

В следующем подходе я подумала: а почему java, давай возьмем python. У меня был небольшой опыт написания на этом языке — и я решилась — начну снова с «Здравствуйте, мир!» только сразу в рамках проекта чат-бот телеграмм. На просторах интернета нашла крутую библиотеку с звучным именем natasha. Идея бота следующая: вы скачиваете свой чатик из одного ныне запрещенного мессенджера и этот .txt файл отдаете боту. Он находит ТОП 10 существительных и глаголов из вашего чата ?. Далее пройдемся по шагам.

Организационная часть

  1. Найти в телеграмм пользователя https://t.me/BotFather — он бог всех ботов.

  2. Передать ему команду /newbot для создания нового бота. Назвать своего бота и обязательно концовка имени должна быть Bot. Имя моего — analyzeYourChatBot

  3. В ответном сообщении отец ботов вышлет вам токен доступа к API.

  4. Так же можно сразу задать описание вашему боту путем вызова команды /setdescription а так же поставить аватар /setuserpic

Функционал бота

Вернемся к идее бота: взять .txt-файл, считать содержимое, очистить текст от ненужных штук, разбить на слова, понять что из них существительные, а что глаголы, подсчитать количество каждых и вывести ТОП 10.

Итак, основной участник действий — функция analyze, которая примет в себя контент файла. Далее построчно:
46 — приведем все слова в нижний регистр
47 — избавимся от текста с паттерном даты и отправителя сообщения вида [16.09.2021, 17:10:20] Katerina: А что осталось сегодня? Тестировала паттерн в удобном онлайн-сервисе regex101
48 — оставим в тексте только русские слова и пробелы
49 — схлопнем несколько пробелов один
51-61 — копипаст кода из примеров использования библиотеки natasha. Если очень вкратце, то мы разделили текст на слова и определили какое слово существительное, а какое — глагол.
Далее формируем структуру данных с существительными и глаголами, находим количество каждого вхождения, сортируем и оставляем ТОП 10.

 #!/usr/bin/env python3  import re from string import whitespace from collections import defaultdict from natasha import (     Segmenter,     MorphVocab,     NewsEmbedding,     NewsMorphTagger,     NewsSyntaxParser,     Doc )  CYRILLIC_LETTERS = u"абвгдеёжзийклмнопрстуфхцчшщъыьэюя" TOP_COUNT = 10  def strip(text):     allowed_chars = CYRILLIC_LETTERS + whitespace     return "".join([c for c in text if c in allowed_chars])  def sort(data): result_dict = defaultdict(int) for key in data: result_dict[key]+=1 return sorted(result_dict.items(), key=lambda kv: kv[1], reverse=True)  def make_str(data): result = "" top_data = data[:TOP_COUNT] for key, value in top_data: result += key result += ": " result += str(value) result += "\n" return result  def find(data, type): result = [] for item in data: if (item.pos == type): result.append(item) return result  def analyze(data): text = data.lower() text = re.sub(r'\[\d{2}\.\d{2}\.\d{4}\, \d{2}:\d{2}:\d{2}\] .+?:', '', text, flags=re.MULTILINE) text = strip(text) text = re.sub(' +', ' ', text)  segmenter = Segmenter() morph_vocab = MorphVocab() emb = NewsEmbedding() morph_tagger = NewsMorphTagger(emb)  doc = Doc(text) doc.segment(segmenter) doc.tag_morph(morph_tagger)  for token in doc.tokens: token.lemmatize(morph_vocab)  nouns_dict = find(doc.tokens, 'NOUN') verbs_dict = find(doc.tokens, 'VERB')  nouns_lemmas = [_.lemma for _ in nouns_dict] verbs_lemmas = [_.lemma for _ in verbs_dict]  sorted_nouns_dict = sort(nouns_lemmas) sorted_verbs_dict = sort(verbs_lemmas)  res_nouns = make_str(sorted_nouns_dict) res_verbs = make_str(sorted_verbs_dict)  result = "ТОП " + str(TOP_COUNT) + " существительных в вашем чате:\n" result += res_nouns result += "\n" result += "ТОП " + str(TOP_COUNT) + " глаголов в вашем чате:\n" result += res_verbs return result 

Вызов функционала бота

В отдельном файле внутри папки проекта будут собраны методы-хендлеры (приемщики определенных команд). Я выбрала библиотеку pyTelegramBotAPI чтобы быстрее и эффективнее взаимодействовать с API телеги.

9 определяем константу с токеном, который нам прислал отец ботов
11 создаем инстанс объекта Telebot
64 запускаем этот инстанс в работу
Пишем простенькие функции на команды /start и /help которые просто отвечают простыней текста. Основной участник тут — get_document. В функции мы получим документ, проверим что он формата .txt, далее считаем содержимое из него и вызовем функцию из уже готового файла с предыдущего шага.

#!/usr/bin/env python3  import telebot import requests import analyze_chat import uuid import os   TOKEN = "blablabla"  bot = telebot.TeleBot(TOKEN)  @bot.message_handler(commands=['start']) def send_welcome(message):    bot.send_message(        message.chat.id,        'Привет!✌️ Я бот, который проанализирует твой диалог из WhatsApp \n' +        '(принадлежит признанной на территории РФ экстремисткой организации Meta). \n' +        'Скачай диалог (только на русском языке ??) и пришли боту в формате .txt.\n' +        'Для того, чтобы посмотреть как скачать весь диалог пройди на комманду /help.\n' +        '⚡️ Предупреждение! Ваши диалоги не сохраняются на стороне приложения, ' +        'однако потенциально могут быть перехвачены злоумышленниками по сети!'        )  @bot.message_handler(commands=['help']) def get_help(message):    bot.send_message(        message.chat.id,        '1) Пройдите в чат, который хотите проанализировать, из WhatsApp ' +        '(принадлежит признанной на территории РФ экстремисткой организации Meta). \n' +        '2) Провалитесь в настройки чата \n' +        '3) Нажмите "Экспортировать чат (Export chat)" -> Без медиа -> Сохраните на компьютер\n' +        '4) Разархивируйте и пришлите боту содержимое архива (по одному файлу если их несколько)'        )  @bot.message_handler(content_types=['document']) def get_document(message):    if (message.document.mime_type != 'text/plain'):       bot.reply_to(message, "Вы прислали файл, но он не в формате .txt ? Исправьте это недоразумение, пожалуйста")    else:       return analyze(message)        def analyze(message):    file_info = bot.get_file(message.document.file_id)    response = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(TOKEN, file_info.file_path))    random_file_name = "response_" + str(uuid.uuid4()) + ".txt"    with open(random_file_name, "wb") as f:       f.write(response.content)    text = get_text_from_file(random_file_name)    result = analyze_chat.analyze(text)    os.remove(random_file_name)    bot.reply_to(message, result)  def get_text_from_file(file_name):    f = open(file_name, "r", encoding="utf-8")    text = f.read()    return text  @bot.message_handler(func=lambda message: True) def echo_all(message):    bot.reply_to(message, "Я могу только принять файл в формате .txt ? Кажется это не он")   bot.infinity_polling()

Деплой этого всего дела

Итак, у нас имеется код, но он работает только тогда, когда у вас открыт ноут (лол). Вернемся на шаг назад и я скажу вам, что чтобы код работал — нужно установить две библиотеки:

pip install pyTelegramBotAPI pip install natasha

Ну и конечно должен быть установлен python ?. Теперь представьте, что все это надо будет установить на удаленной машине. Вспомним про докер. И используем силу докер-файла. Добавляю внутрь папки проекта Dockerfile и пишу следующее:
1 делаю образ на основе официального от питона
2,3 добавляю файлы с двумя написанными на предыдущих шагах скриптами
4,5 устанавливаю необходимые библиотеки для работы приложения
6 запускаю код

FROM python:3 ADD chatbot.py . ADD analyze_chat.py . RUN pip install pyTelegramBotAPI RUN pip install natasha CMD python3 ./chatbot.py

Далее создаем кастомный образ приложения на основе докер-файла:

docker build -t vrestles/analyze-chat-bot:latest -f Dockerfile .

Этот образ я переношу в докер-хаб в качестве приватного образа:

docker login -u vrestles -p ***** docker push vrestles/analyze-chat-bot:latest

Заметьте, что сначала я залогинилась и потом запушила образ.

Далее прохожу на удаленную машину — там уже установлен докер. И только он один кстати говоря. И все что мне нужно сделать опять залогиниться в докер и запустить приватный образ:

docker run -d vrestles/analyze-chat-bot:latest

К слову говоря, при запуске он сам поймет, что образ не скачан и пойдет сам за ним. Запуск произведен в дитач-режиме, что значит что он произведет запуск в фоне и отдаст только айдишник контейнера. Посмотреть запущенные контейнеры можно при помощи команды docker ps

Заключительное слово

В целом мне очень понравилось писать на питоне — это быстро и очень увлекательно. Докер как всегда рулит. Спасибо за внимание и можно кидать в меня помидорами в коментах ?.


ссылка на оригинал статьи https://habr.com/ru/articles/689812/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *