Всем привет! Меня зовут Катя и я backend разработчик. Пишу в основном на java, иногда на kotlin. В один прекрасный день мне пришла в голову мысль написать чат-бота для телеги. В силу специфики своей работы я начала с написания spring boot приложения на java, потом меня понесло в прикручивание БД, медленно все перетекло в тему создания сервиса как такового и до момента собственно вызова рестов ботом телеграмм не дошло ????.
В следующем подходе я подумала: а почему java, давай возьмем python. У меня был небольшой опыт написания на этом языке - и я решилась - начну снова с "Здравствуйте, мир!" только сразу в рамках проекта чат-бот телеграмм. На просторах интернета нашла крутую библиотеку с звучным именем natasha. Идея бота следующая: вы скачиваете свой чатик из одного ныне запрещенного мессенджера и этот .txt
файл отдаете боту. Он находит ТОП 10 существительных и глаголов из вашего чата ????. Далее пройдемся по шагам.
Организационная часть
Найти в телеграмм пользователя https://t.me/BotFather - он бог всех ботов.
Передать ему команду
/newbot
для создания нового бота. Назвать своего бота и обязательно концовка имени должна быть Bot. Имя моего -analyzeYourChatBot
В ответном сообщении отец ботов вышлет вам токен доступа к API.
Так же можно сразу задать описание вашему боту путем вызова команды
/setdescription
а так же поставить аватар/setuserpic
Функционал бота
Вернемся к идее бота: взять .txt
-файл, считать содержимое, очистить текст от ненужных штук, разбить на слова, понять что из них существительные, а что глаголы, подсчитать количество каждых и вывести ТОП 10.
Итак, основной участник действий - функция analyze
, которая примет в себя контент файла. Далее построчно: 46
- приведем все слова в нижний регистр47
- избавимся от текста с паттерном даты и отправителя сообщения вида [16.09.2021, 17:10:20] Katerina: А что осталось сегодня?
Тестировала паттерн в удобном онлайн-сервисе regex10148
- оставим в тексте только русские слова и пробелы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
Заключительное слово
В целом мне очень понравилось писать на питоне - это быстро и очень увлекательно. Докер как всегда рулит. Спасибо за внимание и можно кидать в меня помидорами в коментах ????.
Комментарии (18)
Rad_66
23.09.2022 21:29+1И к чему минус и такие комментарии? человек поделился своим наработками хорошо сделал плохо он поделился а тут )) такое ощущение что тут не сообщество близких по интересам людей о клуб элитных ХАХЕРОФ негоже)
0xf331d34d
24.09.2022 13:17+3Объясню почему минусы.
Название статьи сходу отдает неким хвастовством - "За один день". Вау, невероятно, мы рады, но зачем здесь такое на Хабре? Смайлики и всякие лол зачастую идут туда же.
Сама статья по себе hello world бот на питоне, коих тут и так тысячи, ничего нового не привнесла.
vrestles Автор
24.09.2022 14:01+6Спасибо, поняла. Согласна, тема статьи не нова. А заголовок и посыл статьи в том, что не стоит боятся начать что-то писать: 1) это не так сложно 2) это не так долго. Скорее она более мотивационная, чем новаторская. Но я поняла, что это статья не для хабра
temamagic
25.09.2022 06:55Кажется, что вы просто не совсем поняли сами, для кого пишете эту статью.
Для специалиста ничего нового. Для новичка почему-то кажется что потребуется больше деталей. Мотивационная часть выражена слабо, либо я не заметил.
Про хвастовство сказали выше.
Я такой себе писатель, но вот +- средний сценарий для такой статьи:
1) introduce yourself (Я - Катя...)
2) Боль которая есть сейчас (???, допустим, страстное желание знать топ 10 по существительным и глаголам в том самом месенджере)
3) Как сделать (Телеграм бот с разделением слов на сущ. и глаг. с либой natasha)
4) Драма (Чорт, знаю только java и котлин)
5) Мотивация (Задачка на день, новый амбициозный проект, кину вызов себе и изучу питон ради natasha)
6) Результат что получилось и как, что открыла для себя нового (не просто "мне понравилось", а наверняка узнала что-то из особенностей работы), сколько потратила чашек кофе
При этом код желательно прятать под кат (чтобы не читать полотно кода кому не интересно) и разбавить картинками (хотя бы пример работы бота, вы же его проверили в бою?)
Ну и я ожидал что с таким заголовком в конце будет какой-то вау, в духе что вы это все сделали за 1 день и еще и бот стрельнул где-то)
Заметка для хозяюшки:
Для ботов на питоне, в будущем, лучше взять aiogram, она во многом удобнее, приятнее и у нее есть большое русскоговорящее коммьюнити
sunsexsurf
25.09.2022 11:04Меня смутило именно то, что было написано «чат-бот». Я искренне думал, что автор прикрутит NLP-модели типа Берт или ДипПавлов для того, чтобы «поддерживать диалог». А так - тупо txt передали и там уже Наташа все посчитала. Кстати, ради такого тащить в проект целую библиотеку - не самое лучшее решение, как по мне.
vrestles Автор
25.09.2022 11:33Да, бот очень тупой, а так просто посмотрела на возможности Наташи ) но я не специалист в области data science. В начале статьи написала, что я занимаюсь вообще другим. Видимо лучше писать статью по своему профилю)
vrestles Автор
25.09.2022 11:31Благодарю за обратную связь! Особенно приятно получить развернутый ответ от профессионала в этой области. Учту ваши советы при написании следующей статьи. Не особо удачный выход на просторы хабра =)
gavk
25.09.2022 21:02По поводу Dockerfile: сначала идут команды, которые меняться не будут или вероятность их изменения очень мала. А потом уже копирование исхрдного кода. То есть сначала установка модулей, а потом уже копирование скриптов.
Vasyan282
26.09.2022 10:23Кэт.
Ты большая умница. Не обращай внимание на недалёких людей, которые тебя гнобят. Они сами забыли, как открывали для себя волшебство кода с простейших задач, а другие ничего не умеют, поэтому их колбасит от того, что кто-то развивается и становится успешным.
Верь в себя, улучшай свои навыки, и никогда не сдавайся. На этом тебя крепко обнимаю.vrestles Автор
26.09.2022 10:26Спасибо за поддержку! У меня ещё не так много опыта в разработке, как у старожилов тут. Но мне это интересно и я планирую развиваться дальше. В том числе и благодаря такой обратной связи.
hard2018
26.09.2022 10:47Зачем вам понадобился бот?
Я сделал сервис на php, но это мне было нужно, он ищет вакансии и заказы и отправляет по смс.
И ещё вопрос, мне можно статью отправлять на хабр?
webhamster
На коленке, Катя. Правильно говорить "на коленке".
На коленках сидят у кого-либо. На коленке пишут что-то по-быстрому.
ipatov_dn
Ну не удобно ей на одной писать, девушка, ножки стройные(я предпологаю) поэтому и на коленках
vrestles Автор
спасибо, поправила. узнала что-то новое ;) не была в курсе, что есть различия