9.4 打造一个聊天机器人
现在,了解了聊天机器人有哪些可能性,你很可能想打造一个最好的、最先进的、Google级别的机器人,对吧?好吧,现在不要想着那些了,因为我们会做相反的事情!我们将建立史上最糟糕的机器人!
让我告诉你为什么。要创建一个与Google所造的机器人相媲美的聊天机器人,需要大量的硬件和时间。在你的MacBook Pro上,无论使用何种真实训练集进行学习,模型通常都要耗费一个月或两个月的时间,你是无法速成它的。这意味着你不得不在Amazon的AWS上租用一些时间,而且也不是随随便便什么机器都能满足需求的。这类机器需要有一些强力的性能规格,最好是GPU。尝试这些当然是好事情。但是,如果你的目标只是建立一些酷炫、吸引人的东西,那么下面的内容就可以帮助到你。
我也应该提前警告你,虽然Cleverbot不是微软的Tay,但对话的口味可能还是会有点重。如果你很容易被冒犯,那你可能需要另一个不同的训练集。
好,让我们开始吧!
首先,和往常一样,我们需要训练数据。一如既往,这是整个过程中最具挑战性的一步。幸运的是,我找到了一个超赞的会话数据库。网站notsocleverbot.com让人们提交他们与Cleverbot之间最荒谬的对话。有了这个训练集,夫复何求?
让我们来看看Cleverbot和该站点用户之间的对话示例,如图9-9所示。
图9-9
所以,我们将从这里开始。首先,我们需要从这个网站下载对话脚本。为此,我们将使用和第2章相同的工具import.io,如图9-10所示。
图9-10
你只需将链接粘贴到页面上的表单中即可。输入的格式就像这样:http://www.notsoc leverbot.com/index.php?page=1。
一旦提交,网站import.io就将处理请求并返回一个页面,就像图9-11这样。
图9-11
如果从这里看一切正常,请单击右上角附近的粉色“Done”按钮。
网站import.io将处理该页面,然后将带你到图9-12这样的界面。
图9-12
接下来,单击中间的Show URL Generator按钮,如图9-13所示。
图9-13
接下来,你可以设置要下载的数字范围。例如,1~20,每次1个。显然,你抓取的页面越多,这个模型就会越好。但是,请记住,你的请求会对服务器造成压力,所以使用时请体贴一些[3]。
完成后,单击Add to List并在文本框中单击Return,然后你应该能够单击Save。它将开始运行,完成之后,你可以将数据下载为CSV文件。
接下来,我们将使用Jupyter记事本来检查和处理数据。首先导入 pandas和Python正则表达式的库re。我们还要设置pandas的选项来加宽列,以便我们可以更好地看清数据。
import pandas as pd import re pd.set_option('display.max_colwidth',200)
现在,我们将加载数据。
df = pd.read_csv('/Users/alexcombs/Downloads/nscb.csv') df
上述代码生成图9-14所示的输出。
图9-14
由于我们只对第一列的对话数据感兴趣,将其拆解出来。
convo = df.iloc[:,0] convo
上述代码生成图9-15所示的输出。
图9-15
从图9-15,我们可以看到用户和Cleverbot之间的交互,以及对话的启动。为了获取我们所需的格式,需要将数据解析成问题和答复的配对。我们不一定关心谁说了什么,但我们关心将每个答复和问题对应起来。稍后我们将理解这是为什么。现在让我们在文本上执行一些正则表达式。
clist = [] def qa_pairs(x): cpairs = re.findall(": (.*?)(?:$|\n)", x) clist.extend(list(zip(cpairs, cpairs[1:]))) convo.map(qa_pairs); convo_frame = pd.Series(dict(clist)).to_frame().reset_index() convo_frame.columns = ['q', 'a']
上述代码将产生图9-16所示的输出。
图9-16
好吧,这里有很多代码。刚刚发生了什么?我们首先创建了一个列表来保存问题和答复的元组。然后我们通过一个函数来切分对话,使用正则表达式将它们变为匹配的对。
最后,我们将列标记为q和a,并将所有的数据放入一个pandas的DataFrame。
我们现在将应用一点算法的魔术,为用户的输入匹配最接近的问题。
from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity vectorizer = TfidfVectorizer(ngram_range=(1,3)) vec = vectorizer.fit_transform(convo_frame['q'])
我们在上面的代码中所做的是,导入TfidfVectorization库和余弦相似度的库。然后我们使用训练数据来创建tf-idf矩阵。现在可以使用这个来转换我们自己的新问题,并测量该问题与训练集中现有问题间的相似度。
我们在第5章详细讨论了余弦相似度和tf-idf算法,所以如果你想了解它们运作的细节,请参考第5章。
让我们现在获取相似度分数。
my_q = vectorizer.transform(['Hi. My name is Alex.']) cs = cosine_similarity(my_q, vec) rs = pd.Series(cs[0]).sort_values(ascending=0) top5 = rs.iloc[0:5] top5
上述代码生成图9-17的输出。
图9-17
我们在这里看什么?这里列出了和我提出的问题最接近的前五个问题,以及它们之间的余弦相似度。左边是索引编号,右边是余弦相似度。让我们来看看这些问题。
convo_frame.iloc[top5.index]['q']
这将产生图9-18所示的输出。
图9-18
我们可以看到,没有一个问题和我的输入是完全相同的,但肯定有一些相似之处。
再来看看答复。
rsi = rs.index[0] rsi convo_frame.iloc[rsi]['a']
上述代码将产生图9-19所示的输出。
图9-19
好吧,我们的机器人似乎已经表明了态度。让我们再进一步。
我们将创建一个方便的函数,这样可以轻松地测试一系列的语句。
def get_response(q): my_q = vectorizer.transform([q]) cs = cosine_similarity(my_q, vec) rs = pd.Series(cs[0]).sort_values(ascending=0) rsi = rs.index[0] return convo_frame.iloc[rsi]['a'] get_response('Yes, I am clearly more clever than you will ever be!')
这将产生图9-20所示的输出。
图9-20
显然,我们创造了一个怪物,所以继续吧。
get_response('You are a stupid machine. Why must I prove anything to you?')
这将产生图9-21所示的输出。
图9-21
我很享受这个。让我们继续前进。
get_response('My spirit animal is a menacing cat. What is yours?')
图9-22
我回答说:
get_response('I mean I didn't actually name it.')
这将产生图9-23的输出。
图9-23
继续:
get_response('Do you have a name suggestion?')
这将产生图9-24所示的输出。
图9-24
我回答:
get_response('I think it might be a bit aggressive for a kitten')
这将产生图9-25所示的输出。
图9-25
我试图平息局面:
get_response('No need to involve the police.')
这将产生图9-26所示的输出。
图9-26
最后:
get_response('And I you, Cleverbot')
这将产生图9-27所示的输出。
图9-27
显然,这可能是我近期最好的对话之一了:包括机器人和真实的人。
现在我们已经创建了这个基于蛋糕[4]的智能,这里要设置一下,以便我们可以通过短信的方式与其聊天。
为了达到这个目的,我们还需要一些东西。第一个是twilio账户。他们将提供一个免费的账户,让我们发送和接收短信,如图9-28所示。
图9-28
跳转到http://www.twilio.com的网页,单击注册一个免费的开发者API密钥。你会设置一些登录凭据,然后他们将向你的手机发送短信以确认你的号码。设置完成后,你就可以在Quickstart文档中找到详细信息。请确保你在左上角的下拉菜单中选择了Python,如图9-29所示。
图9-29
从Python代码发送消息很简单,但是你需要请求一个twilio 的号码。在代码中,你将使用这个号码发送和接收消息。接收消息稍微有点复杂,因为它需要你运行一个Web服务器。文档很简洁,所以设置它不会让你太难熬。你需要一个公共Web能访问的Flask[5]服务器URL地址,并将其粘贴到你管理twilio号码的区域之下方。只需单击号码,它就会带你到粘贴网址的地方,如图9-30所示。
图9-30
一旦这些都设置完成,你只需要确保Flask Web服务器启动并运行。这里,我压缩了所有的代码,可以用于你的Flask应用程序。
from flask import Flask, request, redirect import twilio.twiml import pandas as pd import re from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity app = Flask(__name__) PATH_TO_CSV = 'your/path/here.csv' df = pd.read_csv(PATH_TO_CSV) convo = df.iloc[:,0] clist = [] def qa_pairs(x): cpairs = re.findall(": (.*?)(?:$|\n)", x) clist.extend(list(zip(cpairs, cpairs[1:]))) convo.map(qa_pairs); convo_frame = pd.Series(dict(clist)).to_frame().reset_index() convo_frame.columns = ['q', 'a'] vectorizer = TfidfVectorizer(ngram_range=(1,3)) vec = vectorizer.fit_transform(convo_frame['q']) @app.route("/", methods=['GET', 'POST']) def get_response(): input_str = request.values.get('Body') def get_response(q): my_q = vectorizer.transform([input_str]) cs = cosine_similarity(my_q, vec) rs = pd.Series(cs[0]).sort_values(ascending=0) rsi = rs.index[0] return convo_frame.iloc[rsi]['a'] resp = twilio.twiml.Response() if input_str: resp.message(get_response(input_str)) return str(resp) else: resp.message('Something bad happened here.') return str(resp)
看起来有很多的事情,但实际上我们使用了和之前相同的代码,只是现在我们抓取了twilio发送的POST数据——消息正文——而不是之前手动输入get_request函数的数据。
如果所有都按计划进行,你应该已经拥有了自己的搞怪好友,你可以随时向它发送短消息,还有什么比这更棒的?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论