2018年3月10日 星期六

[Python] Google Voice Kit 與 Raspberry Pi 3

AIY4

上一次 Pi 1 開機已經想不起來了,大概是 2013 年的事吧,那年在研究 Raspbmc / Airplay 吧,大概是配置的 SDCard 太慢了,再加上已經長期投資 Linode 後,就漸漸把機器擺進防潮箱了,最近則是因為智慧喇吧的興起,想挑一款產品試試,想著想著,就想到去年就曾看到 Google Voice Kit ,而當初買不下去是因為美國才賣 10 美金,但台灣賣超過 30 美金,更別說美國那邊可是 35 美金含 Pi 3 的方案啊 XD

後來想通後,把多出來的價碼當作代購吧 Orz 何必為了一點還可以承擔的錢,延遲或放棄學習的機會?時間可是不等人的!總之,就這樣噴了將近快台幣 3000 吧,一張近似裸裝 Pi 3 (13XX) + Google Voice Kit (900) + microSD (300),各別都還要加上運費和轉帳費。(若單純對智慧音箱有興趣的,建議可以直接買 Google Home mini ,在露天代購不用兩千,甚至接近一千五,跟定價 49.99 美金非常接近)

AIY3

安裝硬件跟紙盒還滿快的,15 分鐘內應當可以搞定,接下來是軟體與線上服務的搭配,開通 GOOGLE ASSISTANT API 及 OAuth 認證後,就可以執行非常簡單的 demo 機制。

寫到這,的確可以穩穩體驗一下,但突然很反骨的想自己試試一些“中文”,需要搞定的項目為:
  • 語音輸入
  • 語音播放
  • 語音辨識
  • 語音合成(Text to Speech)
整個流程就是善用資源,哪邊有 code 要翻出來拼裝,像是語音輸入跟播放就用 Google 寫好的 aiy.audio,而語音辨識則是 SpeechRecognition ,語音合成則是 gTTS。比較特別的是語音播放是用 wav 格式,而 gTTS 的語音合成產出是 mp3 格式,所以再透過 pydub 轉成 wav (底層是 ffmpeg)

其中找資料的過程,主要是從 ~/Desktop/check_audio.desktop 進而研究 AIY-projects-python/checkpoints/check_audio.py 的寫法,找出底層實作的方式(command line!):

AIY-projects-python/src/aiy/audio.py
aiy._drivers._player
aiy._drivers._recorder
aiy._drivers._tts

AIY-projects-python/src/aiy/_drivers/_recorder.py
$ arecord --version
arecord: version 1.1.3 by Jaroslav Kysela <perex@perex.cz>

AIY-projects-python/src/aiy/_drivers/_player.py
$ aplay --version
aplay: version 1.1.3 by Jaroslav Kysela <perex@perex.cz>

AIY-projects-python/src/aiy/_drivers/_tts.py
$ pico2wave --usage
Usage: pico2wave [-?] [-w|--wave=filename.wav] [-l|--lang=lang] [-?|--help] [--usage] <words>


如果有興趣想追 GOOGLE ASSISTANT API 的實作,也可以多看看這些:

~/AIY-projects-python/src/examples/voice/assistant_library_with_button_demo.py
~/AIY-projects-python/src/examples/voice/assistant_library_demo.py
~/AIY-projects-python/src/aiy/assistant/library.py


很快就會追到 google.assistant.library,接著發現無法欣賞他如何實作 https://github.com/googlesamples/assistant-sdk-python/issues/77

最後,嘗試中文的 Speech to text 跟 text to speech ,再順便加一點點天氣回應,有興趣再到這邊看看,最大的關鍵點是用 AIY 的元件(arecord / aplay) 跟其他 gTTS / pydub 亂串時,發現有一些 async 狀態(要播放剛剛製成的音訊資料時,發現資料未完全寫入檔案,最後靠 time.sleep(3) 來解掉):

https://github.com/changyy/GoogleVoiceKitStudy/blob/master/detect-and-echo.py