Docomo API 音声出力結果Jsonファイルのパース

Docomo APIの音声出力は、Jsonファイルとして返される。それをJavaで構文解析をする。使わせていただいたのは、以下のサイトにあるパーサー。
https://www.tutorialspoint.com/json/json_java_example.htm
要領とサンプルを掲載しておく。
(1)サイトから、ソースをダウンロードし、ライブラリ用のjarファイルを作成する。JsonSimple.jar
(2)以下のソースのライブラリに加える。jsonと配列の処理が頭の中でごちゃごちゃになる。(なお、上記サイトのデコードサンプルは、そのままではエラーになる。なんでそんなものを?)

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
import org.json.simple.parser.ParseException;
import org.json.simple.parser.JSONParser;

public class JsonParserTest {

String readJsonFile(){
// 出力結果をファイルから読み込む場合
// 通常は、httpレスポンスをそのまま、次のparseJasonで解析すれば良い
String json = “”;
try {
File file = new File(“/path/to/docomo_output.json”);
BufferedReader br = new BufferedReader(new FileReader(file));
String str;
while ((str = br.readLine())!= null) {
json += str;
}
br.close();
} catch (FileNotFoundException e) {
System.out.println(e);
} catch (IOException e) {
System.out.println(e);
}
return json;
}

void parseJson(String json){
JSONParser parser = new JSONParser();
try{
JSONObject obj0  = (JSONObject)parser.parse(json);
//認識テキストの出力
//出力テキストの全体は、textタグを読み取れば良い
System.out.println(“出力テキスト”);
System.out.println(obj0.get(“text”));
// 以上で良いのだが、分かち書きされた分析結果も受け取るようにして見る
// resultの値は、配列になっているので、まずその配列を受け取る
JSONArray results_array = (JSONArray)obj0.get(“results”);
// 配列の最初の要素を取り出す
JSONObject obj1_tokens  = (JSONObject)results_array.get(0);
// 配列の最初の要素が”tokens”というJsonになっているので、それをうけとる
// そのtokensの値が配列になっているので、配列として受け取る
JSONArray array1_tokens = (JSONArray)(obj1_tokens.get(“tokens”));
// tokensの配列をループにして回す
for(Object ob:array1_tokens){
JSONObject job = (JSONObject)ob;
String written = (String)job.get(“written”);
System.out.print(“書き方:”+written+”,”);
double confidence = (double)job.get(“confidence”);
System.out.print(“信頼性:”+confidence+”,”);
String spoken = (String)job.get(“spoken”);
System.out.println(“読み:”+spoken);
// 他の要素は省略
}
}catch(ParseException pe){
System.out.println(“position: ” + pe.getPosition());
System.out.println(pe);
}
}

public static void main(String[] args) {
JsonParserTest jparser = new JsonParserTest();
jparser.parseJson(jparser.readJsonFile());
}
}

Docomo API の音声認識は使える

Google Cloud APIが何かと使いにくく、レスポンスも遅いのでDocomo APIの音声認識を試してみた。結果的に、Googleより倍速い。認識率も悪くはない。使える。

以下の文章googleだと6秒以上かかるが、Docomoだと4秒かからない。

{
,”confidence”:0.700,”starttime”:0,”endtime”:8300,”tags”:[],”rulename”:””
,”text”:”今日はネタをやりますお客さんからお題をもらって、この第2ついて扇子とか、なぞかけに答えてもらうというもので、”}
}

NAO、コンセプトの搭載可能数

Pepperは、クラウドで、qichatのワイルドカード認識に対応しているようなのだが、NAOについては、NAOQIバージョンもPepperほどにも更新されておらず、対応していないようだ。それはそれでいい。というのは、Qichatでは、conceptにリストアップしておけば、ロボットはかなり正確に人の言葉を認識できるからだ。だから、conceptにどれだけのワードが載せられるかは、非常に重要な仕様になっている。

まえから、幾つもに切り分けしていれば、500個以上のコンセプトを識別できることはわかっていた。それは、実際使っているものだ。

しかし、一つのconceptのなかに、幾つ詰め込むことができるかは調べたことがなかった。実は、多くのコンセプトに分けるよりも、一つに詰め込むと便利なことがある。とても便利になるのだ。今日試してみてとても驚いた。なんと、一つのコンセプトに、2000個以上のワードを詰め込んでも、識別できたのだ。つまり、トピックファイルの中に、

concept:(words) [今日 明日 ロボット などなど ・・・・・・]

と2000個以上の言葉をwordsというコンセプトで登録しておいても、たとえば

u:(お題は _~words です) なになに $1・・・・・・

