Самообучаемый чат-бот python, который умеет искать ответы в Wikipedia

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Всем привет!

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

Для начала установим все необходимые библиотеки. Их три: pyTelegramBotAPI, scikit-learn, а также Wikipedia. Устанавливаются они просто:

pip install pyTelegramBotAPI
pip install Wikipedia
pip install scikit-learn

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

import telebot, wikipedia, re
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression

wikipedia.set_lang("ru")
bot = telebot.TeleBot('Ваш ключ, полученный от BotFather')

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

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

alphabet = ' 1234567890-йцукенгшщзхъфывапролджэячсмитьбюёqwertyuiopasdfghjklzxcvbnm?%.,()!:;'

Также Вам необходимо создать в папке, где находится Ваш код файл 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)
	
	X_text = []
	y = []
	
	for question, answer in dataset[:10000]:
		X_text.append(question)
		y += [answer]
	
	global vectorizer
	vectorizer = CountVectorizer()
	X = vectorizer.fit_transform(X_text)
	
	global clf
	clf = LogisticRegression()
	clf.fit(X, y)

update()

Этот кусок кода читает файл dialogues.txt, потом превращает реплики в так называемые вектора, с помощью которых наш бот будет искать наиболее подходящий ответ к заданному нами вопросу. Например, если Вы написали в файле dialogues.txt вопрос "Ты знаешь Аню", а ответ на него "Да, конечно", то бот будет отвечать также и на похожие вопросы, например "Ты знаешь Васю".

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

def get_generative_replica(text):
	text_vector = vectorizer.transform([text]).toarray()[0]
	question = clf.predict([text_vector])[0]
	return question

Этот кусок кода принимает вопрос от пользователя и возвращает ответ от бота.

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

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)
        wikitext2=re.sub('\([^()]*\)', '', wikitext2)
        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 sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression

bot = telebot.TeleBot('Ваш ключ от BotFather')

wikipedia.set_lang("ru")

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

alphabet = ' 1234567890-йцукенгшщзхъфывапролджэячсмитьбюёqwertyuiopasdfghjklzxcvbnm?%.,()!:;'

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)
	
	X_text = []
	y = []
	
	for question, answer in dataset[:10000]:
		X_text.append(question)
		y += [answer]
	
	global vectorizer
	vectorizer = CountVectorizer()
	X = vectorizer.fit_transform(X_text)
	
	global clf
	clf = LogisticRegression()
	clf.fit(X, y)

update()

def get_generative_replica(text):
	text_vector = vectorizer.transform([text]).toarray()[0]
	question = clf.predict([text_vector])[0]
	return question

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)
        wikitext2=re.sub('\([^()]*\)', '', wikitext2)
        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)

Надеюсь, статья Вам понравилась :)

Источник: https://habr.com/ru/post/667008/


Интересные статьи

Интересные статьи

На днях разработчик по имени Брайан Бенчофф (Brian Benchoff) анонсировал начало работы над проектом, который получил название minimum viable computer или MVC. Это миниатюрный ПК на базе Linux с базо...
Компании, которые хотят улучшить качество обслуживания клиентов и расширить свои возможности в современном, мире, все больше полагаются на технологии NLP. Одним из наибол...
Но ученые научились определять, где система дает сбой.В далекое прошлое ушли уютные форумы, где люди-модераторы заставляли участников следовать правилам и цивилизованно о...
На этой неделе — творческое переосмысление геологической (или все же ареологической?) карты Марса на основе карты, сделанной USCS. Использовалась те же геологические данные, что и...
«Материалы, полученные при давлениях в сотни тысяч земных атмосфер» звучит гордо, но вызывает логичные вопросы: «А что будет, если давление снизить? Какой смысл работать со структурами, которые н...