一口氣將 Voice Kit 連上 Google Cloud Platform — 實作篇

TIH
TIH
May 31, 2019 · 29 min read

上一篇文中,我們已經組裝好了屬於自己的 Voice Kit,不過,如果要讓 Voice Kit 成為一個稱職的隨身助手,我們還有一些設定要做。如果你剛好對這部分有些疑問,那這篇文章應該可以解決你的問題喔~

在這篇文章中,我們要進行的有:

1. 讓你的 Voice Kit 2.0 ,變成可以進行簡單(只回一句話)對話的聊天機器人 (Chatbot)。

2. 讓你的 Voice Kit 2.0 可以辨識中文。

在按照這篇文章步驟完成設定後,我們應該可以學到:

  1. 基本的vim操作
  2. 基本的python缺套件安裝
  3. 基本的python語法修改
  4. 使用gTTS套件得到文字轉音訊檔
  5. 讓Voice Kit 辨識中文
  6. 如何開設GCP帳號

如果對整個智慧音箱的理論架構有興趣的話,可以參考另一篇的『理論篇』,裡面會有更詳細的說明~

首先我們需要準備:

1. 已經組裝好,可以正常啟動的 Voice Kit 2.0

2. 能進行網路刷卡的信用卡或 Visa 金融卡

3. 電腦 (Mac、Windows、Linux皆可)

確定都有的話,就讓我們開始吧!

1. 開啟 Google Cloud Platform 帳號

1.1 首先先點入此連結,進入 Google Cloud Platform的頁面。

1.2 選擇同意服務條款,居住地區確認依所在地選擇,這裡就先選台灣吧

*是否接收電子郵件訊息的部分可自由選擇。

1.3 點選同意並繼續,就會進入主畫面了

1.4 進入主畫面後,點選左上目錄,接著點選帳單

1.5 選擇新增帳單帳戶

1.6 點選同意後繼續

1.7 填入相關資訊、依照需求選擇付款方式

*稅務資料可以填寫個人

1.8 資料確認無誤後,點選同意免費試用

1.9 點選我知道了

到這裡,我們就完成 Google Cloud Platform 帳戶的申請了,同時,Google 也會自動開啟一個被命名為『 My First Project 』的專案。

2. 申請服務憑證(Service Credentials)

2.1 點選左上目錄,選擇 API 和服務中的『憑證』項目

2.2 點選建立憑證,選擇『服務帳戶金鑰』項目

2.3 服務帳戶的部分,請選擇『新增服務帳戶』

2.4 帳戶名稱可以輸入自己喜歡、好識別的名稱,這篇文章中,我們將帳戶命名為:『 Voice Kit 專用』

2.5 角色身分是 Project (專案)的『檢視者』

2.6 金鑰類型請選擇 JSON

2.7 點選建立

2.8 下載、儲存金鑰檔案

*金鑰就像是你在 Google Cloud 的記名會員卡,請務必妥善存放金鑰檔案。如果金鑰被盜用,相關消費都會記在這個帳戶上面喔

*如果完成後要把程式碼分享給朋友,也請記得再三檢查有沒有不小心把這個檔案公開到網路上

3. 請參考上一篇文章的第三點,以 ssh pi@{Voice Kit 的 IP} 登入 Voice Kit

3.1 執行 ~/AIY-projects-python/checkpoints/check_cloud.py ,這個 Script可以幫忙檢查憑證設定有沒有錯誤,如果正確,會顯示如下:

pi@raspberrypi:~ $ ~/AIY-projects-python/checkpoints/check_cloud.py
Please follow the Custom Voice User Interface instructions on the AIY website
to download credentials:
https://aiyprojects.withgoogle.com/voice-v1/#makers-guide-3-custom-voice-user-interface
and save them to /home/pi/cloud_speech.json
Press Enter to close...

3.2 請按下鍵盤上的 Enter關掉程式

3.3 以任意文字編輯器把上一步的 My First Project-xxxxxxxx.json (金鑰檔案)打開

3.4 打開後應該能看見類似以下開頭的文字

