Help us understand the problem. What is going on with this article?

簡単にできる!音声認識と音声合成を使ってRaspberrypiと会話

More than 3 years have passed since last update.

いきさつ

少し前にタ○ラト○ーのおもちゃハッカソンに申し込んだのですが、抽選に受からず。。。
「ならば自力でOH○NASの対抗馬を作ってやる!」と思いたったのがきっかけで、簡易会話ロボをRasタソを作ってみました。笑
(*実際の人物や団体等とは一切関係ありません)

やりたい事

・マイクからの音声入力に対して、合成音声で返答をする O○aN○Sもどきの作成

スペック

・Raspberry Pi B+
・raspbian 8 Jessie
SANWA SUPPLY MM-MCUSB16 USBマイクロホン
・イヤフォンはiphoneのやつ

Evernote Camera Roll 20160118 005007.jpg

役者

・requests (PythonのHTTPライブラリ)
・pyaudio (pythonでマイク入力)
・AquesTalkPi (合成音声)
・docomo雑談API (会話するためのAPI)
・docomo音声認識API (音声を認識してTEXTに変換するAPI)
※ はじめはJuliusを使おうかと思っていたのですが、軽く触った印象で処理速度と正確さがdocomo音声認識APIの方が良かったのでdocomo音声認識APIを使用する事にしました。

マイクの設定

まずはRaspberryPiでマイクを使用する為の準備を行います。(こちらを参考にしました)
マイクをさした状態でRaspberryPiを起動して、ちゃんと認識されているかを確認します。

$ lsusb
Bus 001 Device 005: ID 056e:4008 Elecom Co., Ltd
Bus 001 Device 004: ID 0d8c:0134 C-Media Electronics, Inc. 
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

良くわからないけど、今回の例だと Bus 001 Device 004: ID 0d8c:0134 C-Media Electronics, Inc.の部分がマイクの事らしいです。

USBオーディオアダプタの優先度を確認します。

$ cat /proc/asound/modules 
  0 snd_bcm2835
  1 snd_usb_audio

このsnd_usb_audioがマイクの事っぽいので、これを最優先にしないといけません。
ちなみにRaspberryPiはALSAを使用しているので、設定を変えるにはalsa-base.confを書き換えます。

ふむふむ、ではalsa-base.confを書き換えますか。。。ん?!
そして事件がおきました!!
なんと/etc/modprobe.d/alsa-base.confを開こうとすると、ファイルが存在していない!
これ結構ハマりましたorz
Jessie(OS)はalsa-base.confの代わりに/usr/share/alsa/alsa.confで修正するんやで、みたいな記事を見つけて、やってみるものの全くうまく行かず、調べても全然わからずにかなりハマりましたorz

結局、「無いのなら作ればよろし、confファイル(字余り)」という事で、alsa-base.confを作成したら解決できました。笑

$ sudo cat /etc/modprobe.d/alsa-base.conf
options snd slots=snd_usb_audio,snd_bcm2835
options snd_usb_audio index=0
options snd_bcm2835 index=1

