COVID-19 Telegram-bot // نحن نجيب على الأسئلة الشائعة تلقائيًا

في سياق الضجيج العالمي على Coronavirus ، قررت أن أفعل شيئًا مفيدًا على الأقل (ولكن ليس أقل من الضجيج). في هذه المقالة سأتحدث عن كيفية إنشاء ونشر Telegram Bot باستخدام أساليب البرمجة اللغوية العصبية المستندة إلى القواعد في 2.5 ساعة (هذا هو مقدار الوقت الذي استغرقته) للإجابة على أسئلة الأسئلة الشائعة باستخدام حالة COVID-19 كمثال.

في سياق العمل ، سنستخدم Python القديم الجيد ، Telegram API ، واثنين من مكتبات NLP القياسية ، وكذلك Docker.



دقيقة العناية UFO


تم الإعلان رسمياً عن وباء COVID-19 الوبائي ، وهو عدوى تنفسية حادة حادة محتملة ناجمة عن الفيروس التاجي SARS-CoV-2 (2019-nCoV) ، في العالم. هناك الكثير من المعلومات حول حبري حول هذا الموضوع - تذكر دائمًا أنه يمكن أن يكون موثوقًا / مفيدًا ، والعكس صحيح.

نحثك على انتقاد أي معلومات منشورة.



اغسل يديك ، ورعاية أحبائك ، والبقاء في المنزل كلما أمكن ذلك والعمل عن بعد.

قراءة المنشورات حول: فيروسات التاجية | العمل عن بعد

مقدمة موجزة


توضح هذه المقالة عملية إنشاء بوت Telegram بسيط للإجابة على أسئلة الأسئلة الشائعة حول COVID-19. تكنولوجيا التطوير بسيطة للغاية ومتعددة الاستخدامات ، ويمكن استخدامها في أي حالات أخرى. أؤكد مرة أخرى أنني لا أتظاهر بأنني دولة حديثة ، ولكني أقدم فقط حلًا بسيطًا وفعالًا يمكن إعادة استخدامه.

نظرًا لأنني أعتقد أن قارئ هذه المقالة لديه بالفعل بعض الخبرة مع Python ، فإننا نفترض أن لديك بالفعل Python 3.X مثبت وأدوات التطوير الضرورية (PyCharm ، VS Code) ، يمكنك إنشاء بوت في Telegram عبر BotFather ، و لذلك ، سوف أتخطى هذه الأشياء.

1. تكوين API


أول شيء تحتاج إلى تثبيته هو مكتبة الغلاف لـ Telegram API " python-telegram-bot ". الأمر القياسي لهذا هو:

pip install python-telegram-bot --upgrade

بعد ذلك ، سنقوم ببناء إطار برنامجنا الصغير من خلال تحديد "معالجات" لأحداث Bot التالية:

  • بدء - أمر إطلاق بوت ؛
  • مساعدة - أمر مساعدة (مساعدة) ؛
  • رسالة - معالجة الرسائل النصية ؛
  • خطأ - خطأ.

سيبدو توقيع المعالجات كما يلي:

def start(update, context):
    #   
    pass


def help(update, context):
    #  
    pass


def message(update, context):
    #  
    pass


def error(update, context):
    # 
    pass

بعد ذلك ، عن طريق القياس مع المثال من وثائق المكتبة ، نحدد الوظيفة الرئيسية التي نعين فيها كل هذه المعالجات ونبدأ الروبوت:

def get_answer():
    """Start the bot."""
    # Create the Updater and pass it your bot's token.
    # Make sure to set use_context=True to use the new context based callbacks
    # Post version 12 this will no longer be necessary
    updater = Updater("Token", use_context=True)

    # Get the dispatcher to register handlers
    dp = updater.dispatcher

    # on different commands - answer in Telegram
    dp.add_handler(CommandHandler("start", start))
    dp.add_handler(CommandHandler("help", help))

    # on noncommand i.e message - echo the message on Telegram
    dp.add_handler(MessageHandler(Filters.text, message))

    # log all errors
    dp.add_error_handler(error)

    # Start the Bot
    updater.start_polling()

    # Run the bot until you press Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()


if __name__ == "__main__":
    get_answer()

أوجه انتباهكم إلى حقيقة وجود آليتين لكيفية إطلاق الروبوت:

  • الاستطلاع القياسي - الاستقصاء الدوري للبوت باستخدام أدوات Telegram API القياسية للأحداث الجديدة ( updater.start_polling()) ؛
  • Webhook - نبدأ الخادم الخاص بنا بنقطة نهاية ، حيث تصل الأحداث من البوت ، يتطلب HTTPS.

كما لاحظت بالفعل ، من أجل البساطة ، نستخدم الاستقصاء القياسي.

2. نملأ المعالجات القياسية بالمنطق


لنبدأ بأخرى بسيطة ، واملأ البداية وساعد المعالجات بالإجابات القياسية ، نحصل على شيء مثل هذا:

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)