{
"type": "service_account",

3.5 把文字全部複製下來

3.6 回到 Voice Kit ,輸入 vim /home/pi/cloud_speech.json 打開檔案

3.7 按下 i進入編輯模式,此時畫面左下角應該會看到 -- INSERT --

3.8 把複製的內容貼上,接著按下 ESC 離開編輯模式

3.9 輸入 :wq 存檔

3.10 再次執行 ~/AIY-projects-python/checkpoints/check_cloud.py ,之後可能會看到有出現錯誤訊息的以下字串:

pi@raspberrypi:~ $ ~/AIY-projects-python/checkpoints/check_cloud.py
Testing the Google Cloud Speech API...
Traceback (most recent call last):
File "/opt/aiy/projects-python/src/aiy/_apis/_speech.py", line 274, in do_request
return self._handle_response_stream(response_stream)
File "/opt/aiy/projects-python/src/aiy/_apis/_speech.py", line 223, in _handle_response_stream
for resp in response_stream:
File "/usr/local/lib/python3.5/dist-packages/grpc/_channel.py", line 347, in __next__
return self._next()
File "/usr/local/lib/python3.5/dist-packages/grpc/_channel.py", line 341, in _next
raise self
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with (StatusCode.PERMISSION_DENIED, Cloud Speech-to-Text API has not been used in project 418950185212 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/speech.googleapis.com/overview?project=418950185212 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.)>
The above exception was the direct cause of the following exception:Traceback (most recent call last):
File "/home/pi/AIY-projects-python/checkpoints/check_cloud.py", line 104, in <module>
main()
File "/home/pi/AIY-projects-python/checkpoints/check_cloud.py", line 95, in main
if not check_speech_reco():
File "/home/pi/AIY-projects-python/checkpoints/check_cloud.py", line 68, in check_speech_reco
output = req.do_request()
File "/opt/aiy/projects-python/src/aiy/_apis/_speech.py", line 279, in do_request
raise Error('Exception in speech request') from exc
aiy._apis._speech.Error: Exception in speech request
Press Enter to close...

*看起來會像圖片中的樣子:

不用太緊張,請仔細閱讀一下,中間有出現來自 Google的溫馨提示:

Cloud Speech-to-Text API has not been used in project 418950185212 before or it is disabled.

這代表這個帳戶還沒開啟 Speech-to-Text API 的權限,等下個步驟開啟後就會消失了

4. 啟用 Speech-to-Text API

4.1 回到 GCP(Google Cloud Platform) Console,點左上目錄,點選『API 和服務』選擇 『資訊主頁』項目。

4.2 點選啟用 「+啟用API和服務」

4.3 在『搜尋 API 和服務』中輸入 Speech

4.4 點擊 Cloud Speech-to-Text API

4.5 點擊啟用

4.6 回到 Voice Kit,再次輸入 ~/AIY-projects-python/checkpoints/check_cloud.py 後,就會看到以下的成功訊息了

pi@raspberrypi:~ $ ~/AIY-projects-python/checkpoints/check_cloud.py
Testing the Google Cloud Speech API...
Everything's set up to use the Google Cloud.
Press Enter to close...

*假如輸入內容和先前相同的話,可以按鍵盤的向上鍵,就能重覆輸入同樣內容喔~

5. 進行第一次語音辨識

5.1 接下來執行 ~/AIY-projects-python/src/examples/voice/cloudspeech_demo.py ,執行後會看到以下訊息:

pi@raspberrypi:~ $ ~/AIY-projects-python/src/examples/voice/cloudspeech_demo.py
Press the button and speak

5.2 按下 Voice Kit 上的按鈕,看到畫面出現 Listening...的時候和他說 turn on the light

5.3 運作順利可以像下圖一樣,看到 Voice Kit 發光

*語音部分可以多試幾次看看反應,如果擔心英文發音不夠標準,可以用 Google 翻譯讓 Google 小姐幫忙說~

如果都請Google小姐說了 turn off light 都還沒看到 Voice Kit 發光,是因為原先的 LED 程式碼是比較舊的版本,需要更新,這時就會進入步驟5.4。

5. 4更新程式

5.4.1 用 cd ~/AIY-projects-python 的命令,把工作目錄 (work directory)切換到程式碼在的資料夾

5.4.2 接著用 git log 做確認,從 Date (加粗的文字)可以看到,程式是 2018年 8月的版本

commit 93a6306438492464c25916b6b2f53d8e4750579b
Author: Dmitry Kovalev <dkovalev@google.com>
Date: Fri Aug 3 16:20:52 2018 -0700
Update debian changelog and bump package version.Change-Id: I80bb5a73e2f9b7c12c6b51152fa7d4c1bc0b3145

5.4.3 輸入 git pull ,從 GitHub 上面拉最新的版本

*這篇文章發布時,最新的版本是應該是 2018年 12月,如加粗文字所示:

pi@raspberrypi:~/AIY-projects-python $ git log
commit 56d40c7c1c5125fcfe2e69ec2b6f27a15fe35ad9
Author: Dmitry Kovalev <dkovalev@google.com>
Date: Thu Dec 20 13:58:35 2018 -0800
Add doc generation shortcut to Makefile.Change-Id: Id51fbe9ceeeab6f055911b2f99645d54510cf03c

5.4.4 輸入 git checkout 56d40c7c1c5125fcfe2e69ec2b6f27a15fe35ad9 這個指令來切換到目前的版本 (有種時間跳躍的感覺)

5.4.5 再執行一次 ~/AIY-projects-python/src/examples/voice/cloudspeech_demo.py此時會看到以下錯誤訊息:

*此時出現錯誤是正常的,因為 AIY 的程式碼還沒更新,所以我們需要手動更新一下程式碼

INFO:root:Initializing for language en_GB...
INFO:root:Say something, e.g. turn on the light, turn off the light, blink the light, goodbye.
DEBUG:google.auth.transport.requests:Making request: POST https://oauth2.googleapis.com/token
DEBUG:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): oauth2.googleapis.com
DEBUG:requests.packages.urllib3.connectionpool:https://oauth2.googleapis.com:443 "POST /token HTTP/1.1" 400 None
ERROR:root:AuthMetadataPluginCallback "<google.auth.transport.grpc.AuthMetadataPlugin object at 0xb54815d0>" raised exception!
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/grpc/_plugin_wrapping.py", line 77, in __call__
callback_state, callback))
File "/usr/local/lib/python3.5/dist-packages/google/auth/transport/grpc.py", line 73, in __call__
callback(self._get_authorization_headers(context), None)
File "/usr/local/lib/python3.5/dist-packages/google/auth/transport/grpc.py", line 61, in _get_authorization_headers
headers)
File "/usr/local/lib/python3.5/dist-packages/google/auth/credentials.py", line 121, in before_request
self.refresh(request)
File "/usr/local/lib/python3.5/dist-packages/google/oauth2/service_account.py", line 310, in refresh
request, self._token_uri, assertion)
File "/usr/local/lib/python3.5/dist-packages/google/oauth2/_client.py", line 143, in jwt_grant
response_data = _token_endpoint_request(request, token_uri, body)
File "/usr/local/lib/python3.5/dist-packages/google/oauth2/_client.py", line 109, in _token_endpoint_request
_handle_error_response(response_body)
File "/usr/local/lib/python3.5/dist-packages/google/oauth2/_client.py", line 59, in _handle_error_response
error_details, response_body)
google.auth.exceptions.RefreshError: ('invalid_scope: Bad Request', '{\n "error": "invalid_scope",\n "error_description": "Bad Request"\n}')

