No contexto do hype universal no Coronavírus, decidi fazer pelo menos algo útil (mas não menos hype). Neste artigo, falarei sobre como criar e implantar o Telegram Bot usando os métodos da PNL baseada em regras em 2,5 horas (o quanto me levou) para responder a perguntas frequentes usando o caso COVID-19 como exemplo.No decorrer do trabalho, usaremos a boa e antiga API Python, Telegram, algumas bibliotecas padrão de PNL, além do Docker.

Minuto de Cuidados com OVNI
A pandemia de COVID-19, uma infecção respiratória aguda potencialmente grave causada pelo coronavírus SARS-CoV-2 (2019-nCoV), foi anunciada oficialmente no mundo. Há muitas informações sobre Habré sobre esse tópico - lembre-se sempre de que pode ser confiável / útil e vice-versa.
Pedimos que você seja crítico com qualquer informação publicada.
Lave as mãos, cuide de seus entes queridos, fique em casa sempre que possível e trabalhe remotamente.
Leia publicações sobre: coronavírus | trabalho remoto
Prefácio breve
Este artigo descreve o processo de criação de um simples Telegram Bot, respondendo a perguntas frequentes no COVID-19. A tecnologia de desenvolvimento é extremamente simples e versátil e pode ser usada para qualquer outro caso. Enfatizo mais uma vez que não pretendo ser o estado da arte, mas apenas ofereço uma solução simples e eficaz que pode ser reutilizada.Como acredito que o leitor deste artigo já tenha alguma experiência com o Python, assumiremos que você já possui o Python 3.X instalado e as ferramentas de desenvolvimento necessárias (PyCharm, VS Code), você pode criar um Bot no Telegram via BotFather e portanto, vou pular essas coisas.1. Configure API
A primeira coisa que você precisa instalar é a biblioteca de wrapper para a API do Telegram " python-telegram-bot ". O comando padrão para isso é:pip install python-telegram-bot --upgrade
Em seguida, criaremos a estrutura do nosso pequeno programa, definindo "manipuladores" para os seguintes eventos de bot:- start - comando de inicialização do Bot;
- help - help command (help);
- mensagem - processamento de mensagens de texto;
- erro - um erro.
A assinatura dos manipuladores ficará assim:def start(update, context):
pass
def help(update, context):
pass
def message(update, context):
pass
def error(update, context):
pass
Em seguida, por analogia com o exemplo da documentação da biblioteca, definimos a função principal na qual atribuímos todos esses manipuladores e iniciamos o 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()
Chamo sua atenção para o fato de que existem 2 mecanismos para iniciar um bot:- Pesquisa Padrão - pesquisa periódica do Bot usando ferramentas padrão da API Telegram para novos eventos (
updater.start_polling()
); - Webhook - iniciamos nosso servidor com um endpoint, para o qual os eventos do bot chegam, ele requer HTTPS.
Como você já percebeu, por simplicidade, usamos o polling padrão.2. Nós preenchemos manipuladores padrão com lógica
Vamos começar com um simples, preencher o início e ajudar os manipuladores com respostas padrão, temos algo parecido com isto: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)
Agora, quando o usuário enviar os comandos / start ou / help, ele receberá a resposta prescrita por nós. Chamo a atenção para o fato de o texto estar formatado em Markdownparse_mode=telegram.ParseMode.MARKDOWN
Em seguida, adicione o log de erros ao manipulador de erros:def error(update, context):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, context.error)
Agora, vamos verificar se o nosso Bot funciona. Copie o código inteiro escrito em um único arquivo, por exemplo app.py . Adicione as importações necessárias .Execute o arquivo e vá para Telegram ( não esqueça de inserir seu token no código ). Escrevemos os comandos / start e / help e nos alegramos:
3. Processamos a mensagem e geramos uma resposta
A primeira coisa que precisamos responder à pergunta é a Base de Conhecimento. A coisa mais simples que você pode fazer é criar um arquivo json simples na forma de valores de valor-chave, em que chave é o texto da pergunta proposta e valor é a resposta para a pergunta. Exemplo da Base de Conhecimento:{
" ?": " — . - , , , . , , . , .",
" ?": " :\n \n \n \n \n\n , .",
" ?": " :\n- ( , , )\n- ( )",
}
O algoritmo para responder à pergunta será o seguinte:- Recebemos o texto da pergunta do usuário;
- Lematize todas as palavras no texto do usuário;
- Não comparamos claramente o texto resultante com todas as perguntas lematizadas da base de conhecimento ( distância de Levenshtein );
- Selecionamos a pergunta mais "semelhante" da base de conhecimento;
- Enviamos a resposta para a pergunta selecionada ao usuário.
Para implementar nossos planos, precisamos de bibliotecas: fuzzywuzzy (para comparações fuzzy) e pymorphy2 (para lematização).Crie um novo arquivo e implemente o algoritmo que soa: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
Antes de escrever um manipulador de mensagens, escreveremos uma função que salva o histórico de correspondência em um arquivo 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)
Agora, usamos o método que escrevemos na mensagem do manipulador de mensagens de texto da mensagem: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, agora vá ao Telegram e aprecie a escrita:
4. Configure o Docker e implante o aplicativo
Como o clássico disse: "Se você executar, é bonito executar". Para que tenhamos tudo como pessoas, configuraremos a conteinerização usando o Docker Compose.Para isso, precisamos:- Criar arquivo de encaixe - define a imagem do contêiner e o ponto de entrada;
- Create docker-compose.yml - inicia muitos contêineres usando um único Dockerfile (no nosso caso, não é necessário, mas, caso você tenha muitos serviços, será útil).
- Crie boot.sh (o script é responsável diretamente pelo lançamento).
Portanto, o conteúdo do 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"]
O conteúdo do 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
O conteúdo do 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
Então, estamos prontos, para iniciar tudo isso, você precisa executar os seguintes comandos na pasta do projeto:sudo docker build -t covid19_rus_bot:latest .
sudo docker-compose up
É isso aí, nosso bot está pronto.Em vez de uma conclusão
Como esperado, todo o código está disponível no repositório .Essa abordagem, mostrada por mim, pode ser aplicada em qualquer caso para responder a perguntas frequentes, basta personalizar a base de conhecimento! Com relação à base de conhecimento, ela também pode ser aprimorada alterando a estrutura de Chave e Valor para matrizes, para que cada par seja uma matriz de possíveis perguntas sobre um tópico e uma série de possíveis respostas para elas (para uma mudança, as respostas podem ser escolhidas aleatoriamente). Naturalmente, a abordagem baseada em regras não é muito flexível para o dimensionamento, mas tenho certeza de que essa abordagem suportará uma base de conhecimento com cerca de 500 perguntas.Quem leu até o fim, convido você a experimentar o meu Bot aqui .