الآن ، عندما يرسل المستخدم أوامر / start أو / help ، سيتلقى الإجابة المحددة من قبلنا. ألفت انتباهكم إلى حقيقة أن النص تم تنسيقه في ماركداون

parse_mode=telegram.ParseMode.MARKDOWN

بعد ذلك ، أضف تسجيل الأخطاء إلى معالج الأخطاء:

def error(update, context):
    """Log Errors caused by Updates."""
    logger.warning('Update "%s" caused error "%s"', update, context.error)

الآن ، دعونا نتحقق مما إذا كان برنامج Bot يعمل. نسخ رمز كله مكتوب في ملف واحد، على سبيل المثال app.py . أضف المستوردات اللازمة .

قم بتشغيل الملف وانتقل إلى Telegram ( لا تنس إدخال الرمز الخاص بك في الرمز ). نكتب الأوامر / البداية و / المساعدة ونفرح:



3. نقوم بمعالجة الرسالة وإنشاء استجابة


أول شيء نحتاجه للإجابة على السؤال هو قاعدة المعارف. إن أبسط شيء يمكنك القيام به هو إنشاء ملف json بسيط على شكل قيم Key-Value ، حيث Key هو نص السؤال المقترح ، و Value هي إجابة السؤال. مثال قاعدة المعرفة:

{
  "      ?": "  —  .     -     ,     ,     ,        .    ,      ,   .        ,     .",
  "   ?": "  :\n     \n    \n    \n     \n\n         ,    .",
  "  ?": " :\n- (    , , )\n- (  )",
  }

ستكون خوارزمية الإجابة على السؤال كما يلي:

  1. نحصل على نص السؤال من المستخدم ؛
  2. Lemmatize جميع الكلمات في نص المستخدم ؛
  3. نحن لا نقارن بوضوح النص الناتج مع جميع الأسئلة المميتة من قاعدة المعرفة ( مسافة Levenshtein ) ؛
  4. نختار السؤال الأكثر "مماثلة" من قاعدة المعرفة ؛
  5. نرسل إجابة السؤال المحدد إلى المستخدم.

لتنفيذ خططنا ، نحتاج إلى مكتبات: fuzzywuzzy ( لمقارنات غامضة) و pymorphy2 (ل lemmatization).

قم بإنشاء ملف جديد وتنفيذ الخوارزمية السليمة:

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

قبل كتابة معالج الرسائل ، سنكتب دالة تحفظ محفوظات المراسلات في ملف 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)

الآن ، نستخدم الطريقة التي كتبناها في رسالة معالج الرسالة النصية:

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)

فويلا ، انتقل الآن إلى Telegram واستمتع بالكتابة:



4. تكوين Docker ونشر التطبيق


كما قال الكلاسيكي: "إذا نفذت ، فسيكون التنفيذ جميلًا." ، حتى يكون لدينا كل شيء كأشخاص ، سنقوم بتكوين حاوية باستخدام Docker Compose.

لهذا نحن بحاجة إلى:

  1. إنشاء Dockerfile - يحدد صورة الحاوية ونقطة الإدخال ؛
  2. إنشاء docker-compose.yml - يُطلق العديد من الحاويات باستخدام ملف Dockerfile واحد (في حالتنا ليس ضروريًا ، ولكن في حالة وجود العديد من الخدمات ، سيكون مفيدًا.)
  3. قم بإنشاء boot.sh (البرنامج النصي مسؤول عن التشغيل مباشرة).

لذا ، فإن محتويات ملف 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"]

محتوى 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

محتويات 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

لذا ، نحن جاهزون لبدء كل هذا تحتاج إلى تنفيذ الأوامر التالية في مجلد المشروع:

sudo docker build -t covid19_rus_bot:latest .
sudo docker-compose up

هذا كل شيء ، بوتنا جاهز.

بدلا من الاستنتاج


كما هو متوقع ، كل الكود متاح في المستودع .

يمكن تطبيق هذا النهج ، الذي أظهرته ، في أي حال للإجابة على أسئلة الأسئلة الشائعة ، ما عليك سوى تخصيص قاعدة المعرفة! فيما يتعلق بقاعدة المعرفة ، يمكن أيضًا تحسينها عن طريق تغيير بنية المفتاح والقيمة إلى صفائف ، لذلك سيكون كل زوج مجموعة من الأسئلة المحتملة حول موضوع واحد ومجموعة من الإجابات المحتملة عليها (لمجموعة متنوعة من الإجابات ، يمكنك الاختيار عشوائيًا). بطبيعة الحال ، فإن النهج القائم على القواعد ليس مرنًا جدًا للتوسع ، ولكني متأكد من أن هذا النهج سوف يتحمل قاعدة معرفية مع حوالي 500 سؤال.

أولئك الذين قرأوا حتى النهاية أدعوكم لتجربة بوتي هنا .

All Articles