免責說明:本文介紹的 dingdang-robot 與公司的叮當助手沒有任何關系。
這個項目其實來源于我生活中的一個需求:我每天晚上都會去廚房做一個面包當明天的早餐,當我把用料按順序準備好放進面包機時,我需要準确預約到明天早上我吃早餐的時間。然而,幾乎每次在這個時候我都沒有帶手機在身邊,而是都放在客廳裡充電,這時隻能跑去客廳看時間。雖然廚房到客廳隻有幾步之遙,但自己又是懶癌患者,每天都要這麼來回奔波就覺得很不友善。要解決這個問題當然有很多種方法,比如直接買個小時鐘放在廚房。不過我更希望“連看都不用看”,直接有人告訴我時間。是以,我需要一個像 Amazon Echo 那樣的智能音箱。
然而,不論是 Amazon Echo 、Google Home 還是微軟 Cortana 音箱,在國内的使用都是個問題。雖然國内也有類似的智能音箱産品,但我沒有用過這些産品,不知道可定制性如何。比如,如果我需要開發個功能讓它告訴我某種面包的配方是什麼,這些産品就不一定能做到了。考慮再三,我決定自己動手寫一個。整個項目用了差不多三個星期的業餘零碎時間。
先放上項目首頁:http://dingdang.hahack.com
Demo:https://github.com/wzpan/dingdang-robot/wiki/demo
下面分享一下我在開發這個項目過程中的心得。
首先要解決的是硬體問題。我選擇在 Raspberry Pi 上開發。于是我買了塊 Raspberry Pi 三代主機闆。麥克風和音響方面,出于美觀的目的,買了個自帶音響的 USB 全向會議麥克風。整套裝置看起來就像這樣:

過了不久覺得這個麥克風自帶的音響音質太一般了,是以我又外接了一個小音箱。然後再插了一個攝像頭,用來實作拍照功能,又進化成了這樣:
釋出了不到一個星期,respeaker 的商務經理看到了我這個項目,希望能提供硬體上的支援,是以我又玩上了各種 respeaker 的硬體(做為回報,我也零報酬給他們帶去了 100 多個 respeaker-2mics-HAT 的銷量):
因為軟體本身是和硬體解耦的,并不依賴具體的硬體要求,是以很多使用者也自己做了硬體上的定制和嘗試(最後一張圖裡預裝了 dingdang-robot 的是熊,不是妹子 <code>:-p</code>):
硬體有了,接下來就得開始寫軟體了。主要的架構借鑒了 Jasper 項目,并加入了我自己的定制和想法。這裡說說一些有意思的部分。
智能音箱要解決的一個最重要的問題就是如何接收指令。這裡頭主要涉及兩個問題:
被動喚醒(Passive Listening),即“什麼時候開始聽”。這個階段隻監聽喚醒詞。當聽到喚醒詞時,進入主動聆聽。
主動聆聽(Active Listening),即“什麼時候結束聽”。這個階段主動聆聽使用者的任何語音指令,然後對聽到的内容進行分析處理。
被動喚醒階段的基本政策是:每次以 16000 的采樣率錄制 1024 個采樣作為一個采樣集,然後對采樣集進行信号強度估計,當某個采樣集信号強度大于一個門檻值時,就認為可能接受到了指令。然後持續錄制多 1 秒時間,再轉交給語音識别子產品。當語音識别子產品認為是喚醒詞時,進入主動聆聽階段。
主動聆聽的政策與被動喚醒基本相似,每次以 16000 的采樣率錄制 1024 個采樣作為一個采樣集,然後對采樣集進行信号強度估計,當某個采樣集信号強度低于一個門檻值約 1 秒的時間時,就認為使用者已說完了指令。當然還要考慮環境吵雜,一直處于聆聽的可能。是以可以再加一個逾時保護,超過 12 秒就結束聆聽。
說說STT(語音識别,說成ASR也是一回事啦)引擎和TTS(語音轉文本)引擎的選擇。由于被動喚醒會試圖識别所有聽到的内容,出于隐私保護的目的,應該使用離線的語音識别引擎,是以我選擇的是 PocketSphinx 。而對于主動聆聽,由于是在喚醒階段才會進行轉換,進入主動聆聽前會有蜂鳴提示,使用者也會清楚此時叮當正在聽他們說話,相對來說隐私洩露的可能性就比較低,是以我最初選擇的是線上的百度 STT 語音識别服務,也省下了擴充語音識别模型的工夫,有利于更好地實作插件可擴充。TTS 引擎方面同樣也先支援了百度的語音合成。
在實際測試中,PocketSphinx 的識别出乎意料的好。由于我的離線指令集隻有幾個候選喚醒詞,PocketSphinx 對這些喚醒詞的識别非常靈敏,甚至有時候其他聲音也可能被誤當成喚醒詞而喚醒叮當。但即使被意外喚醒了,不去理會叮當就可以了。
相比之下,百度的語音識别就比較遲鈍了。有時候明明我發音很清晰了,還是會識别成另外的含義。通過在百度的語音識别平台上傳自定義的語音識别詞庫 可以提高識别的準确率。另外,由于我用的是 Restful API,網速比較差的時候響應也比較慢。我在家用的是 10M 帶寬的網絡,反應速度還算可以接受。
下面這個視訊是我與叮當對話的示範。我把喚醒詞設定成了“小梅”:
http://www.miaopai.com/show/-yeEBNJlvrQ-UNZzaglxr2s9JQU8TZNy.htm
一個問題是當回答内容比較長(比如問叮當當天的新聞)時,合成語音的耗時會變得很長,給人的感受是叮當的響應很慢。是以我加了個 <code>read_long_content</code> 的選項。當内容過長時,改成發送到使用者的郵箱或者微信。
到了九月份的時候,dingdang-robot 在離線喚醒方面又增加了 snowboy 引擎,在主動聆聽和語音合成方面又增加了阿裡、科大訊飛的服務,無論是識别速度和合成音色的豐富程度又有了很大的進步。
叮當最好玩的部分當然就是玩插件了,通過寫插件可以讓叮當接入各種各樣的服務,完成各種各樣的事情。我在叮當裡也内置了幾個插件。為了友善使用者擴充,我定義了三個技能插件目錄:
<code>$HOME/dingdang/client/plugins</code>:官方插件,與 wzpan/dingdang-robot 同一倉庫;
<code>$HOME/.dingdang/contrib</code>:使用者貢獻的第三方插件,單獨維護一個 dingdang-robot/dingdang-contrib 倉庫;
<code>$HOME/.dingdang/custom</code>:使用者自定義插件,用于存放使用者自己開發的,暫時不計劃對外釋出的插件。
如下是截至本文釋出前 dingdang-robot 提供的插件,可以看出,其他使用者貢獻的插件已經達到了叮當自帶的插件的兩倍:
插件名
用途
是否使用者貢獻
Echo
簡單的回聲/傳話功能。
否
檢查郵件功能。
Time
時間插件。詢問叮當時間。
Camera
用于調起攝像頭拍照(如果安裝了攝像頭的話)。
部分
SendQR
要求叮當發送微信登入二維碼到使用者郵箱(友善遠端微信登入)。
Chatting
用于進入/退出閑聊模式的插件。
Unclear
用于機器人聊天兜底。
Hass
用于控制接入HomeAssistant的裝置
是
NetEaseMusic
網易雲音樂播放插件
Weather
天氣查詢插件
SpeakIP
播報主機IP位址插件
Reboot
重新啟動作業系統(root使用者)
WebServer
啟動HTTP伺服器插件
SendMessage
向微信好友發消息插件
ControMqtt
通過Mqtt協定與其他開發闆通訊
WOL
通過WOL(Wake On Lan)實作語音開機
EmailMyPC
以郵件方式實作語音操控電腦
ToDo
簡單的備忘插件
RaspberryPiStatus
簡單的樹莓派狀态查詢插件
HeadlineNews
新聞頭條播報插件
Direction
出行路線規劃插件
BaiduFM
百度FM音樂播放插件
既然是智能音箱,當然少不了播放音樂的功能。是以我額外寫了個播放網易雲音樂的插件 NetEaseMusic 。出于版權考慮,并不內建進官方插件中,而是放進 dingdang-contrib 裡頭。
這個插件的實作比較複雜。普通的插件接受到指令,響應完就退出了。而為了能支援各種指令控制音樂播放,這個插件在接收到播放控制指令後并不退出插件,而是進入一個播放器模式,這個模式主動聆聽得到的指令隻會在播放控制指令集中比對,其他的插件指令都不起作用。隻有當使用者要求退出播放時才回到普通模式。NetEaseMusic 的播放控制指令如下:
指令
相同指令
播放音樂
-
進入音樂播放模式。在音樂播放模式下,其他的插件功能将不可用。
下一首
切歌, 下一首歌, 下首歌
切換到下一首歌。如果沒有下一首歌,就回到清單中第一首歌
上一首
上一首歌,上首歌
切換到上一首歌。如果沒有上一首歌,就跳到清單中最後一首歌
大聲點
大點聲,大聲
調高播放音量
小聲點
小點聲,小聲
降低播放音量
随機播放
随機播放清單中的音樂
順序播放
順序播放清單中的音樂
暫停播放
暫停音樂的播放
播放
繼續
繼續音樂的播放
榜單
播放推薦榜單
歌單
播放使用者的歌單(如果有多張,将隻播放第一張)
結束播放
退出播放,停止播放
退出音樂播放模式。
搜尋
查找
搜尋歌曲/歌手。将自動播放搜尋結果。
什麼歌
正在播放的是什麼歌
實作這個插件的過程中還參考了 Vellow 的 MusicBox 項目以及 yaphone 的 RasWxNeteaseMusic 。為了友善重用,我把 MusicBox 的核心 API 抽離了出來封成了一個 MusicBoxApi 庫 。比較坑爹的是就在我準備釋出叮當的前幾天,老的擷取音樂位址的方式徹底不能用了,而新的接口批量擷取的位址不知道為什麼是亂序的,于是我隻能在播放每首歌前都調用一下新版的擷取位址的 POST 接口,又增加了一點響應時間。
下面這段音頻是使用叮當控制音樂播放的示範:
http://onmw7y6f4.bkt.clouddn.com/%E6%92%AD%E6%94%BE%E9%9F%B3%E4%B9%90.mp3
完成了音樂播放功能後,叮當的好玩程度提高了很多。以前要聽歌,至少得把電腦或者手機打開。現在隻需要喊一聲叫叮當播放歌曲就可以了。想換歌、搜尋歌曲、調節音量都是說句話就搞定的事情,生活幸福指數大幅提升 <code>^_^</code> 。
dingdang-robot 的正式開源時間是今年的 5 月 20 日(是的,我專門挑了個好日子),截至本文發表時,該項目的相關資料如下:
Github Stars:418,平均一個月 100 star
QQ群使用者:340
pull requests:48
項目首頁 PV:12,000+
捐贈記錄:https://github.com/wzpan/dingdang-robot/wiki/donate-list
雖然資料并不是特别亮眼,不過對于這樣的小衆項目,我已經比較滿意了。下面談談個人怎麼維護一個開源項目吧。
根據二八法則,項目的前期應該要把整個項目期望能達到的 80% 的基本要求完成。一個人的力量畢竟有限,要完成剩餘的 20% 的功能可能要耗費非常多的精力,還不如先推出來,形成社群後再去嘗試完成。
以 dingdang-robot 為例,其實智能音箱最重要的幾個用途:音樂播放、鬧鐘提醒和智能家電控制隻有音樂播放是我在首次釋出的時候提供的(因為不能播放線上音樂的智能音箱實在不好意思叫智能音箱)。剩下的幾個功能都是我提了 feature issues 大緻提供了實作思路,然後由其他的開發者去完成的。
是以,對于一個比較大的項目,更重要的是在這個階段界定好 80% 的目标,設計好項目的架構,确定 License,寫好 README 和 CONTRIBUTION(代碼稽核、持續內建測試等)。
項目釋出之後,推廣和社群搭建是非常重要的,畢竟直接關系到項目的使用者數量和這個項目的生命力。
推廣方面,這個階段我釋出了三篇文章:
叮當:一個開源的中文智能音箱項目:介紹這個項目。
手把手教你編寫叮當機器人插件:介紹如何開發和貢獻技能插件。
使用叮當聲控智米電風扇:介紹如何使用叮當控制家電。
這三篇文章推到了開發者頭條和樹莓派實驗室上,都取得了不錯的點選率。
另外,如果你跟微網誌上一些大 V 關系不錯,也可以嘗試 @ 他們幫忙推廣,當然前提是項目要足夠拿得出手才行。
在這個階段,項目的首頁和文檔也必須盡快搞好,良好的首頁和文檔是吸引使用者付出精力去嘗試你的項目的必要前提。如果像我一樣想省點事,可以直接用 Github Pages 生成簡單的項目首頁,然後直接用 Github Wiki 維護文檔。
社群的搭建也是非常關鍵的一環。可以考慮的管道比如:
即時通訊工具:如果項目主要針對國内使用者,可以使用QQ群;如果針對國際使用者,可以使用 slack 。
論壇。即時通訊工具的最大問題就是存在時效性。類似的問題在群裡剛回答完,新加入的使用者又問了一遍,非常崩潰。是以搭建一個論壇,引導使用者多去使用論壇交流就可以解決這樣的問題。
以 dingdang-robot 為例,QQ群是很多人決定參與項目之前先加入的社群。剛開始群裡才幾個人的時候也是非常冷清尴尬,但後面随着人越來越多,群裡變得非常熱鬧(甚至我不得不選擇上班時間屏蔽該群)。而論壇最初是其中一個使用者用 discuz! 搭建的,但郵箱認證沒搞定,久而久之論壇裡一堆的 spam 。趁着國慶我又用 discourse 重新搭了一個,加了嚴格的稽核政策,正好用騰訊雲的體驗代金券。
一旦使用者數量足夠多,參與貢獻的人就會多了起來。這時候怎麼調動大家參與貢獻的熱情就顯得格為重要了。
為了達到這個目的,項目作者本身首先當然要以身作則,展現出充足碼力。該你承擔的部分積極實作,該 code review 的時候趕緊 review,該釋出新版本的時候保證釋出。然後在社群裡頭多多抛出可能的 idea 和實作方案,這時候往往就會有人願意參與貢獻。
我比較喜歡的形式是在項目的 Github issue 頁裡提出需求,然後過不久就可以看到有人參與貢獻了(比如 #28, #29 和 #39)。對于參與貢獻的使用者,要不吝緻謝,讓他們的名字出現在 changelog 中。
除了這種市集模式的合作方式之外,未來我可能會考慮其他新穎的促進合作的方式,比如線上直播寫插件、釋出新版本,線下 Hackathon 等。
對于有 Coding 能力的 Hacker 而言,自己動手做一個智能音箱,不僅可以當做業餘練手項目,還可以自由地定制硬體子產品,并實作自己需要的各種功能,這遠比直接購買一個 Amazon Echo 有趣得多。
更重要的,我更希望能有其他有興趣的朋友參與進來,一同開發完善這個智能音箱項目。我相信,這種個性化服務的産品本身就應該是完全可定制的。而您的加入可以使 dingdang-robot 變得更智能!