Dans le contexte du battage médiatique universel sur le coronavirus, j'ai décidé de faire au moins quelque chose d'utile (mais pas moins de battage médiatique). Dans cet article, je vais vous expliquer comment créer et déployer le Telegram Bot en utilisant des méthodes NLP basées sur des rÚgles en 2,5 heures (c'est le temps qu'il m'a fallu) pour répondre aux questions de la FAQ en utilisant le cas COVID-19 comme exemple.Au cours du travail, nous utiliserons le bon vieux Python, l'API Telegram, quelques bibliothÚques NLP standard, ainsi que Docker.

UFO Care Minute
La pandĂ©mie COVID-19, une infection respiratoire aiguĂ« potentiellement grave causĂ©e par le coronavirus SARS-CoV-2 (2019-nCoV), a Ă©tĂ© officiellement annoncĂ©e dans le monde. Il y a beaucoup d'informations sur HabrĂ© sur ce sujet - rappelez-vous toujours qu'il peut ĂȘtre Ă la fois fiable / utile, et vice versa.
Nous vous invitons à critiquer toute information publiée.
Lavez-vous les mains, prenez soin de vos proches, restez Ă la maison dans la mesure du possible et travaillez Ă distance.
Lire les publications sur: coronavirus | travail Ă distance
BrÚve préface
Cet article dĂ©crit le processus de crĂ©ation d'un Bot Telegram simple rĂ©pondant aux questions de la FAQ sur COVID-19. La technologie de dĂ©veloppement est extrĂȘmement simple et polyvalente et peut ĂȘtre utilisĂ©e pour tout autre cas. Je souligne encore une fois que je ne prĂ©tends pas ĂȘtre Ă la pointe de la technologie, mais seulement proposer une solution simple et efficace qui peut ĂȘtre rĂ©utilisĂ©e.Ătant donnĂ© que je crois que le lecteur de cet article a dĂ©jĂ une certaine expĂ©rience avec Python, nous supposerons que vous avez dĂ©jĂ installĂ© Python 3.X et les outils de dĂ©veloppement nĂ©cessaires (PyCharm, VS Code), vous pouvez crĂ©er un bot dans Telegram via BotFather, et par consĂ©quent, je vais sauter ces choses.1. Configurer l'API
La premiĂšre chose que vous devez installer est la bibliothĂšque d'encapsuleur pour l'API Telegram " python-telegram-bot ". La commande standard pour cela est:pip install python-telegram-bot --upgrade
Ensuite, nous allons construire le cadre de notre petit programme en définissant des "gestionnaires" pour les événements Bot suivants:- start - Commande de lancement de Bot;
- help - commande d'aide (aide);
- message - traitement des messages texte;
- erreur - une erreur.
La signature des gestionnaires ressemblera Ă ceci:def start(update, context):
pass
def help(update, context):
pass
def message(update, context):
pass
def error(update, context):
pass
Ensuite, par analogie avec l'exemple de la documentation de la bibliothÚque, nous définissons la fonction principale dans laquelle nous affectons tous ces gestionnaires et démarrons le bot:def get_answer():
"""Start the bot."""
updater = Updater("Token", use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler("start", start))
dp.add_handler(CommandHandler("help", help))
dp.add_handler(MessageHandler(Filters.text, message))
dp.add_error_handler(error)
updater.start_polling()
updater.idle()
if __name__ == "__main__":
get_answer()
J'attire votre attention sur le fait qu'il existe 2 mécanismes pour lancer un bot:- Interrogation standard - interrogation périodique de Bot à l'aide des outils standard de l'API Telegram pour les nouveaux événements (
updater.start_polling()
); - Webhook - nous démarrons notre serveur avec un point de terminaison, auquel les événements du bot arrivent, il nécessite HTTPS.
Comme vous l'avez déjà remarqué, pour plus de simplicité, nous utilisons l'interrogation standard.2. Nous remplissons les gestionnaires standard de logique
Commençons par une simple, remplissons le début et aidons les gestionnaires avec des réponses standard, nous obtenons quelque chose comme ceci:def start(update, context):
"""Send a message when the command /start is issued."""
update.message.reply_text("""
!
COVID-19.
:
- * ?*
- * ?*
- * ?*
..
!
""", parse_mode=telegram.ParseMode.MARKDOWN)
def help(update, context):
"""Send a message when the command /help is issued."""
update.message.reply_text("""
( COVID-19).
:
- * ?*
- * ?*
- * ?*
..
!
""", parse_mode=telegram.ParseMode.MARKDOWN)
Désormais, lorsque l'utilisateur envoie les commandes / start ou / help, il recevra la réponse que nous lui avons prescrite. J'attire votre attention sur le fait que le texte est formaté en Markdownparse_mode=telegram.ParseMode.MARKDOWN
Ensuite, ajoutez la journalisation des erreurs au gestionnaire d'erreurs:def error(update, context):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, context.error)
Maintenant, vérifions si notre Bot fonctionne. Copiez tout le code écrit dans un seul fichier, par exemple app.py . Ajoutez les importations nécessaires .Exécutez le fichier et accédez à Telegram ( n'oubliez pas d'insérer votre Token dans le code ). Nous écrivons les commandes / start et / help et nous réjouissons:
3. Nous traitons le message et générons une réponse
La premiĂšre chose dont nous avons besoin pour rĂ©pondre Ă la question est la base de connaissances. La chose la plus simple que vous pouvez faire est de crĂ©er un fichier json simple sous la forme de valeurs de valeur-clĂ©, oĂč ClĂ© est le texte de la question proposĂ©e et Valeur est la rĂ©ponse Ă la question. Exemple de base de connaissances:{
" ?": " â . - , , , . , , . , .",
" ?": " :\n \n \n \n \n\n , .",
" ?": " :\n- ( , , )\n- ( )",
}
L'algorithme pour répondre à la question sera le suivant:- Nous obtenons le texte de la question de l'utilisateur;
- Lemmatiser tous les mots du texte de l'utilisateur;
- Nous ne comparons pas clairement le texte résultant avec toutes les questions lemmatisées de la base de connaissances ( distance de Levenshtein );
- Nous sélectionnons la question la plus «similaire» dans la base de connaissances;
- Nous envoyons la réponse à la question sélectionnée à l'utilisateur.
Pour mettre en Ćuvre nos plans, nous avons besoin de bibliothĂšques: fuzzywuzzy (pour les comparaisons floues) et pymorphy2 (pour la lemmatisation).CrĂ©ez un nouveau fichier et implĂ©mentez l'algorithme sondĂ©:import json
from fuzzywuzzy import fuzz
import pymorphy2
morph = pymorphy2.MorphAnalyzer()
with open("faq.json") as json_file:
faq = json.load(json_file)
def classify_question(text):
text = ' '.join(morph.parse(word)[0].normal_form for word in text.split())
questions = list(faq.keys())
scores = list()
for question in questions:
norm_question = ' '.join(morph.parse(word)[0].normal_form for word in question.split())
scores.append(fuzz.token_sort_ratio(norm_question.lower(), text.lower()))
answer = faq[questions[scores.index(max(scores))]]
return answer
Avant d'écrire un gestionnaire de messages, nous allons écrire une fonction qui enregistre l'historique de la correspondance dans un fichier tsv:def dump_data(user, question, answer):
username = user.username
full_name = user.full_name
id = user.id
str = """{username}\t{full_name}\t{id}\t{question}\t{answer}\n""".format(username=username,
full_name=full_name,
id=id,
question=question,
answer=answer)
with open("/data/dump.tsv", "a") as myfile:
myfile.write(str)
Maintenant, nous utilisons la méthode que nous avons écrite dans le message du gestionnaire de message texte:def message(update, context):
"""Answer the user message."""
answer = classify_question(update.message.text)
dump_data(update.message.from_user, update.message.text, answer)
update.message.reply_text(answer)
Voila, allez maintenant à Telegram et profitez de l'écriture:
4. Configurer Docker et déployer l'application
Comme le disait le classique: "Si vous exécutez, alors c'est beau à exécuter.", Pour que nous ayons tout en tant que personnes, nous allons configurer la conteneurisation à l'aide de Docker Compose.Pour cela, nous avons besoin de:- Créer Dockerfile - définit l'image du conteneur et le point d'entrée;
- Create docker-compose.yml - lance de nombreux conteneurs à l'aide d'un seul Dockerfile (dans notre cas, ce n'est pas nécessaire, mais si vous avez de nombreux services, cela sera utile.)
- Créez boot.sh (le script est directement responsable du lancement).
Ainsi, le contenu du Dockerfile:#
FROM python:3.6.6-slim
#
WORKDIR /home/alex/covid-bot
# requirements.txt
COPY requirements.txt ./
# Install required libs
RUN pip install --upgrade pip -r requirements.txt; exit 0
#
COPY data data
#
COPY app.py faq.json reply_generator.py boot.sh ./
#
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
#
RUN chmod +x boot.sh
#
ENTRYPOINT ["./boot.sh"]
Le contenu de docker-compose.yml:# docker-compose
version: '2'
#
services:
bot:
restart: unless-stopped
image: covid19_rus_bot:latest
container_name: covid19_rus_bot
# boot.sh
environment:
- SERVICE_TYPE=covid19_rus_bot
# volume
volumes:
- ./data:/data
Le contenu de boot.sh:#!/bin/bash
if [ -n $SERVICE_TYPE ]
then
if [ $SERVICE_TYPE == "covid19_rus_bot" ]
then
exec python app.py
exit
fi
else
echo -e "SERVICE_TYPE not set\n"
fi
Donc, nous sommes prĂȘts, pour dĂ©marrer tout cela, vous devez exĂ©cuter les commandes suivantes dans le dossier du projet:sudo docker build -t covid19_rus_bot:latest .
sudo docker-compose up
VoilĂ , notre bot est prĂȘt.Au lieu d'une conclusion
Comme prĂ©vu, tout le code est disponible dans le rĂ©fĂ©rentiel .Cette approche, montrĂ©e par moi, peut ĂȘtre appliquĂ©e dans tous les cas pour rĂ©pondre aux questions de la FAQ, il suffit de personnaliser la base de connaissances! En ce qui concerne la base de connaissances, elle peut Ă©galement ĂȘtre amĂ©liorĂ©e en changeant la structure de la clĂ© et de la valeur en tableaux, de sorte que chaque paire sera un tableau de questions potentielles sur un sujet et un tableau de rĂ©ponses potentielles (pour un changement, les rĂ©ponses peuvent ĂȘtre choisies au hasard). Naturellement, l'approche basĂ©e sur les rĂšgles n'est pas trop flexible pour la mise Ă l'Ă©chelle, mais je suis sĂ»r que cette approche rĂ©sistera Ă une base de connaissances avec environ 500 questions.Ceux qui ont lu jusqu'Ă la fin, je vous invite Ă essayer mon Bot ici .