Qichatでヴァーチャルなif文を作る(1)

(※ 次の(2)で、単純に説明します、笑)

ロボットは対話で動かすというのが、私の確信だ。NAOを動かすときは、基本Qichatで書かれたtopicファイルに、自作ライブラリを起動するための独自コマンドを埋め込んで、制御する。

この間、一つのスクリプトで、即興漫才と即興謎かけのネタを切り替えるようにした。このスクリプトは、お題として識別できる語数は20000万語を超えている。それも、Qichatに書かれている。

ここで問題は、Qichatの変数 $manzai の値が1の時は、もらったお題に対して即興漫才を実行し、それが0の時は謎かけをするようにしたい。しかも、お題として認識できるのは、標準でこれまで作成したコンセプト2500語に引っかかるのか、その後拡張した18000 語の方に引っかかるのかということがある。混ぜていないのだ。

当初は以下のような書き方をしていた。

u:(お題は _~manzai_concepts です) $manzai==1 $1 ですね。少しお待ちください。 $sub_main=$1 $telepathy_to_emily="emily_getmanzai_subjects/$sub_main"
u:(お題は _~manzai_extended_concepts です) $manzai==1 $1 ですね。少しお待ちください。 $sub_main=$1 $telepathy_to_emily="emily_getmanzai_subjects/$sub_main"
u:(お題は _~manzai_concepts です) $manzai==0 $1 ですね。少しお待ちください。 $sub_main=$1 $telepathy_to_emily="emily_getnazokake_subjects/$sub_main"
u:(お題は _~manzai_extended_concepts です) $manzai==0 $1 ですね。少しお待ちください。 $sub_main=$1 $telepathy_to_emily="emily_getnazokake_subjects/$sub_main"

ロボットの出力文の中に、条件式を入れている。何が違うんだということになるかもしれない。$telepathy_to_emilyというのは、私のライブラリ ibotライブラリのコマンドであり、emilyというのは制御コンピュータの名前で、それに対してお題を送っている。コンピューターからは、作られたネタの要素がこれも、telepathyコマンド(Qichat的にいうとイベント)で返されてくるのだが。つまり、私のibotシステムでは、ロボットとロボット、ロボットとコンピュータの、ローカルネットを経由したやり取りは、すべてテレパシー機能として実現している。それで、お互いのデータのやり取りも2000バイトまでは日本語でもできるようになっているのだ。

Qichatに戻ろう。後の二つが謎かけの、標準コンセプトと拡張コンセプトの場合である。$manzai==1というのは、$manzaiの値が1の時だけ真となる。

Quichatのロボット出力に、一つでも真でないものがあると、その全体が出力しないという機能を使っている。$manzaiが1の時は、前二つのいずれかにマッチングし、そうでない時は、謎かけの後者二つのいずれかにマッチングするはずだった。

しかし、これはうまく機能しないかった。細かくは調べていないが、考えられるのは、Qichatは、マッチングしているイベント処理ステートメントのどれか一つでも偽の文があると、たとえ真の文があってもそれを実行しないということだ。

たとえば「お題はチューリップです」という拡張コンセプトのチューリップに一致した入力文(イベント文)が、漫才と謎かけで二つある。$manzaiが1ならば、漫才の文にだけ一致すると思うのだが、全体が偽となって、実行しなくなってしまうということだと思う。

そこで、まず、次のように改良した。

u:(お題は _~manzai_concepts です) $1 ですね。少しお待ちください。 $sub_main=$1 [ $getmanzai_script=1 $getnazokake_script=1 ]
u:(お題は _~manzai_extended_concepts です) $1 ですね。少しお待ちください。 $sub_main=$1 [ $getmanzai_script=1 $getnazokake_script=1]
u:(e:getmanzai_script) $manzai==1 $telepathy_to_emily="emily_getmanzai_subjects/$sub_main"
u:(e:getnazokake_script) $manzai==0 $telepathy_to_emily="emily_getnazokake_subjects/$sub_main"

ポイントは、初めのロボット出力文の最後に、オプション処理の [ ] でくくっって、のちの、テレパシー送信文の漫才と謎かけのいずれかを実行するようにしたのだ。

これでいいかと思った。実際、ちゃんと謎かけのお題を与えると、パソコンにデータを送信し、回答をもらうようになった。そして、ネタ見せもこれでやった。

ただ、問題があることもすぐにわかった。たとえば、漫才の一つ目のお題をもらって実行する。それはちゃんとやる。しかし、それを終えて、もう一つお題をもらう。すると、「〇〇ですね、少しお待ちください」と言ったあと黙ってしまうのだ。そういう時は、もう一度お題を伝えると、今度はちゃんとテレパシーを送ってパソコンからの回答ももらう。

