Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 5
×

Чат-бот Python, який вміє шукати відповіді у Wikipedia

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Всім привіт!

Давно хотів зробити свій власний Jarvis. Нещодавно вдалася вільна хвилинка, і я його зробив. Він вміє переписуватись з Вами, а також шукати відповіді на Ваші запитання у Wikipedia. Для його реалізації я використовував мову Python.

Для початку встановимо всі необхідні бібліотеки. Їх три: pyTelegramBotAPI, fuzzy-wuzzy, і навіть Wikipedia. Встановлюються вони просто:

pip install pyTelegramBotAPI
pip install Wikipedia
pip install fuzzywuzzy

Після встановлення всіх бібліотек приступаємо до розробки. Для початку імпортуємо всі бібліотеки, встановимо мову для Вікіпедії та підключимо телеграм бота:

import telebot, wikipedia, re
from fuzzywuzzy import process
from random import choice
alphabet = "1234567890йцукнегшщзхїєждлорпавіфячсмитьбюґ.,%?():;@"
wikipedia.set_lang("ukr")
bot = telebot.TeleBot('Ваш ключ, отриманий від BotFather')

Тепер напишемо код для очищення всіх непотрібних нам знаків, які вводить користувач:

def clean_str(r):
   r = r.lower()
   r = [c for c in r if c in alphabet]
   return ''.join(r)

Також Вам необхідно створити в папці, де знаходиться Ваш код файл dialogues.txt, в ньому ми створюватимемо репліки на які має відповідати бот. Ось приклад цього файлу:

Привіт\привіт!@хелоу!@як сам?
Як справи?\дуже добре!@гарно

Рядок до знака \ означає питання користувача, а після відповідь нашого бота. Відповіді поділяються знаком @. Він поділяє фрази бота одна від одної, щоб бот міг вибирати рандомні фрази з кількох запропонованих, для імітації більш живої розмови. Після чого напишемо такий код у наш файл з ботом:

def update():
   with open('dialogues.txt', encoding='utf-8') as f:
      content = f.read()
   blocks = content.split('\n')
   dataset = []
   for block in blocks:
      replicas = block.split('\\')[:2]
      if len(replicas) == 2:
         pair = [clean_str(replicas[0]), clean_str(replicas[1])]
         if pair[0] and pair[1]:
            dataset.append(pair)
   global X_text
   global y
   for question, answer in dataset[:10000]:
      X_text.append(question)
      y += [answer]
update()

Цей шматок коду читає файл dialogues.txt, потім перетворює репліки на так звані вектори, за допомогою яких наш бот шукатиме найбільш відповідну відповідь до заданого нами питання. Наприклад, якщо Ви написали у файлі dialogues.txt питання «Ти знаєш Надію?», а відповідь на нього «Так, звичайно», то бот буде відповідати також і на схожі питання, наприклад «Ти знаєш Васю».

Тепер напишемо шматок коду, який генеруватиме відповіді на основі векторів:

def get_generative_replica(text):
   global X_text
   global y
   question = process.extractOne(text, X_text)[0]
   answer = y[X_text.index(question)]
   answer = answer.split('@')
   return choice(answer)

Цей шматок коду приймає запитання від користувача та повертає відповідь від бота, рандомно обравши один з поданих варіантів (якщо вони є), за допомогою бібліотеки random та fuzzywuzzy.

Тепер напишемо функцію для пошуку інформації у Вікіпедії:

def getwiki(s):
   try:
      ny = wikipedia.page(s)
      wikitext=ny.content[:1000]
      wikimas=wikitext.split('.')
      wikimas = wikimas[:-1]
      wikitext2 = ''
      for x in wikimas:
         if not('==' in x):
            if(len((x.strip()))>3):
               wikitext2=wikitext2+x+'.'
            else:
               break
            wikitext2=re.sub('\{[^\{\}]*\}', '', wikitext2)
            return wikitext2
   except Exception as e:
      return 'У вікіпедії немає інформації про це :('

Цей шматок коду отримує питання користувача, потім шукає відповідь на нього у Вікіпедії і якщо відповідь знайдена, то віддає її користувачеві, а якщо відповідь не знайдена, то пише, що «Вікіпедія не має інформації про це».

Тепер пишемо останній шматок коду:

@bot.message_handler(commands=['start'])
def start_message(message):
   bot.send_message(message.chat.id,"Доброго дня!")
question = ""
@bot.message_handler(content_types=['text'])
def get_text_messages(message):
   command = message.text.lower()
   if command =="не так":
      bot.send_message(message.from_user.id, "а як?")
      bot.register_next_step_handler(message, wrong)
   else:
      global question
      question = command
      reply = get_generative_replica(command)
      if reply=="вики ":
         bot.send_message(message.from_user.id, getwiki(command))
      else:
         bot.send_message(message.from_user.id, reply)
