python开源聊天机器人ChatterBot——聊天机器人搭建、流程分析、源码分析
開源聊天機器人ChatterBot
3.1? ChatterBot簡介
ChatterBot是一個Python庫,可以輕松生成對用戶輸入的自動響應(yīng)。ChatterBot使用一系列機器學習算法來產(chǎn)生不同類型的響應(yīng)。這使開發(fā)人員可以輕松創(chuàng)建聊天機器人并自動與用戶進行對話。
ChatterBot的獨立于語言的設(shè)計使其能夠接受任何語言的培訓。此外,ChatterBot的機器學習特性允許代理實例在與人類和其他信息數(shù)據(jù)源進行交互時提高自己對可能響應(yīng)的知識。對話流程如圖3.1所示。
?
圖3.1? ChatterBot對話流程圖
3.2? 搭建聊天機器人
3.2.1? 第一步:pip下載包
在命令行中輸入命令。
sudo pip install chatterbot輸入密碼后,等待系統(tǒng)安裝。安裝完成后檢測安裝結(jié)果如圖3.2所示。
圖3.2? chatterbot安裝結(jié)果
3.2.2? 第二步:建立python工程、編碼訓練
在PyCharm中建立工程,創(chuàng)建python文件,編碼,執(zhí)行。執(zhí)行結(jié)果如圖3.3所示。
圖3.3? 執(zhí)行結(jié)果
3.2.3? 第三步:輸入對話,得到回答
在控制臺輸入句子,得到對話系統(tǒng)的結(jié)果,如圖3.4、圖3.5所示。
圖3.4? 對話結(jié)果
圖3.5? 對話結(jié)果
3.3? ChatterBot對話流程分析
3.3.1? 創(chuàng)建聊天機器人流程
通過創(chuàng)建ChatBot對象創(chuàng)建聊天機器人,在其構(gòu)造方法中有多個屬性可以進行配置:
1.?? 存儲適配器:為ChatterBot提供連接到各種存儲系統(tǒng)(如MongoDB或本地文件存儲)的接口。
storage_adapter參數(shù)用來配置不同的數(shù)據(jù)庫連接。
database參數(shù)用于指定聊天機器人將使用的數(shù)據(jù)庫的路徑。
2.?? 輸入輸出適配器:
input_adapter參數(shù)配置輸入適配器,用于從命令行、Microsoft Bot、gitter、hipchat、Mailgun讀取用戶的輸入。
output_adapter參數(shù)配置輸出適配器,用于將輸出打印到命令行、Microsoft Bot、gitter、hipchat、Mailgun。
3.?? 邏輯適配器:定義用來響應(yīng)它接收到輸入的ChatterBot
logic_adapters參數(shù)是一個list,可以有多個邏輯適配器,不同的邏輯適配器解決不同的問題。
(1)Time Logic Adapter解決時間相關(guān)的問題;
(2)Mathematical Evaluation Adapter適配器可解決使用基本計算的數(shù)學問題;
(3)Best Match Adapter使用函數(shù)將輸入語句與已知語句進行比較,也就是最匹配方式,從訓練的對話中找到最相似的語句,根據(jù)對話,提供回答;
(4)Low Confidence Response Adapter:如果無法確定具有高置信度的響應(yīng),此適配器會返回指定的默認響應(yīng);
(5)Specific Response Adapter如果聊天機器人接收到的輸入與此適配器指定的輸入文本匹配,則返回指定的響應(yīng)。
4.?? 過濾器:
減少聊天機器人在選擇響應(yīng)時必須處理的語句數(shù)量。
5.?? name:名稱是ChatBot類唯一必需的參數(shù)。
6.?? trainer:訓練器。
3.3.2? 聊天機器人訓練過程
通過調(diào)用train方法,并將訓練集作為參數(shù)。
ChatterBot的訓練過程涉及將示例對話框加載到聊天機器人的數(shù)據(jù)庫中。這可以構(gòu)建代表已知語句和響應(yīng)集的圖數(shù)據(jù)結(jié)構(gòu)。當一個聊天機器人訓練師被提供一個數(shù)據(jù)集時,它會在聊天機器人的知識圖中創(chuàng)建必要的條目,以正確表示語句輸入和響應(yīng)。
用上下句來構(gòu)建一個statement ,statement相當于存儲了一個上下對話的關(guān)系,在查找的時候,先找到最合適的上文,下文就是答案了。這就是一個訓練的過程,訓練的這一過程,主要是在構(gòu)建statement,并把statement放到storage中。
圖3.6? 對話訓練流程
3.3.3? 獲取答案
聊天機器人主要的過程是產(chǎn)生答案的過程,而答案的選擇最關(guān)鍵的就是算法的實現(xiàn),比較好的聊天機器人必須擁有不同的算法,對不同的聊天內(nèi)容給出不一樣的答案,根據(jù)輸入選擇最合適的算法,產(chǎn)生最好的答案。
圖3.7? 獲取答案
3.4? ChatterBot源代分析
分析源代碼需要有入手點,我的入手點就從自己的聊天機器人入手,我將聊天機器人的步驟分為三部分:創(chuàng)建chatterbot、訓練語料、獲取回答。
main.py實現(xiàn)了簡單的對話流程,其代碼如下:
# coding=utf-8from chatterbot import ChatBot# 第一步,創(chuàng)建chatterbotchatbot = ChatBot('Ron Obvious',trainer='chatterbot.trainers.ChatterBotCorpusTrainer')# 第二步,訓練語料chatbot.train("chatterbot.corpus.english")# 第三步,輸入對話得到答案while True:q = raw_input()print chatbot.get_response(q)?
?3.4.1? 創(chuàng)建模塊
創(chuàng)建模塊負責創(chuàng)建對象,其相關(guān)方法如圖3.8所示。
圖3.8?? ChatBot類
1.?? 創(chuàng)建ChatBot對象。
2.?? ChatBot 類的構(gòu)造方法對聊天機器人的相關(guān)屬性進行賦值,包括:聊天機器人的名字、存儲適配器、邏輯適配器、輸入輸出適配器、過濾器、訓練器、訓練的數(shù)據(jù)集、是否要學習用戶輸入等。
3.?? 在賦值相關(guān)適配器的過程中,調(diào)用utils的validate_adapter_class方法對每個適配器進行檢測,檢測其是否為對應(yīng)的父類的子類,也就是檢測我們自己加載的適配器是否為規(guī)定的適配器,如果不是,則會拋出異常。
4.?? 檢測完成后調(diào)用utils的initialize_class對適配器進行加載。
5.?? 加載過程中會調(diào)用utils的import_module,從而找到適配器。
6.?? 找到適配器之后,每個適配器分別調(diào)用各自的set方法,而所有的適配器都繼承自Adapter類。
7.?? 最后還要對邏輯適配器進行一個初始化的處理,調(diào)用initialize方法。
8.?? 接著調(diào)用LogicAdapter類的get_initialization_functions 方法,獲取所有初始化需要執(zhí)行的方法,一一執(zhí)行。
3.4.2? 訓練模塊
訓練模塊開始于語句:chatbot.train()方法,在ChatBot類中,train方法由@property修飾,會根據(jù)不同的訓練器執(zhí)行不同的訓練方法。雖然取名字中都帶有train,其實只是把語料數(shù)據(jù)存入storage而已,不存在機器學習意義上的訓練。在ChatterBot中提供了四種訓練器。所有的訓練器都繼承了Trainer類。其繼承結(jié)構(gòu)如圖3.9所示。
圖3.9? 訓練器繼承結(jié)構(gòu)
3.4.2.1? ListTrainer
使用表示對話的list來訓練聊天機器人。ListTrainer類如圖3.10所示。
圖3.10?? ListTrainer類
1.?? 執(zhí)行train方法,循環(huán)對參數(shù)list進行處理。
2.?? 由于處理需要一定的時間,因此在處理過程中會調(diào)用utils的print_progress_bar方法,顯示處理的進度條。
3.?? 在處理對話的過程中,調(diào)用父類的get_or_create方法,如果statement已經(jīng)存在,則利用已存在的statement,如果不存在,則會創(chuàng)建一個新的statement。
4.?? 為每一個Statement添加tag和response,將結(jié)果存儲到storage中。
3.4.2.2? ChatterBotCorpusTrainer
ChatterBotCorpusTrainer使用來自ChatterBot對話語料庫的數(shù)據(jù)訓練聊天機器人。ChatterBotCorpusTrainer旨在處理yml格式的語料數(shù)據(jù)文件。
圖3.11?? ChatterBotCorpusTrainer
1.?? 在train方法中首先對參數(shù)進行判斷,判斷參數(shù)是否為list。接下來開始對每個語句和其對應(yīng)的回答進行訓練。
2.?? 調(diào)用Cropus類的load_corpus(corpus_path)方法,獲取路徑下所有談話yml中對話內(nèi)容的合集,數(shù)據(jù)集的排序方法按照python的默認方法。
3.?? 調(diào)用Cropus類的list_corpus_files(corpus_path)方法得到y(tǒng)ml文件構(gòu)成的列表 ,該方法會遍歷目錄下的所有文件,如果該文件以yml為后綴,那么該文件path就會存入list。
4.?? 進入循環(huán),開始對每一條對話進行處理,目的是用上下句來構(gòu)建一個statement ,statement相當于存儲了一個上下對話的關(guān)系,在查找的時候,先找到最合適的上文,下文就是答案了。這就是一個訓練的過程,訓練的這一過程,主要是在構(gòu)建statement,并把statement放到storage中。
5.?? 由于處理需要一定的時間,因此在處理過程中會調(diào)用utils的print_progress_bar方法,顯示處理的進度條。
6.?? 在處理對話的過程中,調(diào)用父類的get_or_create方法,如果statement已經(jīng)存在,則利用已存在的statement,如果不存在,則會創(chuàng)建一個新的statement。
7.?? 為每一個Statement添加tag和response,將結(jié)果存儲到storage中。
3.4.2.3? TwitterTrainer
可以訓練來自Twitter的語料。
圖3.12?? TwitterTrainer類
1.?? 執(zhí)行train方法,循環(huán)調(diào)用get_statements方法獲取statement。
2.?? 在get_statements方法中通過調(diào)用twitter提供的API,返回API中隨機statement的列表。
3.?? 最后將statement存儲到storage中。
3.4.2.4? UbuntuCorpusTrainer
使用來自Ubuntu Dialog Corpus的數(shù)據(jù)進行訓練。UbuntuCorpusTrainer是在處理tsv格式的語料數(shù)據(jù)文件。
圖3.13?? UbuntuCorpusTrainer類
1.?? 執(zhí)行train方法,首先會調(diào)用download方法下載語料,然后調(diào)用is_extracted判斷語料是否解壓,如果沒有解壓,那就對語料進行解壓,下載提取ubuntu對話數(shù)據(jù)集,然后檢查python的版本,python2.x的版本可能存在問題。
2.?? 采用循環(huán)對每個語料進行處理,處理每個語料的過程中循環(huán)處理tsv文件的每一行數(shù)據(jù),接下來對循環(huán)處理的每一行代碼進行分析。
for row in reader: #row表示語料tsv文件中的每一行數(shù)據(jù)。 if len(row) > 0: text = row[3] #這個是根據(jù)數(shù)據(jù)集的特性來決定寫代碼的,因為語料庫的第四列是對話內(nèi)容。所以這里是row[3]。statement = self.get_or_create(text) statement.add_extra_data('datetime', row[0]) #這個函數(shù)用來添加字典類型數(shù)據(jù),例如此處添加的數(shù)據(jù)就是 {datetime,row[0]} statement.add_extra_data('speaker', row[1]) if row[2].strip(): #這個代碼的意思是,對話發(fā)起時,是不知道哪個是聽眾的,因為是在論壇發(fā)帖子。因為語料數(shù)據(jù)來自論壇交談,論壇發(fā)帖子是不知道誰會回復的,所以出事狀態(tài)下,發(fā)了一個新帖子以后,在帖子還沒有回復的情況下,row[2]默認是空,只有出現(xiàn)回復者以后,row[2]才會有值。#所以剛發(fā)完帖子后,由于row[2]是空,所以if下面的語句將不會被執(zhí)行。上面的if語句中,Python strip() 方法用于移除字符串頭尾指定的字符(默認為空格)所以上面的if語句的意思是,row[2]這個數(shù)據(jù)集合中的第三個屬性,進行去除空格處理,得到的數(shù)據(jù)是否為空(即判斷這是否是個新發(fā)的帖子) statement.add_extra_data('addressing_speaker', row[2]) #因為人們的交談是一次只能有一個人說話,A說話時,B就只能聽著,可用來增加字典類型數(shù)據(jù),如果用法如上,則函數(shù)調(diào)用前后無變化。 所以row[1]和row[2]表示row[1]對row[2]講話 if previous_statement_text: #這個previous_statement在這里代表上一次某人說的話,因為語料庫來自論壇對話,所以論壇帖子沒發(fā)以前,這個變量肯定是空的。 statement.add_response( Response(previous_statement_text) ) previous_statement_text = statement.text #為下一輪for循環(huán)做準備,方便取得此次回答的下一輪回答。這樣進入下一輪循環(huán)的時候,就可以正常進入if語句。 self.storage.update(statement) #最后將statement存入storage?
3.4.3? 獲取回答模塊
獲取回答模塊主要用于根據(jù)用戶的輸入,產(chǎn)生相應(yīng)的回答。該調(diào)用流程如圖3.14所示。
圖3.14? 回答流程
1.?? 執(zhí)行ChatBot類中的get_response方法,該方法首先檢測默認的會話id,如果該id不存在,則表明是新的會話,這時要給新會話賦予一個新的id。
2.?? 調(diào)用InputAdapter類的process_input_statement方法處理輸入,將輸入轉(zhuǎn)化為statement,該方法會查詢輸入語句對應(yīng)的statement是否存在,如果存在則返回statement,并記錄日志,如果不存在則直接記錄日志。InputAdapter是一個抽象類,所有的輸入適配器必須實現(xiàn)。
3.?? 繼續(xù)在get_response方法中執(zhí)行preprocessor的過濾方法,得到過濾后的statement。
4.?? 調(diào)用ChatBot類中的generate_response方法,該方法根據(jù)輸入的statement得到相應(yīng)的回答。
5.?? 在產(chǎn)生回答的過程中會調(diào)用StorageAdapter類的generate_base_query方法修改storage的屬性。
6.?? 由于邏輯適配器可能有多個,不同的適配器也可能產(chǎn)生不同的結(jié)果,調(diào)用proces方法的過程中會調(diào)用get_greatest_confidence方法找到最佳答案,如果多個適配器都贊同相同的statement,那么這個statement大概率是正確答案。
7.?? 最后通過輸出適配器OutputAdapter,將結(jié)果返回給用戶。
3.4.4? 全局梳理
整個ChatterBot關(guān)鍵部分如圖3.15所示。
圖3.15? 全局關(guān)鍵類
?
總結(jié)
以上是生活随笔為你收集整理的python开源聊天机器人ChatterBot——聊天机器人搭建、流程分析、源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL语句求解同一人物不同日期,某一属性
- 下一篇: Leetcode-136. 只出现一次的