Самообучаемый чат-бот python, который умеет искать ответы в Wikipedia
- воскресенье, 22 мая 2022 г. в 00:28:30
Всем привет!
Давно хотел сделать своего собственного 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)
Надеюсь, статья Вам понравилась :)