Google Cloud APIのストリーミングを継続して使う

Google Cloud APIのストリーミング音声認識を、ロボットとの継続した対話に使おうとすると、60秒の制限があって、それ以上使えずに、例外が発生してアボートしてしまう。これでは使えない。
そこで、gracefull(優美)に一つの会話を終了させながら、次の会話に入っていくということがどうしても必要になる。その基本的なやり方を以下に記しておく。
(1)ロボットからの音声データのストリーミング入力は、それとして生かしておくという戦略。
(2)Google Cloudからは、送られたーデータの解析結果が中間的に、最終的にの二つのバージョンで送られて来るが、最終バージョンが送られて来たら、それを一旦出力(エコーロボットとしてロボットに喋らせる、あるいは、人間入力の言葉を解析して応答を用意したりして)
(3)これで例外を発生させずに終わるが、これだと一回の聞き取りしかできなくなってしまう。そこで、
requests = request_stream(buffered_audio_data, RATE)
のスレッドの作成から、再度はじめ直す必要がある。そこでここからを関数化して、先の終了後に、再帰的にこの関数を呼び出すようにすればいい。すると、また60秒制限の新しいスレッドが立ち上がる。無限続けるのは良くないので、いったい何度ロボットやり取りするかを事前に与えておいて、その回数の会話をしたら全てを終了させるようにすれば良い。
(4)一つ問題は、(2)で、会話が入れば、一つのスレッドはグレースフルに終わるが、無言の時間が続くと終わるタイミングを逃して例外を発生させてしまう。そこで、60秒以内の一定時間無言が続くと、一旦gracefullに終わらせる。
そこで、次のようなタイマーイベントを、先に分離した関数部分の中に置いておく、
###############
def stopAPI():
print "ループを止めます"
recognize_stream.cancel()
#ここまでが関数、以下でタイマーでこのハンドラーを呼び出す
t=threading.Timer(MAX_SILENT_LENGTH,stopAPI)
t.start()
###############
関数の中にstopAPIという関数を定義して、MAX_SILENT_LENGTHの秒数が経過すると、
recognize_stream.cancel()
というイベントを発生させる。すると、CANCELLという例外が発生して、綺麗に終わるように例外処理手続きが組み込まれているのでうまくいく。そしてこの例外処理が終わった後、さいど、先に作成した関数、request_streamから始める関数をスタートさせれば良い。
これで、指定回数の会話が終わるまで、継続的にGoogle Cloud APIでストリーミング処理を続けることができる。
これで、人工無脳の会話ボットと、ロボットNAO、そしてGoogle Cloud APIの三つをつなぐ準備が80%ほど、整った。

エコーロボット(echo robot)の考察

人間的知能の最もプリミティブな形態は、音を言葉に変えることだと思う。たとえば、見知らぬ外国語は言葉ではなく単なる音でしかない。しかし、それが言葉に変わった時、すべての人間的知能の基礎ができる。言葉は、まさにロゴスなのだ。
この間、Googoleのcloud apiのストリーミングの音声解析をやってきたが、結局それは、知能なのだ。非常に単純で、簡単なことをやっているように思われるかもしれないが、そこにこそ人工知能の基礎がある。音を連続的に言葉に変えること、それは素晴らしいことだと思う。確かに、その言葉を意味化することはできていない。しかし、決定的に重要な一歩だと思う。
そこで、エコーロボットというのを考えてみる。いや、実際に作ってみようと思う。人が話しかけた言葉を、そのまま鸚鵡返しに、自分で繰り返すのだ。音声を単にロボットの発音に変換するのではない。一旦、「言葉」してから、ロボットの音声としてそれを発するのだ。赤ちゃんが、お母さんの言葉を真似しながら、言葉を覚えていくことに似ている。マネができれば、その意味を少し理解して返せば、ごく簡単な人間的応答ができてしまうはずだ。お笑いで言えば、いつかそれがボケにつながる。
エコーロボットは、人工知能型ロボットの最も初歩的なもので、プログラミングで言えば、"Hello World" に対応するものだ。
そのための技術としては、まず、ロボットの音声データをストリーミングで受け取る必要がある。これは、ALAudioDeviceでできることがわかった。それを、GoogleのCloud APIに送って、これまたストリーミングで言葉化する。返ってきた言葉を、ロボットに送り込んでALTextSpeechで発生させる。
プログラミングのツボはだいたいわかったので、数日中にはできると思う。
 
 

ロボット植え込みiBotは、ほぼできた

途中、ロボットのウェッブサーバーをapache2にしようかという迷いがあったが、結局、originalのnginxを使った。これからは、本番は、スマホだけで全て処理できる。
こちらに何か支障があれば、今まで通りノートブックのサーバー上のiBotでもコントロールできるので、セキュリティが高まった。
ロボット植え込みiBotの弱点は、パソコンからのファイル転送をftpなどに頼らなければならないところだ。これも、nginx用のfcgiを使えるようになればなんとかなるので、しばらくそれに取り組みたい。
それが終わったら、 クラウドの人工知能機能を利用する段取りに入りたい。

apache2のcgiから、naoqiのロボット制御モジュールを呼び出す

ALTextToSpeechを呼び出して「こんにちわ、サリーです」とロボットに言わせる単純な、cgiをC++で作った。NAO(名前がサリー)に組み込んだ、apache2のcgiとして、外部のpcからアクセスすると、ちゃんとロボットは喋った。
qimessaging.jsの代わりに、qimessaging.cgiをC++で作れることはほぼ間違いがない。ALbrokerを使えば、汎用性の高いcgiにすることができるはずだ。
急いで作ろう。

ロボットnaoにapache2ウェッブサーバーをインストール

前に書いた理由で、新たにnaoにapache2をインストールすることにした。手順をメモがわりに書いておく。
(1)apache2の最新版をダウンロードする。ここでは、apache2-2.4.25を使った。
(2)opennaoバーチャルロボットにpsftpなどで転送し、解凍する
(3)解凍したフォルダで、./configure --prefix=ロボット上のインストールしたいフォルダの指定する。私は、rootじゃなく、naoで実行したいので、/home/nao 以下のフォルダを指定した。
(4)普通にmakeとmake installを実行する。エラーは出ない。
(5)インストールしたフォルダごとアーカイブし、naoの実機に転送する。
(6)httpd.confを編集する。私の場合は、portを80から8080に変更。変更しないと、通常のrobotページとバッティングするので。cgiを動かす設定、ドメイン名がコメントアウトされているのをそのまま外す。関係のないドメイン名になっているが、コメントアウトするとスタート時に警告が出るを避けるだけの目的。
(7)ただ、これだけでは、apachectl startとやるとライブラリがらみのエラーが出て、実行できない。そこで以下の操作をやる。
opennaoの/usr/libディレクトリから、次の二つのファイルを取ってくる。
libaprutil-1.so.0
libapr-1.so.0
これをapache2のあるフォルダ以下libフォルダを作成してその下に入れておく。今そのフォルダを、
/home/nao/hoge/lib
だったとしよう。/etc/ld.so.conf.d/にnanoを使って、apache.confファイルを作り、そこに、上記フォルダのパスを書いて保存する。
ロボットのrootになって、ldconfigを実行する。その後、
ldconfig -p | grep libapr
をrootで実行すると、
libaprutil-1.so.0 (libc6) => /home/nao/ibot/www/lib/libaprutil-1.so.0
libapr-1.so.0 (libc6) => /home/nao/ibot/www/lib/libapr-1.so.0
となり、これでOKである。
あとは、ポートを8080にしている限り、rootにならなくても、naoユーザーのままで、apachectl
./bin/apachectl start
を起動すれば、サーバーが立ち上がり、ロボットのipとポートを指定すると、
と、無事立ち上がった。

ロボットにapache2を入れようと

naoには、nginxというウェッブサーバーが入っている。それはそれでいい。しかし、c++で作った実行ファイルをcgiにしたいのだが、nginxにはcgiを直接動かす機能がないので、fastcgiなどを追加しなきゃいけないらしい。それもまた入っているようなのだが、pythonしか動かないような設定になっているように見える。nginxやfastcgiに不慣れなので、不確かなのだが。
これ以上、いじると、元のロボットページなどに影響が出るかもしれないので、別にウェッブサーバーを動かそうと思う。ポートを、80じゃなくて、8080あたりにしておけば、nginxとバッティングしないだろう。
apache2は長年使い慣れている。ちょっと重たいが、まあ、それほどディスクを食うわけではない。
ただ、前にも書いたように、ロボットには、g++などの開発ツールは入っていないので、opennaoというvirtual-naoを使う必要がある。ここで開発すれば、まあ、naoに持ち込めると踏んでいる。そこで、opennaoでapache2をコンパイルするところまではやった。
あとは、ロボットに持ち込んで、動かすだけだが、今日はこれ以上それをやっている余裕はないので、やめておく。明日は時間が取れると思う。

埋め込み用ibotサイト

ロボットをコントロールするためのWEBシステムibotをロボット自身のサーバー上で動かすための改変をしていたが、それは終えた。いざ、通常のロボットサイトの下にibotというフォルダを作りそこに入れようとしたら、そもそも、ロボットのLinuxでphpが動いていないことに気づいた。
phpでサーバーサイドの処理を行うhtml5システムなので、困った。phpを入れようとすると、gccやらgmakeなどをインストールしなければならず、それが限りなく重たい。そこで、naoqiの指摘ライブラリの中で、ファイルを操作などを行うようにしようと思った。つまり、javascriptからqimessaging.jsでC++で作成したnaoqiのライブラリを呼び出して、サーバー内のファイル操作をやらせるのだ。ただ、パソコンからのファイルのアップロードの受け取り処理をphpにやらせていたのだが、それをライブラリでやる方法が今ひとつわからない。

ibotをバージョンアップする

一つ大きな仕事があって、安定したibotシステムで対応しなければならなかったので、本格的な変更を全くしなかった。それが終わって、これからもっといいシステムにする。当面の改良すべき点は、
(1)複数ロボットを扱っている時Qimessaging.jsからsessionオブジェクトを、毎回作り直していたが、これが無駄なので、sessionを連想配列の中に入れて、使い回せるようにする。
(2)telepathyがやはり不安定なので、現在のような複数ロボットの起動時に、他のすべてのロボットの状態をすべて認識するというのはそのままに生かして、それをたとえやらなくても、あるいは既にやっていたとしても、ibotクライアント側が持っているすべてのロボット情報を事後的にロボットに送り込んで、telepathy通信に用いられるようにする。
さらに抜本的には、先に書いたロボットの聞いた言葉をクライアント側で、文字列に起こして人工知能的処理ができるようにしたい。

Juliusにwav音声ファイルをテキスト化させる

先の投稿の手続きの段階の、chromeのweb speech apiの代わりに、juliusを使えないかと試したところ、ほぼ、問題ないレベルで答えを出すことがわかった。
Juliusにwavファイルで、音声データを与えて、それをテキストに変換させてみた。

 
 
これで、プロセスとプログラムが、単純化される。

音声認識でweb speech api を使う

今日考えていたことをメモがわりに書いておこう。
(1)ロボットNAOが受け取った人の言葉を音声ファイルに出力することは制御できるだろう。C++でライブラリ化することができる。
(2)そのファイルをPC、つまりMACbookに、無線ネットワーク経由で送ることもできる。
(3)MacでChromeを開いていて、ibotサイトを表示しているとすると、Chromeのweb speech api が使えるだろう。
(4)受け取った音声ファイルをJAVAで、実際の音として出力することはできるだろう。
(5)その音を、物理的コードを使って、マイク入力として直接入力することができるだろう。
(6)その入力に反応して、音声をweb speech apiがテキスト化することができるだろう。
(7)javascriptからjavaを呼びだして、そのテキストを、JAVAで解析して、求める答えを構成させることができたとする。
(8)それをロボットに送り込み、qichatの変数に組み込み、それを読み出させるイベントを発生させることができるだろう。
(9)ロボットは、その内容を喋るだろう。
※PCはインターネットに接続していなければならない。
以上