というかたちで、言葉の認識、変数 $1 への代入が可能になるのだ。もちろん、ALDialogで、そのトピックファイルを読み込み、コンパイルするのには多少時間がかかる。20秒くらいか。それは、スタート時だけだから、全然大したロスではない。

2000個も入れると、言葉の中に変な文字、つまり、ロボットが発音できない文字が入っていると、コンパイルに失敗してトピックファイルが有効化されない。アンダースコアとか、全角の数字(これがエラーになるのはちょっと不思議だが)とか、「つ」の小さい版「っ」がワードの最後に発音しにくい形で入っていても、コンパイルエラーになった。しかし、数の大きさは平気だったのだ。

NAOがワイルドカードの認識が下手なので、やむ負えず、Googleのcloud APIで変換させたりしていたのだが、音源ファイルで送ろうとも、ストリーミングにしようとも、やはり、人が喋ってからその結果をロボットに返すまでに10秒余のロスが発生して、ネタの120秒などという短い尺には、耐えられない長さになってしまう。conceptにおいて、聞き取られレベ、ほぼリアルタイムで時間のロスがない。

2000個というのは相当のキーワード数だ。実際それ以上が可能かもしれない。それ以上を試す気になれないほど、2000という数字は大きかった。

word2vecでロボットに言葉の演算をやらせた

この間、ずっとはまっていたのは、word2vecを使い、wikipediaに登場する単語を演算可能にすることだった。そこに、ボケの匂いを感じたのだ。word2vecは、ニューラルネットを使って、言葉を数量ベクトル化する手法だ。すると、言葉の演算がベクトル演算に変化できて、面白い結果が出てくる。

http://www.blog.umentu.work/ubuntu-word2vec%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E7%89%88wikipedia%E3%82%92%E8%87%AA%E7%84%B6%E8%A8%80%E8%AA%9E%E5%87%A6%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/

http://qiita.com/tsuruchan/items/7d3af5c5e9182230db4e
を参考にした。
wikipediaデータをmecabで分かち書きした膨大な単語について、演算が可能になった。たとえば、
ギター+キーボード
という演算をやらせると「セッション」になるとか。面白い。ネタになる。

隠れユニット200個で、学習結果のウェイトマトリクスデータが、900メガバイトを超える。

このデータは、ロボットNAOのストレージには入らない。そこで、NAOのUSBポートからデータをロードしようとしたら、当然のことなのだが、mallocで確保しようとしたヒープのメモリが、確保できない。仕方がないので、このデータを処理するライブラリを、パソコン上において、naoqiのリモートライブラリとすることで解決した。

人工知能など、およそ、その機能をロボットに全部組み込む事は不可能なので、PC上のリモートライブラリにするのはある意味自然なのだが、ロボットを立ち上げ、さらにリモートでライブラリを立ち上げるのは面倒だ。

しかも、言葉の聞き取りは、これも実に面倒なのだが、qichatを使って、トリがを与え、ロボットに喋りかけた言葉をwav音声データにして、パソコン上のサーバーに送って、それをさらにrawデータに変換したりして、Google cloud APIの音声認識システムに送って、テキスト化し、それをまたパソコン上で、形態素分析して、必要なデータを取り出し、またロボットのqichatのスクリプトの中にイベントとして取り組むと言う、質面倒臭いことをやる。それで、10秒くらい使ってしまうのが痛い。

しかし、まあ、これで、結構な人工知能をロボットに組み込んだことになる。

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

ロボットの対話関係の知識データは、基本的にいつでも持ち運んでいるmacbookのmysqlデータベースに入れている。ここから、ロボットも必要な情報を取ってくるし、決定的に重要なデータベースなのだ。

数時間前に急にログインできなくなった。あせった!!久しぶりにbookを再起動したのがきっかけか、なんなのか、よくわからないが、rootでもユーザーでも正しいパスワードを入れてもaccess denyになってしまう。

まさに、今日、ロボットのネタでこのデータベースを使うという時に。

2時間ほど悪戦苦闘した。結局何が何だかわからないのだが、やったことといえば、mysqlが入れていあるフォルダーがあって、そのデータ部分を実際、使っていたであろうデータに移し替えた。少し詳しく言えば、古いバージョンのmysqlmのフォルダーに、使っていたdataフォルダがあって、シンボリックされている新しいバージョンのmysqlのフォルダのdataフォルダは使っていたデータが入っていない。そこで、古いバージョンのdataフォルダーを新しい方に移して、オーナーをもとどおりに変えたりしたのだ。OSの方のrootになってだ。そのあたりは複雑なのだが。

そんなことを、色々やっているうちに、再起動すると、不意に戻った。ログインできるようになった。バンザーイ!!

すぐさま、今のデータベースのデータをmysqldumpで全てバックアプした。

ヒューマノイドロボットとコミュニケーション