上記のようにalsa-base.confを新規に作成し、RaspberryPiを再起動します。
そして再度、USBオーディオアダプタの優先度を確認します。
すると、ちゃんと優先度が変更されてるよー!(´∀`)

$ cat /proc/asound/modules
  0 snd_usb_audio
  1 snd_bcm2835

解決できたおかげで、モチベーションが一気に復活しました。笑
さて、次に一応マイクの感度を調整しておきます。

$ amixer sset Mic 50
Simple mixer control 'Mic',0
  Capabilities: cvolume cvolume-joined cswitch cswitch-joined
  Capture channels: Mono
  Limits: Capture 0 - 62
  Mono: Capture 50 [81%] [16.59dB] [on]

では実際に録音して、マイクに問題が無いか確認します。
arecordコマンドで録音を開始して 、Ctrl + Cで終了します。

$ arecord -r 16000 -f S16_LE test.wav
録音中 WAVE 'test.wav' : Signed 16 bit Little Endian, レート 16000 Hz, モノラル
^C 
シグナル 割り込み で中断...

lsコマンドなどで、ファイルができている事を確認したら、実際に再生してみます。

再生コマンドでは下記の様にサウンドカードナンバーとデバイスナンバーを指定する必要があります。
aplay -Dhw:[カードナンバー, デバイスナンバー] test.wav

RaspberryPi B+には標準でイヤホンジャックがついているので、イヤホンジャックのサウンドカードナンバーとデバイスナンバーを確認します。

 $ aplay -l
**** ハードウェアデバイス PLAYBACK のリスト ****
カード 1: ALSA [bcm2835 ALSA], デバイス 0: bcm2835 ALSA [bcm2835 ALSA]
  サブデバイス: 8/8
  サブデバイス #0: subdevice #0
  サブデバイス #1: subdevice #1
  サブデバイス #2: subdevice #2
  サブデバイス #3: subdevice #3
  サブデバイス #4: subdevice #4
  サブデバイス #5: subdevice #5
  サブデバイス #6: subdevice #6
  サブデバイス #7: subdevice #7
カード 1: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0

上記の内容だと
カード:1 デバイス:0 が 【スピーカ出力のオーディオ】
カード:1 デバイス:1 が 【HDMI出力のオーディオ】
の事らしいです。
なので今回使用するのは カード:1 デバイス:0 のですね。

では再生してみます。

$ aplay -Dhw:1,0 test.wav
再生中 WAVE 'test.wav' : Signed 16 bit Little Endian, レート 16000 Hz, モノラル

再生されました!
これで無事に、録音から再生まで一通り問題無い事が確認できました。

docomoAPI

次にdocomoAPIを使ってみます。
まずはdocomo Developer supportに登録します。
登録するとAPIKEYが発行されるので、今後はそのAPIKEYを使ってAPIを使用します。
では、まずは雑談APIから試してみます。

$ python
>>> import requests
>>> import json

>>> url = "https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY={}".format(APIKEY)
>>> payload = {
  "utt": "こんにちは",
  "context": "",
  "nickname": "光",
  "nickname_y": "ヒカリ",
  "sex": "女",
  "bloodtype": "B",
  "birthdateY": "1997",
  "birthdateM": "5",
  "birthdateD": "30",
  "age": "16",
  "constellations": "双子座",
  "place": "東京",
  "mode": "dialog",
}
>>> r = requests.post(url, data=json.dumps(payload))
>>> print r.json()['utt']
こんちは

上記の例は「こんにちは」っていう話しかけに対してAPIが「こんちは」って返してます。
簡単ですね!

次に音声認識APIを試します。
こちらは音声データを渡す必要があるので、もう一度ドキュメントを見てみます。

音声データのフォーマット:PCM(MSB)16khz/16bit

とあります。
PCMというのは非圧縮の音声データで、wikiには下記のようにあります

圧縮しない音声フォーマットはPCMそのものであり、Windowsでは .wavとして、Mac OS では .aiffとして格納される。

ちょうど先ほど作成したtest.wav(16khz/16bit)と条件も一致しているので、test.wavを使って試してみます。
ちなみにtest.wavには「なんでやねん」と言っている音声が入っています。
音声認識APIなので、この音声を認識して「なんでやねん」というテキストが返ってきたら良い訳ですね。

$ python
>>> import requests
>>> path = '/home/pi/test.wav'
>>> url = "https://api.apigw.smt.docomo.ne.jp/amiVoice/v1/recognize?APIKEY={}".format(APIKEY)
>>>files = {"a": open(path, 'rb'), "v":"on"}
>>>r = requests.post(url, files=files)
>>> print r.json()['text']
なんでやねん。

返ってきました!成功です!
これでdocomoAPIの使用は問題無さそうですね。

pyaudioで録音する

さて、さきほどマイク入力のテストをしましたが、やはり制御ができないと厳しいので、Pythonでオーディオ制御ができるpyaudioを使って録音を行ってみます。
pyaudioに関してはこちらを参考にさせて頂きました。
ではまず、pyaudioをインストールします。

$ sudo apt-get install python-pyaudio

参考サイトのソースをほぼそのまんまコピーして、動作確認します。

$ python pyaudio_test.py
Please input recoding time>>> 3
ALSA lib pcm_dmix.c:1022:(snd_pcm_dmix_open) unable to open slave
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm_dmix.c:1022:(snd_pcm_dmix_open) unable to open slave
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
ここでマイク入力を行います。

では、録音したらmono.wavファイルができている事を確認します。
ファイルができていれば先ほどと同じコマンドで、下記のように再生してみて録音ができてればOKです。

$ aplay -Dhw:1,0 mono.wav

うむ、ばっちり録音されておるわ!

AquesTalkで合成音声

さてさて、これで 音声入力 からの 音声認識 からの 雑談 まではできる様になりました。
あとは雑談APIにて、返ってきた返答をRaspberryPiことRasタソに発声させます。

まずはAquesTalkを公式サイトからダウンロードし、RaspberryPiにコピーします。

localpc ~ $ scp  ~/Desktop/aquestalkpi-20130827.tgz user@host:/home/pi/
aquestalkpi-20130827.tgz

RaspberryPiにコピーできたら、RaspberryPi内で解凍します。

$ tar xvf aquestalkpi-20130827.tar

解凍ができたら試しに実行してみます。
イヤホンから合成音声が聞こえてきたらOKです。

$ cd aquestalkpi
$ ./AquesTalkPi "オンギャーオンギャー" |  aplay -Dhw:1,0

再生!!
\オンギャーオンギャー/
き。。。聞こえました。。。
Rasタソが初めての自ら発声しました。。。泣
命が吹き込まれた瞬間です。笑

Rasタソと会話するの巻

さて、今のRasタソは脳に直接書き込まれた文章を発声するだけですが、こんなRasタソに知性を与えて「聞く、考える、発声する」という会話能力を与えます。

といっても上でやってきた事をまとめるだけなので、やる事は簡単です。
こんな感じでdialogue_test.pyを作成します。

復習がてらにdialogue_test.pyの内容を説明すると、
 1.pyaudioでマイク入力を受付。
 2.その音声をdocomo音声認識APIで認識してTextにします。
 3.そのTextを元にdocomo雑談APIを叩きます
 4.その結果を合成音声でしゃべらせます。
というものですね。

では実行してみます。

$ python dialogue_test.py
Please input recoding time>>>3
~~snip~~
元気ですか? ←マイクから入力した内容
元気でちゅ ←Rasタソの回答

$ python dialogue_test.py
Please input recoding time>>>3
~~snip~~
何歳ですか。←マイクから入力した内容
ところで、気になるニュースがあるんだが、カルビーと阪急そばがコラボレーションして「関西だししょうゆポテトチップスそば・うどん」を期間限定で販売、関西だしの旨みと斬新な食感が味わえるそうでちゅ←Rasタソの回答

$ python dialogue_test.py
Please input recoding time>>>3
~~snip~~
誕生おめでとう。←マイクから入力した内容
楽しみに待ってるか? ←Rasタソの回答

赤ちゃんなので、ちょっと会話が成り立たない事もありますが、そこは御愛嬌です!
ちゃんとdocomoAPIを使いこなせば、もっと賢くなるそうですが、それは今後の課題にしていきます。

最後に

こんな事まで簡単にできてしまう世の中にビックリですね。
今後はもっと賢くして、Siriみたいにして、顔認識機能とかもつけてとか夢は広がります^^
という事で、今後も時間と根気などがあればRasタソを成長させていきますので楽しみに待っていてください。

kinpira
colorful-board
「すべての人々に、人生が変わる出会いを」をビジョンとして、これまで出会えなかった情報と瞬時に出会うことで人々の生活をより豊かにする、新しい情報発見のためのプラットフォームを目指しています。
https://sensy.ai/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした