python制作聊天机器人原理_用 Python 来做一个聊天机器人吧!(一)
在我的一個(gè)回答里,我提到了用 Python 搭建聊天機(jī)器人。從今天開始,我就帶著大家從0開始搭建一個(gè)聊天機(jī)器人。
(順便說(shuō)一句,我喜歡把鏈接像上面這樣加在文字里,如果找不到文中所說(shuō)的資源,可以看看周圍有沒(méi)有鏈接。)
準(zhǔn)備工作
首先,你要有一臺(tái)安裝了 Python 的電腦,推薦 Python3.6+。另外,系統(tǒng)最好使用 Windows 系統(tǒng),因?yàn)榘褭C(jī)器人和 QQ 對(duì)接的軟件 CoolQ 只有 Windows 版,雖然使用 Docker 和 wine 可以在其它系統(tǒng)上運(yùn)行,但不能保證穩(wěn)定性。
然后,你需要在系統(tǒng)中安裝并運(yùn)行 MongoDB 數(shù)據(jù)庫(kù)服務(wù)。安裝方法可以看這里。記得安裝完成之后運(yùn)行 MongoDB 服務(wù),也就是把 MongoDB 作為服務(wù)安裝到系統(tǒng)中,以保持后臺(tái)運(yùn)行。
其次,你可能會(huì)需要一個(gè)好看的控制臺(tái),最好像 Conemu 一樣既方便又美觀的。畢竟寫累了還可以舔舔老婆(劃去
Chatterbot
Chatterbot 是一個(gè) Python 庫(kù),我們的聊天機(jī)器人就是主要基于這一個(gè)庫(kù)。
安裝和其他的 Python 庫(kù)一樣簡(jiǎn)單:
pip3 install chatterbot chatterbot_corpus
其中 chatterbot_corpus 是 Chatterbot 自帶的語(yǔ)料庫(kù)。
現(xiàn)在簡(jiǎn)單說(shuō)一下 Chatterbot 的原理。Chatterbot 是比較簡(jiǎn)單的聊天機(jī)器人,它需要大量對(duì)話語(yǔ)料來(lái)支撐它的運(yùn)行。當(dāng)用戶給它一個(gè)輸入時(shí),它會(huì)在所有的語(yǔ)料庫(kù)中尋找和這句話最相似的一句話,然后返回語(yǔ)料庫(kù)中的下一句。
所以,在使用 Chatterbot 前,我們需要先進(jìn)行訓(xùn)練。
from chatterbot import ChatBot
from chatterbot.trainers import ChatterBotCorpusTrainer
bot = ChatBot(
'Sakura',
storage_adapter='chatterbot.storage.MongoDatabaseAdapter'
)
trainer = ChatterBotCorpusTrainer(bot)
trainer.train("chatterbot.corpus.chinese")
trainer.train("chatterbot.corpus.english")
我們分析一下這幾行代碼。
bot = ChatBot(
'Sakura',
storage_adapter='chatterbot.storage.MongoDatabaseAdapter'
)
這是創(chuàng)建一個(gè)聊天機(jī)器人,名字叫 Sakura(你也可以改成自己起的名字),使用 MongoDB 中的數(shù)據(jù)。(其實(shí) Chatterbot 還支持 SQL,但是速度太慢了。)
這句代碼里面有一個(gè)單詞 adapter,官方翻譯為“適配器”。其實(shí)它更準(zhǔn)確的含義是“組件”。創(chuàng)建 Chatbot 時(shí)還有很多 xxx_adapter 這樣的參數(shù),可以為機(jī)器人開啟各種各樣的功能。不過(guò)有一點(diǎn)要注意,有些功能可能只對(duì)于英語(yǔ)進(jìn)行了適配,對(duì)其他語(yǔ)言支持并不好。
trainer = ChatterBotCorpusTrainer(bot)
trainer.train("chatterbot.corpus.chinese")
trainer.train("chatterbot.corpus.english")
這幾行就是具體的訓(xùn)練代碼了。注意,這是最新版(2019/8/18)的寫法,之前版本有所不同,使用的是bot.set_trainer(ChatterBotCorpusTrainer)和bot.train,具體寫法可以參看網(wǎng)上其他文章。
chatterbot.corpus.chinese是 Chatterbot 自帶的語(yǔ)料庫(kù)之一。 Chatterbot 的英文語(yǔ)料庫(kù)是非常不錯(cuò)的,只是數(shù)據(jù)量有點(diǎn)少。但是 Chatterbot 的中文語(yǔ)料庫(kù)是由英文語(yǔ)料庫(kù)完全機(jī)器翻譯來(lái)的,而且不太符合中文語(yǔ)境。我自己爬取網(wǎng)絡(luò)言情小說(shuō),提取其中的對(duì)話,整理了一個(gè)語(yǔ)料庫(kù),可以替換 chatterbot 自帶的語(yǔ)料庫(kù)。
上面所說(shuō)的訓(xùn)練代碼單獨(dú)保存再一個(gè)文件里,因?yàn)樵诿看胃膭?dòng)語(yǔ)料庫(kù)之前它只需要運(yùn)行一次。
現(xiàn)在,把訓(xùn)練的代碼運(yùn)行一下,不出意外的話,你會(huì)看到一系列進(jìn)度條,大概這樣:Conemu 支持控制臺(tái)背景圖片,欸嘿嘿~(可以猜一下背景是誰(shuí),雖然猜對(duì)了也沒(méi)有獎(jiǎng))
如果你在上面的[nltk_data]那里卡住了,屬于網(wǎng)絡(luò)環(huán)境的問(wèn)題,我也沒(méi)有辦法,只能放棄 Chatterbot 框架了(之后的系列文章中會(huì)有涉及)。
(2020/2/14補(bǔ)充)注意!如果在 Chatterbot 啟動(dòng)的時(shí)候,出現(xiàn)以[nltk_data]開頭的網(wǎng)絡(luò)錯(cuò)誤,請(qǐng)看下面的補(bǔ)充內(nèi)容! 即使前幾次啟動(dòng)成功,在之后的某一次啟動(dòng)失敗,也是管用的!(2020/2/3補(bǔ)充)破案了!出現(xiàn)這個(gè)問(wèn)題的原因是 chatterbot 把判斷 nltk 數(shù)據(jù)是否存在的代碼寫錯(cuò)了,導(dǎo)致每次啟動(dòng)都需要下載數(shù)據(jù),再加上特殊的網(wǎng)絡(luò)環(huán)境,就會(huì)出現(xiàn)這個(gè)問(wèn)題。解決方法如下:首先手動(dòng)下載 nltk 數(shù)據(jù)(方法自行百度),然后找到 chatterbot 目錄(一般在python目錄/Lib/site-packages/chatterbot)中的 utils.py,將最后面幾個(gè)函數(shù)中的nltk_download_corpus('stopwords'),nltk_download_corpus('averaged_perceptron_tagger'),nltk_download_corpus('vader_lexicon')分別改為 nltk_download_corpus('corpora/stopwords'),nltk_download_corpus('taggers/averaged_perceptron_tagger'),nltk_download_corpus('sentiment/vader_lexicon')。
訓(xùn)練完成之后,機(jī)器人就能支持基本的對(duì)話了。
那么,怎么在自己的代碼里插入這個(gè)機(jī)器人呢?
首先,要?jiǎng)?chuàng)建機(jī)器人實(shí)例,代碼和上面訓(xùn)練時(shí)一樣:
from chatterbot import ChatBot
bot = ChatBot(
'Sakura',
storage_adapter='chatterbot.storage.MongoDatabaseAdapter'
)
bot 對(duì)象有一個(gè)get_response方法,顧名思義,就是獲取一句回答。
現(xiàn)在可以試一下:
print(bot.get_response('你好嗎?'))
在經(jīng)過(guò)短暫的等待之后,就能看到機(jī)器人的回答啦~
print(bot.get_response('你好嗎?'))
# 輸出:你好!
get_response返回的是一個(gè)Statement對(duì)象,它有兩個(gè)常用的屬性text和confindence,分別代表返回的語(yǔ)句的內(nèi)容和可信度(0到1)。
r = bot.get_response('你好嗎?')
print('{},confidence={}'.format(r.text, r.confidence))
# 輸出:你好! ,confidence=1.0
這就是基本操作了。雖然也沒(méi)有進(jìn)階操作就對(duì)了(劃去
然后是一只無(wú)限對(duì)話的小程序:
from chatterbot import ChatBot
bot = ChatBot(
'Sakura',
storage_adapter='chatterbot.storage.MongoDatabaseAdapter'
)
def r(s):return bot.get_response(s).text
while True:
i = input('>>> ').strip()
if i != 'exit':
print(r(i))
else:
break
享受和機(jī)器人沙雕對(duì)話的樂(lè)趣吧!
CoolQ
現(xiàn)在我們已經(jīng)有了能用的機(jī)器人了,但是只有我們一個(gè)人和機(jī)器人對(duì)話沒(méi)有意思,接下來(lái)我們要把它部署到QQ上。
首先你要有一個(gè)QQ小號(hào),當(dāng)然不怕嚇到朋友的同學(xué)也可以用自己的大號(hào)當(dāng)機(jī)器人。
我們使用的軟件是酷Q,一個(gè)專門用于架設(shè)QQ機(jī)器人的軟件??酫 Air 版可以免費(fèi)使用,支持基本的接收發(fā)送文字消息等功能。
運(yùn)行酷Q并登錄之后,我們會(huì)在屏幕上看到一個(gè)懸浮窗:當(dāng)然頭像是你的賬號(hào)的頭像咯
右鍵懸浮窗,選擇「應(yīng)用-應(yīng)用管理」菜單,可以看到一個(gè)這樣的界面:
這里需要解釋一下酷Q運(yùn)行的原理了??酫是依賴于安裝的各種「應(yīng)用」運(yùn)行的,每個(gè)應(yīng)用其實(shí)是一個(gè)動(dòng)態(tài)鏈接庫(kù),酷Q通過(guò)調(diào)用動(dòng)態(tài)鏈接庫(kù)的對(duì)應(yīng)接口,執(zhí)行應(yīng)用的功能。但是問(wèn)題來(lái)了,Python 并不能編譯成動(dòng)態(tài)鏈接庫(kù),該怎么辦呢?
大家注意到我的應(yīng)用列表中最后一個(gè)「HTTP API」了嗎?這就是解決方法。CoolQ HTTP API是一個(gè)將酷Q的接口封裝為HTTP接口或Socket接口的應(yīng)用,理論上,它可以解決一切編程語(yǔ)言連接酷Q的問(wèn)題。
在 CoolQ HTTP API 的 gtihub 倉(cāng)庫(kù)的 release 頁(yè)面可以找到最新版本的下載鏈接,下載完成之后,將 cpk 文件放入酷Q 目錄下的 app 文件夾中。
然后我們需要 Python 端的對(duì)應(yīng)接口。Aiocqhttp 就是 Python 上的 CoolQ HTTP API 接口。同樣,它可以用 pip 安裝:
pip3 install aiocqhttp
在連接 CoolQ HTTP API 時(shí),我推薦使用反向 WebSocket 方式,雖然配置起來(lái)有點(diǎn)麻煩,但是能保證穩(wěn)定運(yùn)行。
首先配置 CoolQ HTTP API。在酷Q目錄\app\io.github.richardchien.coolqhttpapi\config下,找到一個(gè)文件名為QQ號(hào)的 json 文件,按照如下步驟進(jìn)行:增加如下兩行
"ws_reverse_url": "ws://127.0.0.1:7700/ws/",
"use_ws_reverse": true,
(如果端口號(hào)沖突,可以把這里的7700改為其他端口。)找到access_token行,設(shè)置為當(dāng)前賬號(hào)的QQ號(hào),或者其他能唯一標(biāo)識(shí)這個(gè)賬號(hào)的信息。(如果不需要同時(shí)運(yùn)行多個(gè)機(jī)器人, 也可以隨便寫。)
看看這個(gè) json 里有沒(méi)有use_http 和use_ws這兩項(xiàng),如果沒(méi)有,添加這兩項(xiàng),并且把值改為false。這是為了on為了禁用用不到的功能。
如果有ws_reverse_event_url和`ws_reverse_api_url 這兩項(xiàng),把他們刪除。這兩項(xiàng)分別表示 WebSocket 的事件接口和方法接口,其值可以由ws_reverse_url自動(dòng)配置,所以不需要填寫。
新版 CoolQ HTTP API 會(huì)在啟動(dòng)時(shí)彈出它自己的控制臺(tái),如果嫌它太難看,方法是將show_log_console一項(xiàng)改為false。
如果在 Python 端需要執(zhí)行初始化代碼,請(qǐng)將 CoolQ HTTP API 升級(jí)到最新版本(v4.14及以上),然后在配置文件中加入這樣一行:"ws_reverse_use_universal_client": true。
每次修改配置文件之后,都需要重啟酷Q。
接下來(lái)就可以擼 Python 端的代碼了。
先上一個(gè)模板代碼:
from aiocqhttp import CQHttp
bot = CQHttp(access_token='你剛才設(shè)置的 access_token', enable_http_post=False)
@bot.on_message('private')
async def handle_msg(context):
await bot.send(context, '現(xiàn)在為您復(fù)讀:')
return {'reply': context['message']}
if __name__ == '__main__':
bot.run(host = '127.0.0.1', port = 7700)
不要忘了把a(bǔ)ccess_token改成剛才設(shè)置的內(nèi)容。
現(xiàn)在我們分析一下這段代碼:
bot = CQHttp(access_token='你剛才設(shè)置的 access_token', enable_http_post=False)
創(chuàng)建一個(gè)機(jī)器人實(shí)例,因?yàn)樵O(shè)置了enable_http_post=False,所以啟用的是反向 WebSocket 模式,這個(gè)模式下,只需要傳入 access_token 即可。
if __name__ == '__main__':
bot.run(host = '127.0.0.1', port = 7700)
在本地的 7700 端口開啟反向 WebSocket 服務(wù)。如果機(jī)器人的主程序有公網(wǎng)IP,那么還可以實(shí)現(xiàn)把任意一個(gè)酷Q連接到機(jī)器人(雖然我買不起公網(wǎng)IP,也沒(méi)試過(guò))。
@bot.on_message('private')
async def handle_msg(context):
await bot.send(context, '現(xiàn)在為您復(fù)讀:')
return {'reply': context['message']}
這就是機(jī)器人的邏輯代碼了。Aiocqhttp 把酷Q的各種事件封裝為裝飾器,最常用的就是@bot.on_message(),這個(gè)裝飾器可以帶一個(gè)字符串參數(shù), private、group和discuss分別代表私聊消息、群消息、討論組消息;也可以不帶參數(shù) ,表示處理全部消息。除此之外,還有on_notice、on_request、on_meta_event裝飾器分別對(duì)應(yīng)其他三種事件。這三種裝飾器也可以帶參數(shù),參數(shù)內(nèi)容為要處理的事件類型(notice_type、request_type或meta_event_type,具體取值見事件列表)。
處理消息的內(nèi)容寫在函數(shù)里。由于消息的收發(fā)是異步的,所以要使用async def xxx(context):的語(yǔ)法。函數(shù)名可以任意取,也可以創(chuàng)建多個(gè)不同函數(shù)名的函數(shù)來(lái)處理同一個(gè)消息(但是我并不確定按什么順序執(zhí)行)。
函數(shù)參數(shù)只有一個(gè):context,類型為字典,代表 CoolQ HTTP API 傳來(lái)的事件參數(shù)。具體內(nèi)容的格式參看這里,比如對(duì)于接收消息的事件,context['message']就代表了消息內(nèi)容。
在函數(shù)里,可以通過(guò)await bot.xxx(...)的語(yǔ)法來(lái)調(diào)用 CoolQ HTTP API 提供的 API,在API列表中的API全部可以直接通過(guò)bot.API名字()調(diào)用,API參數(shù)通過(guò)命名參數(shù)提供,也就是類似于bot.send_private_msg(user_id=123456, message='hello')的形式。另外,Aiocqhttp 提供了一個(gè)發(fā)送消息的簡(jiǎn)單操作,調(diào)用形式為await bot.send(context, '消息內(nèi)容')。
處理事件的函數(shù)可以有一個(gè)返回值,也是一個(gè)字典,代表事件的響應(yīng)數(shù)據(jù),就是事件列表中每 個(gè)事件下面的響應(yīng)數(shù)據(jù)列表,用于快速處理事件。最簡(jiǎn)單地,return {'reply':'消息內(nèi)容'}就會(huì)回復(fù)發(fā)來(lái)消息的人。在群聊中,如果不指定'at_sender':false,還會(huì)自動(dòng)@發(fā)消息的人。當(dāng)然,也可以沒(méi)有返回值。
上面的這一段代碼,就是一個(gè)復(fù)讀機(jī)機(jī)器人,會(huì)自動(dòng)復(fù)讀所有的私聊消息。
所以,人類的本質(zhì)是——人類的本質(zhì)是——
CoolQ x Chatterbot
現(xiàn)在,終于可以為我們的機(jī)器人注入靈魂了。把 Chatterbot 嵌入 CoolQ 機(jī)器人實(shí)際上并不是一件難事。
廢話不多說(shuō),直接上代碼:
from aiocqhttp import CQHttp
from chatterbot import ChatBot
bot = CQHttp(access_token='你剛才設(shè)置的 access_token', enable_http_post=False)
chatterbot = ChatBot(
'Sakura',
storage_adapter='chatterbot.storage.MongoDatabaseAdapter'
)
def r(s):
return chatterbot.get_response(s)
@bot.on_message('private')
async def handle_msg(context):
rep = r(context['message'].strip())
if rep.confidence > 0.65:
return {'reply':rep.text}
if __name__ == '__main__':
bot.run(host = '127.0.0.1', port = 7700)
邏輯很簡(jiǎn)單,判斷回答的可信度是否大于0.65,如果是,作出回答。
當(dāng)然,可以在這段代碼的基礎(chǔ)上,進(jìn)一步拓展,實(shí)現(xiàn)更加復(fù)雜的處理邏輯。
在下一篇文章里,我會(huì)介紹我在編寫自己的機(jī)器人時(shí)用到的一些處理邏輯和小技巧。(雖然也不知道下一篇文章會(huì)鴿幾個(gè)月)
下一篇文章:忘憂北萱草:用 Python 來(lái)做一個(gè)聊天機(jī)器人吧!(二)?zhuanlan.zhihu.com
(封面PID:72774437)
現(xiàn)已加入知乎專欄:用 Python 來(lái)做一個(gè)聊天機(jī)器人吧!?zhuanlan.zhihu.com
總結(jié)
以上是生活随笔為你收集整理的python制作聊天机器人原理_用 Python 来做一个聊天机器人吧!(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python3之字典生成器结合lambd
- 下一篇: python公式计算器_Python-计