Самообучаемый чат-бот python, который умеет искать ответы в Wikipedia
Давно хотел сделать своего собственного Jarvis. Недавно удалась свободная минутка и я его сделал. Он умеет переписываться с Вами, а также искать ответы на Ваши вопросы в Wikipedia. Для его реализации я использовал язык Python.
Для начала установим все необходимые библиотеки. Их три: pyTelegramBotAPI, scikit-learn, а также Wikipedia. Устанавливаются они просто:
pip install pyTelegramBotAPI
После установки всех библиотек приступаем к разработке. Для начала импортируем все библиотеки, установим язык для Википедии и подключим телеграмм бота
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"\ \n" with open('dialogues.txt', "a", encoding='utf-8') as f: f.write(a) bot.send_message(message.from_user.id, "Готово") update()
В этом куске кода телеграмм бот при получении сообщения от пользователя отвечает на него и если ответ не верный, то пользователь пишет «не так». Если бот получает сообщение «не так», то он берет последний вопрос пользователя и спрашивает «а как?», после чего пользователь должен отправить ему правильный ответ. После этого бот обновляет свою базу данных вопросов и ответов и при следующих вопросах пользователя отвечает на них правильно. И если ответ на вопрос бот должен был взять из Википедии, то пользователь в ответ на вопрос «а как?», должен написать «wiki». Осталось в конце приписать строчку:
И можно запускать и тестировать бота.
Весь код файла с ботом прилагаю ниже:
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"\ \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)
Надеюсь, статья Вам понравилась 🙂