也許很多人會把wechaty和wechat聯(lián)系起來,畢竟名字上只有一個字的區(qū)別。這必須從wechaty的起源開始。起初,該項(xiàng)目只是微信的一個工具庫,可以進(jìn)行一些簡單的自動化操作流程,如定期發(fā)送消息、群發(fā)消息、朋友申請接受等。
但隨著項(xiàng)目的逐步更新,wechaty已經(jīng)支持微信、釘釘?shù)戎髁鱅M軟件Telegram。
自2016年以來,該項(xiàng)目已獲得8kstar。這是一個非常穩(wěn)定和龐大的用戶項(xiàng)目。官方介紹如下:
AConversationalAIRPASDKforChatbot
因此,作為IMChatbot的入口工具,wechaty是許多聊天機(jī)器人的基本結(jié)構(gòu)組件,并將逐步支持主流聊天機(jī)器人的功能。
在2019年底的一次技術(shù)沙龍會議上,我意識到原來的六行代碼可以開發(fā)出一個足夠靈活的機(jī)器人,這給了我很大的震驚。微信作為我們的日常聊天工具之一,如果我們能做一些自動化過程,可以大大減少繁瑣過程的工作量,如:拉人進(jìn)入小組,定期提醒用戶打卡,提醒女朋友阿姨來等等。而且wechaty能很好地支持上述所有功能,只需幾行簡單的代碼即可完成。回去后,立即開始查閱相關(guān)資料,然后逐步進(jìn)入wechaty社區(qū)。
一個巧合的機(jī)會小組說可以開發(fā)一個go-wechaty。當(dāng)時我在想為什么不能有python-wechaty,然后自我推薦,成為python-wechaty的聯(lián)合作者之一。由于對開源軟件和Devops不太熟悉,在起步階段遇到了很多問題,但在社區(qū)老板的耐心指導(dǎo)下,issue和feature的開發(fā)和管理已經(jīng)能夠完成。親身經(jīng)歷,建議你有機(jī)會參加開源項(xiàng)目,讓你學(xué)到很多知識點(diǎn)。
使用python-wechaty可以簡單地開發(fā)Bot,特別是在使用插件系統(tǒng)后,如下所示:
上述代碼實(shí)現(xiàn)了兩個主要功能:當(dāng)Bot接收到#ding信號時,立即回復(fù)dong信息,這是一個基本的ding-dong-bot。當(dāng)接收到查閱天氣的文本語句時,返回相應(yīng)的天氣查詢結(jié)果,如:今天的天氣如何?
以上兩個插件都是系統(tǒng)內(nèi)置的,以后會增加更實(shí)用的即時插件。當(dāng)然,用戶也可以創(chuàng)建自己的插件,方法非常簡單。
在知道如何開發(fā)插件系統(tǒng)之前,可以先移動Plug-in`,插件系統(tǒng)支持插件的安裝、卸載、自定義配置等內(nèi)容。至于具體的實(shí)現(xiàn)形式,我相信我們也需要面對具體的應(yīng)用場景。在面部事件和交互邏輯非常簡單的場景中,插件的設(shè)計和開發(fā)非常簡單。
現(xiàn)在讓我們來看看如何實(shí)現(xiàn)系統(tǒng)內(nèi)置的丁咚插件。
“””basicding-dongbotforthewechatyplugin”””
fromtypingimportUnion
fromwechatyimportMessage,Contact,Room,FileBox
fromwechaty.pluginimportWechatyPlugin
classDingDongPlugin(WechatyPlugin):
“””basicding-dongplugin”””
@property
defname(self):
“””nameoftheplugin”””
return’ding-dong’
asyncdefon_message(self,msg:Message):
“””listenmessageevent”””
from_contact=msg.talker()
text=msg.text()
room=msg.room()
iftext==’#ding’:
conversation:Union[
Room,Contact]=from_contactifroomisNoneelseroom
awaitconversation.ready()
awaitconversation.say(‘dong’)
代碼很簡單,但也需要介紹幾個層次的氛圍。WechatyPluginon_[event_name]init_plugin
這類是抽象類,所有插件都必須繼承這個基類,并重寫函數(shù)。name屬性函數(shù)為抽象函數(shù),必須重寫。主要是為了識別插件的名稱,作為插件的唯一身份認(rèn)證。init_plugin初始化函數(shù)可以支持插件的初始化過程,如初始化定時器對象、數(shù)據(jù)庫延遲連接對象等。on_[event_name]該函數(shù)主要用于監(jiān)控系統(tǒng)中的不同事件,如:on_message,on_login,on_friendship等事件的監(jiān)控只需重寫函數(shù)即可完成。不同的插件和不同的事件是獨(dú)立的,可以很好地關(guān)注不同業(yè)務(wù)場景的發(fā)展。
python-wechaty在很大程度上是由事件驅(qū)動的。畢竟很多操作都是基于新聞接收觸發(fā)的。因此,事件監(jiān)控是其基本特征。也許第一感覺是實(shí)用的eventemiter模式來監(jiān)控事件,這樣我就可以注冊不同的函數(shù)來監(jiān)控每個事件,每個函數(shù)都會有不同的邏輯處理。這也是一種傳統(tǒng)的事件監(jiān)控方法,但至少會給開發(fā)帶來一些不便:函數(shù)參數(shù)需要參考文檔才能知道,標(biāo)準(zhǔn)函數(shù)編程。
我不是說函數(shù)編程不好,但是在這種情況下系統(tǒng)性能提升不了多少,python-wechaty也不能太注重性能。
這擴(kuò)展了OOP的方式,用戶可以繼承Wechaty或WechatyPlugin來監(jiān)控不同的事件,并在傳統(tǒng)的代碼編輯器中重寫函數(shù)時自動填寫函數(shù)參數(shù),從而減少訪問事件函數(shù)參數(shù)的問題。
監(jiān)控事件的類型有:error,friendship,heartbeat,login,logout,message,ready,room_invite,room_join,room_leave,room_topic,scan。
上面已經(jīng)展示了如何開發(fā)WechatyPlugin,需要注意。接下來,我將詳細(xì)介紹如何開發(fā)最基本的日常機(jī)器人。
顧名思義,每天在每個固定時間段發(fā)送祝福或提醒,具體內(nèi)容可以自定義。需要注意的是,機(jī)器人內(nèi)部有一個調(diào)度器,用于觸發(fā)調(diào)度時間事件。機(jī)器人可以將相應(yīng)的內(nèi)容發(fā)送給制定的人和組。
我將上述功能封裝成插件,然后注入python-wechaty。
“””dailywordplugin”””
fromdatetimeimportdatetime
fromapscheduler.schedulers.asyncioimportAsyncIOScheduler
fromwechatyimportWechaty
fromwechaty.pluginimportWechatyPlugin
classDailyPlugin(WechatyPlugin):
saysomethingeveryday,like`DailyWords`
@property
defname(self)->str:
“””getthenameoftheplugin”””
return’dayily’
asyncdeftick(self):
“””timetickforthepluginscheduler”””
room_id=get_room_id()
room=self.bot.Room.load(room_id)
awaitroom.ready()
awaitroom.say(f’iloveyou->{datetime.now()}’)
asyncdefinit_plugin(self,wechaty:Wechaty):
“””initplugin”””
awaitsuper().init_plugin(wechaty)
scheduler=AsyncIOScheduler()
scheduler.add_job(self.tick,’cron’,hour=6,minute=16)
scheduler.start()
插件開發(fā)完畢,然后注入Wechaty就可以跑了。
asyncdefmain():
bot=Wechaty().use(DailyPlugin())
awaitbot.start()
asyncio.run(main())
是不是超級簡單?插件系統(tǒng)幫助您隔離所有業(yè)務(wù)場景,使代碼非常容易開發(fā)和維護(hù)。
現(xiàn)在python-wechaty只完成了基本的chatbot入口工具,離真正的聊天機(jī)器人還有很長的路要走,所以未來還有很多工作要做。也歡迎更多研究chatbot和nlp的朋友聯(lián)系我,共同開發(fā)大家都喜歡使用的開源軟件。