def wrong(message):
   a = f"{question}\{message.text.lower()} \n"
   with open('dialogues.txt', "a", encoding='utf-8') as f:
      f.write(a)
   bot.send_message(message.from_user.id, "Готово")
   update()

У цьому шматку коду телеграм бот при отриманні повідомлення від користувача відповідає на нього і якщо відповідь не вірна, то користувач пише «не так». Якщо бот отримує повідомлення «не так», він бере останнє запитання користувача і запитує «а як?», після чого користувач повинен відправити йому правильну відповідь. Після цього бот оновлює свою базу даних питань та відповідей і за наступних питань користувача відповідає на них правильно. І якщо відповідь на запитання бот повинен був взяти з Вікіпедії, то користувач у відповідь на запитання «а як?» повинен написати «wiki». Залишилося наприкінці приписати рядок:

bot.polling(none_stop=True)

І можна запускати та тестувати бота.

Сподіваюся стаття вам сподобалася :). Протестувати цього бота ви можете на моєму сайті. Весь код файлу з ботом прикладаю нижче:

import telebot, wikipedia, re
from fuzzywuzzy import process
from random import choice
alphabet = "1234567890йцукнегшщзхїєждлорпавіфячсмитьбюґ.,%?():;@"
wikipedia.set_lang("ukr")
bot = telebot.TeleBot('Ваш ключ, отриманий від BotFather')
def clean_str(r):
   r = r.lower()
   r = [c for c in r if c in alphabet]
   return ''.join(r)
def update():
   with open('dialogues.txt', encoding='utf-8') as f:
      content = f.read()
   blocks = content.split('\n')
   dataset = []
   for block in blocks:
      replicas = block.split('\\')[:2]
      if len(replicas) == 2:
         pair = [clean_str(replicas[0]), clean_str(replicas[1])]
         if pair[0] and pair[1]:
            dataset.append(pair)
   global X_text
   global y
   for question, answer in dataset[:10000]:
      X_text.append(question)
      y += [answer]
update()
def get_generative_replica(text):
   global X_text
   global y
   question = process.extractOne(text, X_text)[0]
   answer = y[X_text.index(question)]
   answer = answer.split('@')
   return choice(answer)
def getwiki(s):
   try:
      ny = wikipedia.page(s)
      wikitext=ny.content[:1000]
      wikimas=wikitext.split('.')
      wikimas = wikimas[:-1]
      wikitext2 = ''
      for x in wikimas:
         if not('==' in x):
            if(len((x.strip()))>3):
               wikitext2=wikitext2+x+'.'
            else:
               break
      wikitext2=re.sub('\{[^\{\}]*\}', '', wikitext2)
      return wikitext2
   except Exception as e:
      return 'У вікіпедії немає інформації про це :('
@bot.message_handler(commands=['start'])
def start_message(message):
   bot.send_message(message.chat.id,"Доброго дня!")
question = ""
@bot.message_handler(content_types=['text'])
def get_text_messages(message):
   command = message.text.lower()
   if command =="не так":
      bot.send_message(message.from_user.id, "а як?")
      bot.register_next_step_handler(message, wrong)
   else:
      global question
      question = command
      reply = get_generative_replica(command)
      if reply=="вики ":
         bot.send_message(message.from_user.id, getwiki(command))
      else:
         bot.send_message(message.from_user.id, reply)
def wrong(message):
   a = f"{question}\{message.text.lower()} \n"
   with open('dialogues.txt', "a", encoding='utf-8') as f:
      f.write(a)
   bot.send_message(message.from_user.id, "Готово")
   update()
bot.polling(none_stop=True)




			
	
👍ПодобаєтьсяСподобалось8
До обраногоВ обраному2
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Коментар порушує правила спільноти і видалений модераторами.

Можна поцікавитися, чому саме ця бібліотека була використана для телеграм бота?
Цікавить саме чому не pypi.org/...​ject/python-telegram-bot

Мені було все одно, яку бібліотеку використовувати. Я всі пробував. На цій бібліотеці я мав більше проектів, от я її і вибрав.

Він ще зовсім маленький у вас. До того ж іномовний.

Це так) Ніяк не доходять руки перекласти його, та збільшити базу даних.

Ніт. Вам для початку потрібно її максимально зменшити. Зробіть Незнайку, але такого, що пройде тест Тьюрінгу. Щоб він так не знав, як не знає мала дитина. І щоб пізнавав він свій світ так само, як мала дитина пізнає свій.

Спасибі! Якщо буде вільна хвилинка, то спробую.

Підписатись на коментарі