5.4.6 輸入 vim src/aiy/cloudspeech.py ,開啟有問題的程式碼,此時會看到以下訊息:

@@ -38,6 +38,9 @@ AUDIO_SAMPLE_RATE_HZ = 16000
AUDIO_FORMAT=AudioFormat(sample_rate_hz=AUDIO_SAMPLE_RATE_HZ,
num_channels=1,
bytes_per_sample=2)
+_CLOUD_SPEECH_OAUTH_SCOPE = (
+ 'https://www.googleapis.com/auth/cloud-platform'
+)
logger = logging.getLogger(__name__)@@ -47,7 +50,7 @@ class CloudSpeechClient:
if service_accout_file is None:
service_accout_file = os.path.expanduser('~/cloud_speech.json')
- credentials = service_account.Credentials.from_service_account_file(service_accout_file)
+ credentials = service_account.Credentials.from_service_account_file(service_accout_file, scopes=[_CLOUD_SPEECH_OAUTH_SCOPE])
self._client = speech.SpeechClient(credentials=credentials)
def _make_config(self, language_code, hint_phrases):

5.4.7 打開此連結,找到第 38 行,可看見以下訊息:

AUDIO_FORMAT=AudioFormat(sample_rate_hz=AUDIO_SAMPLE_RATE_HZ,
num_channels=1,
bytes_per_sample=2)

5.4.8 用 i 進入插入模式,在後面加上以下訊息 ,完成後按 ESC 恢復

