python 使用gensim和pickle包,模拟智能客服系统
程序员文章站
2022-05-19 20:56:42
...
开发环境
mac + python3.6.3
思路讲解
现在一些智能客服系统,号称是机器人客服,其实也就是事先训练好了一些对话模型,从而看起来更精准智能,看着也高大上一些。其实可以分为三个部分:
1. 训练对话模型
2. 服务器加载对话模型,并等待客户端客服接入
3. 客户端接入后,问问题。
训练对话模型
这里模拟淘宝卖家训练一个对话模型:
import jieba
from gensim import corpora, models, similarities
import pickle
q = ["你好,在吗?",
"可以货到付款吗?",
"包邮吗?",
"产品什么材质面料,组成成分?",
"我身高XX ,体重XX 的,应该穿什么尺码?",
"发什么快递?",
"可以发顺丰或邮政吗?",
"我怎么补邮费呢?",
"可以发其他快递吗?",
"你们的产品有色差吗?",
"如果不满意,可以退货吗?",
"退换货邮费谁负责?",
"能不能便宜一点或者送礼品?",
"什么时候发货?",
"几天能到?",
"么么哒"
]
a = ["在的,亲,欢迎您光临“XX官方旗舰店”,我是售前客服小智,请问有什么可以帮助您?",
"亲,不好意思,,本店暂时还没有开货到付款的服务。但是亲不用担心的,现在京东支付方式是非常很多的,而且支付也很方便安全的。现有支付方式:信用卡,网银,快捷支付都是行的。",
"亲,您好,我们全国大部分地区是包邮的,但是部分偏远地区(*、*、青海、甘肃、内蒙等) 是不包邮, 不知亲是哪个地方的?",
"亲,本产品是由30%的亚麻,48%的粘胶 12%的聚酯纤维组成。亚麻面料 夏季清凉,聚酯纤维亲肤透气,韩版修身,穿这款衣服既帅气又舒适。",
"an01",
"我们是默认发汇通和中通的哦。",
"可以的,但是由于顺丰/邮政收费比普通快递要高,您如果要发顺丰/邮政 要补一定的快递费用的。",
"请您稍等一下,我把补邮链接发给你http://item.jd.com/1037266211.html(补邮链接金额为1元,也就是说你这边要补多少元,数量选择多少个就行)。",
"你好,亲这边目前收什么快递方便呢?我帮您看一下我们是否可以发。",
"亲,请您放心,我们是官方正品,没有什么色差的哦,我们有针对200位客户做过售后调查, 根据收到货的客户反映都是可以接受的,不会影响您的穿着,请您放心选购,按照你喜欢的颜色进行选购就可以了。",
"只要不影响我们二次销售的情况下 我们都是支持七天无理由退换货的 所以请你放心购买。",
"亲,如果是产品质量问题我们承担来回邮费。如果不是产品质量问题(如尺码,颜色不合适等因客户个人喜好的问题造成的退换货)运费需要客户自己承担的。",
"亲,不好意思,产品微利已近成本价销售,是不送小礼品/不议价的哦,请您谅解。",
"您好,我们是根据店铺订单量的多少来确定的。正常情况16:00之前付款的,当天都可以发货的。订单量多或者其他特殊情况则是次日发货的。",
"亲,发货后江浙沪1-2天左右到货,其他地区3-5天左右到货的。",
"啪啪啪"]
qcut = []
for i in q:
data1 = ""
this_data = jieba.cut(i)
for item in this_data:
data1 += item + " "
qcut.append(data1)
docs = qcut
# w1_list = []
# for doc in docs:
# for w1 in doc.split():
# print(w1)
# w1_list.append([w1 for w1 in doc.split()])
tall = [[w1 for w1 in doc.split()] for doc in docs]
# corpora.Dictionary()
# 将二维数组转为字典
dictionary = corpora.Dictionary(tall)
# print(dictionary)
# for dic in dictionary:
# print(dictionary[dic])
# gensim的doc2bow实现词袋模型
corpus = [dictionary.doc2bow(text) for text in tall]
# print(corpus)
# corpus是一个返回bow向量的迭代器。下面代码将完成对corpus中出现的每一个特征的IDF值的统计工作
tfidf = models.TfidfModel(corpus)
print(tfidf)
# 通过token2id得到特征数
num = len(dictionary.token2id.keys())
#稀疏矩阵相似度,从而建立索引
index = similarities.SparseMatrixSimilarity(tfidf[corpus], num_features=num)
'''
pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。
pickle模块只能在python中使用,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化,
pickle序列化后的数据,可读性差,人一般无法识别。
pickle.dump(obj, file, protocol)
序列化对象,并将结果数据流写入到文件对象中。参数protocol是序列化模式,默认值为0,表示以文本的形式序列化。protocol的值还可以是1或2,表示以二进制的形式序列化。
pickle.load(file)
反序列化对象。将文件中的数据解析为一个Python对象。
'''
fh = open("dictionary.pk", "wb")
pickle.dump(dictionary, fh)
fh.close()
fh = open("tfidf.pk", "wb")
pickle.dump(tfidf, fh)
fh.close()
fh = open("index.pk", "wb")
pickle.dump(index, fh)
fh.close()
fh = open("a.pk", "wb")
pickle.dump(a, fh)
fh.close()
模型数据序列化后以文件形式保存在本地.
加载对话模型,并等待客服接入
import socket
import jieba
import pickle
# 直接加载训练好的模型
fh = open("dictionary.pk", "rb")
dictionary = pickle.load(fh)
fh.close()
fh = open("index.pk", "rb")
index = pickle.load(fh)
fh.close()
fh = open("tfidf.pk", "rb")
tfidf = pickle.load(fh)
fh.close()
fh = open("a.pk", "rb")
a = pickle.load(fh)
fh.close()
def answer(question, address):
# 加载待计算的问题
data3 = jieba.cut(question)
data31 = ""
for item in data3:
data31 += item + " "
new_doc = data31
new_vec = dictionary.doc2bow(new_doc.split())
sim = index[tfidf[new_vec]]
postion = sim.argsort()[-1]
answer = a[postion]
if (answer == "an01"):
h = "请输入您的身高,单位默认为cm:"
sock.sendto(h.encode("utf-8"), address)
this_data, address2 = sock.recvfrom(2048)
h = this_data.decode("utf-8")
w = "请输入您的体重,单位默认为kg:"
sock.sendto(w.encode("utf-8"),address2)
this_data, address2 = sock.recvfrom(2048)
w = this_data.decode("utf-8")
if(int(h) >= 160 and int(h) <= 170):
if(int(w) < 50):
cm = "S"
elif(int(w) > 65):
cm = "XXL"
else:
cm = "XL"
elif(int(h) >= 170 and int(h) <= 180):
if(int(w) < 65):
cm = "XL"
elif(int(w) > 85):
cm = "XXXL"
else:
cm = "XXL"
else:
cm = "没有符合条件尺码的衣服"
this_result = "根据您的身高与体重,我们给你推荐的衣服尺寸是"+cm+",祝购物愉快!"
sock.sendto(this_result.encode("utf-8"),address2)
return this_result,address,1
return answer,address,0
port = int(input("请输入您想绑定的主机端口:"))
# 绑定
# socket.socket(通信方式,套接字类型)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip = "127.0.0.1"
sock.bind((ip, port))
# 监听连接
# 循环监控连接
while True:
# 接收连接
this_data, address = sock.recvfrom(2048)
key_word = this_data.decode("utf-8")
# 响应信息
rst, address, issend = answer(key_word, address)
if (issend == 0):
sock.sendto(rst.encode("utf-8"), address)
sock.close()
客户端接入,实现交互
import socket
ip = input("请输入您想连接的主机IP:")
port = int(input("请输入您想连接的主机端口:"))
while True:
# 连接
# socket.socket(通信方式,套接字类型)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect((ip, port))
# 发送数据
keywd = input("请输入您要咨询的问题:")
if (keywd == "end"):
break
bstring = keywd.encode("utf-8")
sock.sendall(bstring)
# 接收服务端返回的数据
rst = sock.recv(2048).decode("utf-8")
print("客服回复:" + str(rst))
sock.close()
首先运行训练对话模型文件;然后运行加载对话模型,并等待客服接入;最后运行客户端接入代码。运行效果如下:
上一篇: 登录验证码的实现
下一篇: PHP开发客服系统之WebSocket