それで、さっき原因がわかった。 [  ] のオプションオペレータを使ったからなのだ。つまり[ ]がロボットの出力に与えられると、実行するたびに、一つずつ変わるようになっている。だから、最初のお題は、漫才用に対応するが、次にまたお題をもらうと、次の謎かけの処理をしてしまうのだ。

結局!!この [ ] を外したら思う通りの処理するようになった。 [ ]を外すと、選択せずに毎回両方実行する。その先のイベント処理の出力の中に、真があろうが偽があろうが関係なしに実行するのだ。だから、$manzaiが1の時は、つねに偽になっている、謎かけは実行されずに、漫才の処理だけが実行されるのだ。

あまりに単純なことで、笑ってしまいそうなくらいだった。

Mysqlにログインできなくなって

ロボットの対話関係の知識データは、基本的にいつでも持ち運んでいるmacbookのmysqlデータベースに入れている。ここから、ロボットも必要な情報を取ってくるし、決定的に重要なデータベースなのだ。
数時間前に急にログインできなくなった。あせった!!久しぶりにbookを再起動したのがきっかけか、なんなのか、よくわからないが、rootでもユーザーでも正しいパスワードを入れてもaccess denyになってしまう。
まさに、今日、ロボットのネタでこのデータベースを使うという時に。
2時間ほど悪戦苦闘した。結局何が何だかわからないのだが、やったことといえば、mysqlが入れていあるフォルダーがあって、そのデータ部分を実際、使っていたであろうデータに移し替えた。少し詳しく言えば、古いバージョンのmysqlmのフォルダーに、使っていたdataフォルダがあって、シンボリックされている新しいバージョンのmysqlのフォルダのdataフォルダは使っていたデータが入っていない。そこで、古いバージョンのdataフォルダーを新しい方に移して、オーナーをもとどおりに変えたりしたのだ。OSの方のrootになってだ。そのあたりは複雑なのだが。
そんなことを、色々やっているうちに、再起動すると、不意に戻った。ログインできるようになった。バンザーイ!!
すぐさま、今のデータベースのデータをmysqldumpで全てバックアプした。

ibotのライブラリにタイマーコマンドを加える

ロボットと何かパフォーマンスをやっているときに、尺が気になる。時間切れで失格ということが実際にあるからだ。そこで、対話システム用のコマンドに、タイマーコマンドを作成した。
トピックファイルの中に、
$wscom_starttimer_1=タイマー秒数
をいれると、それが実行された段階で、指定秒数のタイマーがスタートする。時間が来ると割り込みイベントが発生するので、それを、トピックファイルのイベント関数で、たとえば、
u:(e:TIMEOUT) 時間が来ました
のように、しておけばよい。
途中でタイマーを止める時は、
$wscom_stoptimer_1=1
をトピックファイルに埋め込んでおけば良い。

ldtexeの廃止

一連の動作及び発話を記述したコマンドリストファイルをロードし、対話の中の与えられたタイミングで実行する ldtexeを廃止する。同じコマンド ldexeがあるので不要だ。両方可能にしようかと思ったが、逆に混乱するので。
ldtexeは、ロボットの対話でコマンドリストを作り上げていくモードとトピックファイル中に埋め込むモードで、ロード&実行関数を区別していたのだが、区別が不要になって、意味がなくなっていた。

ロボット植え込み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にすることができるはずだ。
急いで作ろう。

qimessaging.jsの代わりになるcgi実行ファイル

埋め込みサイトで、apache2も正常に機能し、先に作成したファイルアップロード受け口用のC++で書いたcgiファイルも正常に実行されることが確認できたが、肝心のqimessaging.jsがうまく機能しない。呼び出し中に、ソケットIDがらみのエラーが出る。そのとのサーバーからの呼び出しでは問題なく機能していたのだが。
色々やれば、解決できるのかもしれないが、ふと、そこまでqimessaging.jsに位存在なければならないの??という疑問がふつふつと湧いてきた。ロボットのローカルでサーバーが動いている、C++で書いたcgiの実行ファイルも正常に動く。ロボット内部のライブラリ(システムのも、こちらで作成したもの)も問題ない。だったら、C++で書いたcgiの実行ファイルから、直接、ライブラリのメソッドを呼び出せばいいのではないか??
ふと、それをpythonで書こうかと思ったが、いやいや、それは面倒だ。直接C++で書けば良い。brokerを使えば、コンパクトで汎用性のあるものが作れるのではないかという気がしてきた。

ロボット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をコンパイルするところまではやった。
あとは、ロボットに持ち込んで、動かすだけだが、今日はこれ以上それをやっている余裕はないので、やめておく。明日は時間が取れると思う。