_CLOUD_SPEECH_OAUTH_SCOPE = (
'https://www.googleapis.com/auth/cloud-platform'
)

5.4.9 然後找到第 47 行,用 i 進入插入模式,把

credentials = service_account.Credentials.from_service_account_file(service_accout_file)

修改成

credentials = service_account.Credentials.from_service_account_file(service_accout_file, scopes=[_CLOUD_SPEECH_OAUTH_SCOPE])

完成後按 ESC 恢復

*修改完成後,應該會如圖呈現:

5.4.10 用 :wq 存檔離開

5.4.11 再輸入一次 ~/AIY-projects-python/src/examples/voice/cloudspeech_demo.py,這時應該就能看到以下訊息:

pi@raspberrypi:~/AIY-projects-python $ ~/AIY-projects-python/src/examples/voice/cloudspeech_demo.py
INFO:root:Initializing for language en_GB...
INFO:root:Say something, e.g. turn on the light, turn off the light, blink the light, goodbye.
DEBUG:google.auth.transport.requests:Making request: POST https://oauth2.googleapis.com/token
DEBUG:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): oauth2.googleapis.com
DEBUG:requests.packages.urllib3.connectionpool:https://oauth2.googleapis.com:443 "POST /token HTTP/1.1" 200 None
INFO:aiy.cloudspeech:Start listening.
INFO:aiy.cloudspeech:Stop listening.
INFO:root:You said nothing.
INFO:root:Say something, e.g. turn on the light, turn off the light, blink the light, goodbye.
INFO:aiy.cloudspeech:Start listening.

*這個版本的程式碼不需要按按鈕就會自動偵測麥克風,所以直接用 turn on the lightturn off the light 做測試吧

6. 讓 Voice Kit 發出聲音

6.1 先把工作目錄切換到 example下

pi@raspberrypi:~ $ cd ~/AIY-projects-python/src/examples/voice/
pi@raspberrypi:~/AIY-projects-python/src/examples/voice $

:$ 中間的東西就被我們稱做是工作目錄(work directory) 這時候我們執行程式就可以少掉一串路徑

6.2 在這個狀況下,輸入 ./cloudspeech_demo.py 應該可以順利執行上一步驟的程式

接下來,我們要在開燈的時候讓他和我們說 “Light is turned on.” 、關燈的時候說 “Light is turned off.”

我們要使用gtts這個 python套件來將文字轉成語音(gtts是什麼意思請參考理論篇)

6.3 先用 vim 打開程式 vim ./cloudspeech_demo.py

6.4 移動到form aiy.cloudspeech import CloudSpeechClient

這行下面,點 i 進入插入模式,接著新增新的一行,輸入form gtts import gTTS ,如下圖:

6.5 按下 ESC離開插入模式,輸入 :wq 存檔並關掉檔案

6.6 執行 ./cloudspeech_demo.py ,但可能會看到下圖的錯誤訊息

6.7 這時用 pip把套件裝下來就行了,輸入 pip3 install gtts

6.8 當看到以下訊息時代表安裝成功

Installing collected packages: ... gtts
Successfully installed ...

6.9 這時再重新執行 ./cloudspeech_demo.py 應該就可以順利執行了

* 因為 gtts 可以幫我們把文字存成 mp3的格式,接下來要安裝可以播放 mp3的套件。

6.10 用 vim ./cloudspeech_demo.py 打開程式,在

from gtts import gTTS

下繼續新增

from pydub import AudioSegment

然後執行,如果缺套件的話同樣輸入 pip3 install pydub 安裝

6.11 接著執行 ./cloudspeech_demo.py

6.12 確認兩個 python套件安裝完成後,接著我們把文字轉成語音撥出的函式放在 from ...def get_hints( ... 的中間

def say(text):
tts = gTTS(text) # 把文字變成gtts內建的物件
tts.save('output.mp3') # 把得到的語音存成 output.mp3
sound = AudioSegment.from_mp3('output.mp3') # 把 output.mp3 讀出
sound.export('output.wav', format='wav') # 轉存成 output.wav
audio.play_wav('output.wav') # 把 wav 用 VoiceKit 播出來

*打在#後的是註解,不用打

6.13 因為用到了 audio 這個套件,所以在上面的 from再多輸入一行:

from aiy.voice import audio

完成後如下圖:

6.14 接著存檔執行,確定沒有打錯

6.15 在 def main(): 後新增 say('test') ,如下圖

6.16 執行 ./cloudspeech_demo.py ,應該會看到以下錯誤訊息:

Traceback (most recent call last):
File "./cloudspeech_demo.py", line 81, in <module>
main()
File "./cloudspeech_demo.py", line 48, in main
say('Test')
File "./cloudspeech_demo.py", line 30, in say
sound = AudioSegment.from_mp3("output.mp3")
File "/home/pi/.local/lib/python3.5/site-packages/pydub/audio_segment.py", line 716, in from_mp3
return cls.from_file(file, 'mp3', parameters=parameters)
File "/home/pi/.local/lib/python3.5/site-packages/pydub/audio_segment.py", line 665, in from_file
info = mediainfo_json(orig_file)
File "/home/pi/.local/lib/python3.5/site-packages/pydub/utils.py", line 263, in mediainfo_json
res = Popen(command, stdin=stdin_parameter, stdout=PIPE, stderr=PIPE)
File "/usr/lib/python3.5/subprocess.py", line 676, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.5/subprocess.py", line 1282, in _execute_child
raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'ffprobe'

6.17 錯誤關鍵在 No such file or directory: ‘ffprobe’ 上面,請輸入以下文字進行安裝

sudo apt install ffmpeg

6.18 出現 Do you want to continue? [Y/n] 時請選 Y,接著執行 ./cloudspeech_demo.py

*沒問題的話應該能聽到 Test 的音效

接著,需要在原先開燈關燈判斷的地方加上開關完成的回應。

6.19 找到 if 'turn on the light' in text: 後面加上 say('the light has been turned on')

6.20 找到 if 'turn off the light' in text: 後面加上 say('the light has been turned off')

6.21 找到 if 'goodbye' in text: 後面加上 say('bye')後存檔、執行。

*此時的程式如下圖:

這階段完成的程式

7. 中文化

語音轉文字的中文化可以透過在執行的時候使用 --language=zh-TW 這樣的參數讓他變成中文。

7.1 將 say(text): 裡面的 tts = gTTS(text) 改成 tts = gTTS(text, lang='zh-TW'),如下圖所示:

7.2 判斷意圖的部分可以用 elif 依樣畫葫蘆,參考下圖:

其實可以自己玩玩看,例如「生日快樂」之類的

然後用 ./cloudspeech_demo.py — language=zh-TW 的方式執行

*因為語言參數會在

text = client.recognize(language_code=args.language, hint_pharses=hints)

被傳入(所以直接改這邊把它寫死也可以)

到這裡,我們就有了一個可以聽懂中文、也能回應中文的 Voice Kit啦~

大家都關心的費用問題

Cloud Speech To Text API (STT)需要付費,目前每 15秒 0.006美元 (約0.18台幣)每個月 60分鐘免費,大概是 240 次,一天平均可使用 8次

Text To Speech API (TTS)的部分主要是進行文字轉語音(還需要確認) ,目前每個月 400萬字以下的轉換是免費的,超過400萬字後,每 100 萬文字收取 4 美元 (約32元台幣)費用

以上兩種 API 如果都是由個人正常使用,應該都不會超過免費使用的額度。

同場加映:串接Maid White

只是控制 Voice Kit 上面的電燈,還不是個合格的隨身助手,如果要控制家中的電器,我們可以利用 Maid White Python SDK 來控制 Maid White 目前可以支援的設備(電燈、冷氣、洗衣機……)喔~

安裝透過 pip3 install maidwhite 進行,並透過以下程式碼進行控制

m = MaidWhite({access_token})
l = m.get_devices()
dl = [x for x in l if x.display_name == 'My lamp']
dl[0].set_state({"power_status": "true"})

完成後如下圖

access_token 的取得方式請參考 如何以qmote控制聲寶冷氣 這篇文章,透過以下命令取得

curl 'https://www.tih.tw/2/token' -d 'username=your@email.tw&password=yourpassword'

參考資料

AIY 多語系

Maid White Python SDK

如何開機自動啟動程式 (避免Voice Kit 插頭被拔掉…)

TIH

Written by

TIH

台灣智慧家庭(Taiwan Intelligent Home,TIH),以打造台灣軟體產業鍊為宗旨的公司,致力於智慧家電跨品牌整合,同時協助開發物聯網相關的應用程式。

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade