Python умный чат бот

Чат-бот на Python (Deep Learning + TensorFlow). Часть I

Нашей целью было создание чат-бота, который мог бы в режиме реального времени разговаривать с людьми в Twitch Stream и не выглядеть при этом полным идиотом.

Для того, чтобы создать чат-бота или вообще решить любую задачу машинного обучения, нужно для начала получить сами данные для этого обучения. Затем их нужно структурировать и отформатировать по принципу «вход» и «выход», чтобы алгоритм машинного обучения мог бы их переварить. Возможно именно в этом и состоит наиболее трудоемкая работа при решении практически любых задач машинного обучения. Построение модели, а также этапы обучения и тестирования гораздо проще!

Где взять данные для обучения

Чтобы получить данные для обучения бота, можно исследовать достаточно много разных ресурсов. Например, есть сборник диалогов из фильмов от Корнеллского университета (Cornell movie dialogue corpus) — он пользуется большой популярностью. Есть также и множество других источников, но нам бы хотелось найти что-то более сырое, что ли. Что-то менее изысканное, что-то с характером. Естественно, это сразу нас ведет на Reddit!

Сначала нам казалось, что мы сможем использовать Python Reddit API Wrapper, но ограничения, накладываемые Reddit на сканирование, не самые удобные. Чтобы собрать большие объемы данных, вам придется нарушить некоторые правила. Вместо этого мы нашли дамп данных из 1,7 миллиарда комментариев на Reddit. Что ж, это должно сработать!

Reddit имеет древовидную структуру в отличие от ряда других форумов, где все линейно. Родительские комментарии линейны, но ответы на них разветвляются. На всякий случай, если кто-то с этим незнаком:

-Top level reply 1 --Reply to top level reply 1 --Reply to top level reply 1 ---Reply to reply. -Top level reply 2 --Reply to top level reply 1 -Top level reply 3

Структура, которая нам нужна для глубокого обучения, это вход-выход. Так что нам нужно получить что-то большее, например пары комментарий-ответ. В приведенном выше примере мы могли бы использовать следующие пары комментарий-ответ:

-Top level reply 1 and --Reply to top level reply 1 --Reply to top level reply 1 and ---Reply to reply…

Таким образом, нам нужно взять этот дамп Reddit и создать такие пары. Следующее, что нам нужно учитывать, это то, что у нас, вероятно, должен быть только 1 ответ на комментарий. Несмотря на то, что на многие отдельные комментарии может приходиться много ответов, на самом деле нам стоит остановиться на одном.

Читайте также:  Java any enum parameter

Мы можем просто взять первый комментарий, либо выбрать лучший — набравший наибольшее количество голосов. Подробнее на этом мы остановимся позже. Наша первая задача — получить данные. Если у вас есть проблемы с хранением данных, вы можете взять данные только за один месяц, за январь 2015 года. В противном случае вы можете скачать весь дамп целиком:

magnet:?xt=urn:btih:7690f71ea949b868080401c749e878f98de34d3d&dn=reddit%5Fdata&tr=http%3A%2F%2Ftracker.pushshift.io%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80

Мы качали этот торрент два раза, но в зависимости от количества сидов и пиров время загрузки может сильно варьироваться.

Наконец, вы также можете получить доступ к данным через Google BigQuery: Google BigQuery of all Reddit comments. Таблицы BigQuery со временем обновляются, а торрент — нет, так что это тоже хороший вариант.

Мы будем использовать торрент, так как он абсолютно бесплатен, и если вы хотите в точности следовать инструкциям, он вам понадобится. Но никогда не надо стесняться идти своим путем, поэтому при желании вы всегда можете выбрать и другие варианты.

Поскольку загрузка данных может занять значительное время, мы пока прервемся на этом. А после загрузки данных перейдем к следующей статье. Для работы с нашими статьями вам вполне будет достаточно скачать только один файл 2015-01, все 1.7 миллиардов комментариев загружать совсем не обязательно. Комментариев за один месяц должно хватить.

Источник

Самообучаемый чат-бот 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 вопрос «Ты знаешь Аню», а ответ на него «Да, конечно», то бот будет отвечать также и на похожие вопросы, например «Ты знаешь Васю».

Читайте также:  Как создать alert javascript

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

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)

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

Источник

Оцените статью