在2019年1期的《科幻世界》中我偶然看到了《鹦鹉之梦与提线木偶》里面的巴德鲁的对话程序我非常感兴趣,文章节选我分为两部分,使用案例和实现方式(引自《鹦鹉之梦与提线木偶》文/【日】藤井太洋 译/田田)
(文中的使用案例)
“谢谢。”飞美从四轮降到沙发高度的托盘上取下咖啡。
“不客气。”巴德鲁演示起飞美为它安装的回礼程序。
“还是要谢谢你。”飞美摸了摸巴德鲁的脑袋。
“谢谢你巴德鲁,你能和飞美说说话吗?”
巴德鲁看了一眼飞美的脸,然后开口道:“飞美总经理,您吃过饭了吗?”
“这又是什么鬼把戏?”飞美问。
“我编了简单的对话程序,试试和它说话吧。你吃过饭了吗?”
(略)…………………………
于是,我决定尝试一条新的思路。
“很遗憾,我已经吃过了。”
飞美话音刚落,巴德鲁就在恰好的时机接话道:“是吗,您吃的什么?”
“对面的那家温迪汉堡。”
“哦,是温迪汉堡呀?好吃吗?”
“一般般吧。”
“哦,一般般呀?有没有什么优点呢?”
“生菜还不错。”
“哦,生菜还不错呀?您喜欢生菜吗?”
“嗯,我爱吃蔬菜。有一次我在旧金山吃汉堡,里面夹的蔬菜鲜美极了。没想到日本也有这么香甜的生菜。”
“您喜欢旧金山吗?”
“喜欢。”
“是吗,您喜欢旧金山的哪一点呢?”
“嗯……”飞美一时答不上来,就冲巴德鲁挥了挥手。美味美公司的巴德鲁会在看到“再见”的手势时停止说话——这个设定是由飞美最初提议,我负责安装的。
只见巴德鲁晃了晃上身,发出“唔”的一声,像是在表示遗憾。“飞美总经理,下次记得和我讲讲旧金山的事。再见!”巴德鲁先是向后退了大约三十厘米,然后领着四轮离开了办公室。
“怎么样?”
“不可思议!”
“随便从公司里抓来一个巴德鲁,只要提起刚才的话,它就会陪你聊有关旧金山的事!如果把相应的照片分享到公共文件夹里,巴德鲁就会对照片提问。要是你把上次去旧金山出差时的照片传上去,它或许会问你喜不喜欢金门大桥。”
(文中描述的实现方式)
“说话的一直都是飞美。巴德鲁只是听了你的话,并对其中的关键词进行了提问而已。”
我掰着手指数道:“怎么样、你喜欢吗、喜欢哪里、有没有什么优点——我为巴德鲁输入了很多这样提问模式,然后让它对听到的关键词进行分类,比如场所、商品、人名等等。最后,再让它根据关键词的分属性选择问题即可。这种设计的关键就在于反应速度,这个飞美也注意到了。从人声的输入到应答的输出需要等待一段时间,而我要做的就是将这段时间尽可能地缩短。”
“你是怎么做到的?”
“听到一个词就往服务器里输入一个词,直到对方停嘴为止。然后再根据关键词的属性进行提问。比如‘你喜欢汉堡吗’。”
“也就是说,它并不需要听我把话说完?”
(略)……………………
“人们往往会在适当的时候搭腔,追问关键词以作确认,接着才开始说自己要说的。但巴德鲁不会有自己想要说的东西,所以一旦对话开始,它就会接连不断地追问下去。”
虽然文中的设定是使用在(2045年的二十年前)2025年发布的python5写的,但是我个人感觉可以使用当前的python3实现部分功能。
使用jieba分词的posseg词性分析来获取一句话中的重点词汇,比如动词,名词等。
然后用选择的重点词汇的词性使用已经设定好的一些句式发问。
import jieba
import random
import logging
import jieba.posseg as psg
#jieba库对的那个载入让人觉得有点烦躁用以下语句丢掉
jieba.setLogLevel(logging.INFO)
#用到的几个列表
##名词列表
global nounwordlist=[]
##形容词列表
global adjwordlist=[]
##动词列表
global verbwordlist=[]
##时间列表
global timewordlist=[]
#保存词和词性
class words:
word=""
flag=""
def __init__(self,w,f):
self.word=w
self.flag=f
#随机抽取一个词
def randomselectfrom(wordlist):
#print(wordlist)
inde=random.randint(0,len(wordlist)-1)
wordselect=wordlist[inde]
del wordlist[inde]
return wordselect
#对一个词进行回复的方式
def reply(words):
if words.flag=='n':
return (nounreply(words.word))
elif words.flag=='a':
return (adjreply(words.word))
elif words.flag=='v':
return (verbreply(words.word))
elif words.flag=='t':
return (timereply(words.word))
else:
return ("嗯,您说。")
#各种词回复
def nounreply(word):
former=["可以聊聊关于「",
"我对「"]
latter=["」的事情吗?",
"」有点兴趣,能说说看吗?"]
sel=len(former)
select=random.randint(0,sel-1)
return (''+former[select]+word+latter[select])
def adjreply(word):
former=["那个有点「",
"有多「"]
latter=["」呀,你觉得有什么优点吗",
"」?"]
sel=len(former)
select=random.randint(0,sel-1)
return (''+former[select]+word+latter[select])
def timereply(word):
former=["「",
"「"]
latter=["」?还发生了什么吗?",
"」啊,有什么别的事一起发生了吗?"]
sel=len(former)
select=random.randint(0,sel-1)
return (''+former[select]+word+latter[select])
def verbreply(word):
former=["为什么「",
"「"]
latter=["」?",
"」的感觉你觉得怎么样?"]
sel=len(former)
select=random.randint(0,sel-1)
return (''+former[select]+word+latter[select])
def main():
buffer=input("说说看关于你的事情。")
while(True):
wordlistflag=list(psg.cut(buffer))
print(wordlistflag)
wordlist=[]
for w,f in wordlistflag:#根据词性进行重新划分
if f in("n",'i'):#普通名词,成语
if (len(w)<1):
wordlist.append(words(w,'n'))
if f in ("nr","nz","ns","nt","nw"):#专用名词,人名地名团体专名
if (len(w)>1):
wordlist.append(words(w,'n'))
nounwordlist.append(words(w,'n'))
if f in ("v","vd","vn"):#动词动名词
if (len(w)>1):
wordlist.append(words(w,'v'))
verbwordlist.append(words(w,'v'))
if f in ("t"):#时间
if (len(w)>1):
wordlist.append(words(w,'t'))
timewordlist.append(words(w,'t'))
if f in ("a","an","ad","d"):#形容词 形容副词
if (len(w)>1):
wordlist.append(words(w,'a'))
timewordlist.append(words(w,'a'))
#print(list(wordlist))
if (len(nounwordlist)>=1):#特殊名词
wordselect=randomselectfrom(nounwordlist)
elif (len(verbwordlist)>=1):#verb
wordselect=randomselectfrom(verbwordlist)
elif (len(timewordlist)>=1):#time
wordselect=randomselectfrom(timewordlist)
elif (len(adjwordlist)>=1):#adj
wordselect=randomselectfrom(adjwordlist)
elif (len(wordlist)<=0):
buffer=input("嗯,您说。")#或许还要一个开始问题的库
continue
else:
wordselect=randomselectfrom(wordlist)
while(True):
buffer=input(reply(wordselect))
if (len(buffer)>0):
break
main()