【改訂しました】AI連携FW『シンプルエーアイ』を使ってみた(2)：AIっぽい事をさせてみたい

#はじめに

**//-----2018/05/10追記ここから-----//**
閲覧ありがとうございます。
本記事の内容について、内容が複雑で分かり辛いというご指摘をいただきましたので、改訂版の記事を作成しました。
・[改訂版その1](https://qiita.com/denaripam/items/1aede5526136729ea0c5)
・[改訂版その2](https://qiita.com/denaripam/items/c53c01ea8856ab18f0f0)


また本内容につきましては、SSL接続が可能なサーバにアップしなければ、うまく動作しません。
改訂版の記事に詳細を記載しておりますので、ご参照下さい。
**//-----2018/05/10追記ここまで-----//**


AI連携フレームワーク『シンプルエーアイ』を使って遊ぶ、第二回目です。
この記事より、実際に作って動かします。環境等は、第一回目の記事をご覧下さい。
・[前回の記事（準備編）](https://qiita.com/denaripam/items/0c128c50788d9553f88e)

**公式サイトはこちら：[https://smartaifw.com/simpleai-trial/](https://smartaifw.com/simpleai-trial/)**


#AIといえば…
AIといえば、昔の映画のアンドロイドのように機械音声でお喋りしてくれるというのが、中の人の勝手なイメージだったりします。
今なら、某携帯会社の看板ロボ・ペッ○ー君のような、あんな感じでしょうか。
なので今回の記事では、さくっとお喋りさせてみたいと思います。

また、お喋りするだけだと物足りないので、画像分析機能も使ってみることにします。


#やりたい事

* 起動したら、カメラを使って自分を写す。
* マイクを使ってAIとお喋りする。
* 「人物判断」と声を掛けると、写っている人物の性別と年齢をAIが答えてくれる。



#(1)初期処理：カメラの処理

ここからは、実際のサンプルプログラムを元にご説明します。
サンプルプログラムを開くと、このようにカメラが起動し、画面いっぱいに表示されます。
![2-1.png](https://qiita-image-store.s3.amazonaws.com/0/255412/fc75b73f-7448-0f8a-0289-bb6f1287b375.png)

　
つまり、カメラの初期処理が必要です。
初期処理は window.onload イベントにて行うと良いでしょう。

シンプルエーアイ本体は、以下の一文を記入すればOK。

```js
var SimpleAI = new denaripamSimpleAI
```

その後の処理でカメラやマイクを初期化しています。

なお、下記の一文で、カメラの内部的な解像度の設定を行っています。
実際に画面に表示されている画像の解像度ではありませんので、ご注意下さい。

```js
initCamera:{ width: 1366, height: 768 },
```
これで、やりたい事の以下の部分が出来るようになりました。
* 起動したら、カメラを使って自分を写す。


#(2)APIキーの設定

…と、言いたいところですが、まだ大事な設定が残っています。
そう、APIキーですね。
[前回の記事（準備編）](https://qiita.com/drafts/0c128c50788d9553f88e)で取得しておいたキーを、ここで設定します。
設定するキーの種類と内容を間違えないよう、ご注意下さい。

```js
//-----uriBase、APIキーを設定してください START-----
			MicrosoftAzureFaceAPI:true,
			MicrosoftAzureFaceAPIuriBase:"",	//FaceAPIのエンドポイントを入力
			MicrosoftAzureFaceAPIsubscriptionKey:"",	//FaceAPIのキー①を入力

			MicrosoftBingSpeechAPIREST:true,
			//※↓は変更不要
			MicrosoftBingSpeechAPIRESTuriBase:"https://speech.platform.bing.com/speech/recognition/<RECOGNITION_MODE>/cognitiveservices/v1?language=<LANGUAGE_TAG>&format=<OUTPUT_FORMAT>",					//※↑は変更不要
			MicrosoftBingSpeechAPIsubscriptionKey:"",	//BingSpeechAPIのキー②を入力

			MicrosoftAzureComputerVisionAPI:true,
			MicrosoftAzureComputerVisionAPIuriBase:"",		//ComputerVisionAPIのエンドポイントを入力
			MicrosoftAzureComputerVisionAPIsubscriptionKey:"",	//ComputerVisionAPIのキー①を入力
//-----uriBase、APIキーを設定してください END-----
		},
	);
```

　
#(3)音声認識の設定

AIが音声を認識できるようにするには、以下の一文を追加します。

```js
//スマートエージェント開始
SimpleAI.SmartAgent();
```
初期処理でマイクさえきちんと初期化しておけば、これでもうお喋りできてしまいます。


#(4)AIに年齢を教えてもらう（音声キーの追加）

さあ、たったこれだけの設定で、やりたい事の二つは出来てしまいます。
ですが、まだ一つ残っています。
そう、以下の機能です。
* 「人物判断」と声を掛けると、写っている人物の性別と年齢をAIが答えてくれる。

###AIへの命令（音声キー）を、簡単に追加できるぞ

これは実は、『シンプルエーアイ』を使った独自機能の追加という事になりまして。
AIに投げかけたい言葉と行ってほしい動作を、JavaScriptで記入して追加する事ができるのです。

まずは、追加処理の全体像をどうぞ。

```Javascript
	//人物判断（スマートエージェントコマンド追加サンプル）
	if(SimpleAI) {
		var cmd;
		cmd=SimpleAI.getSmartAgentCommand();
		cmd.MainCommand.push(
			{
				//人物判断
				label: "PersonalJudgment",
				labelname: "人物判断",			//ラベル名称、現在のモード読み上げ等に使用
				word:[/人物/,/判断/],
				message:"人物判断を行います",
				messageafter:function(sender,event,param) {
					SimpleAI.Personinformation(
						{
							done:function(data) {
								var output=document.getElementById("denaripamSimpleAI_responseTextArea");
								if(output) {
									var responsedata = JSON.parse(output.value);
									//responsedata.Processingtext=Processingtext;
									if(responsedata[0]) SimpleAI.SpeechSynthesis(responsedata[0].Processingtext);
								}
							},
							fail:function(errstring) {alert("NG!!" + errstring);
							},
						},
					);
				},
			},

```



###命令文の追加は、まずこれを書こう

少しずつ見ていきますね。
何か音声キーを追加したいと思ったら、以下の部分が必ず必要です。

```js
if(SimpleAI) {		
	var cmd;	
	cmd=SimpleAI.getSmartAgentCommand();	
	cmd.MainCommand.push(	
		{

```

###命令文の追加用の構文は、こうなっている

次に、実際に追加したい音声キーに沿って考えます。

```js
label: "PersonalJudgment",
labelname: "人物判断",
```

上記二行分が、AIに対するキーの見出しです。後で分かり易いようにして下さい。

続けて、実際にAIが認識する「ことば」を設定します。

```js
word:[/人物/,/判断/],
```

"/"で囲まれた単語で一つのセンテンスとなっています。
","で区切る事で、複数の単語を一かたまりの命令文として設定しています。

続いて、音声キーを告げられた時にAIが返答する内容（メッセージ）を設定します。
喋らせたくない場合は空白にして下さい。

```js
message:"人物判断を行います",
```

メッセージの後に処理を行う場合は、以下の一文となります。
メッセージの前に処理を行いたい場合は「messagebefore:」です。

```js
messageafter:function(sender,event,param) {
```

この後に、実際に動作させたい内容をJavaScriptで記入します。
これで、音声キーが追加されます。


#サンプルプログラムコード全文


<details><summary>サンプルコード</summary><div>

```js

<!DOCTYPE html>
<html>
<head>
    <title>シンプルエーアイ　デモ</title>
    <script src="https://code.jquery.com/jquery-3.0.0.js"></script>
    <script src="simpleai-0.1.0.min.enc.js"></script>
<script>
//------------------------------------------------------------------------------------------------------------------------
//起動時処理
window.onload = function () {
	var SimpleAI = new denaripamSimpleAI(
		this,
		{
			successMicrophone:function() {	//Audioデバイス初期化終了時に実行する処理、自動音声認識など
	console.log("successAudio");
			},
			successCamera:function() {	//Videoデバイス初期化終了時に実行する処理
	console.log("successVideo");
			},
		},
		{
			initCamera:{ width: 1366, height: 768 },
			initMicrophone:true,
			SpeechSynthesis:{Mute:false},
			VoiceRecognition:{listen:true},

//-----uriBase、APIキーを設定してください START-----
			MicrosoftAzureFaceAPI:true,
			MicrosoftAzureFaceAPIuriBase:"",
			MicrosoftAzureFaceAPIsubscriptionKey:"",

			MicrosoftBingSpeechAPIREST:true,
			//※↓は変更不要
			MicrosoftBingSpeechAPIRESTuriBase:"https://speech.platform.bing.com/speech/recognition/<RECOGNITION_MODE>/cognitiveservices/v1?language=<LANGUAGE_TAG>&format=<OUTPUT_FORMAT>",
			//※↑は変更不要
			MicrosoftBingSpeechAPIsubscriptionKey:"",

			MicrosoftAzureComputerVisionAPI:true,
			MicrosoftAzureComputerVisionAPIuriBase:"",
			MicrosoftAzureComputerVisionAPIsubscriptionKey:"",
//-----uriBase、APIキーを設定してください END-----
		},
	);
//-----------------------------------------------
	//スマートエージェント開始
	SimpleAI.SmartAgent();
//-----------------------------------------------
	//人物判断（スマートエージェントコマンド追加サンプル）
	if(SimpleAI) {
		var cmd;
		cmd=SimpleAI.getSmartAgentCommand();
		cmd.MainCommand.push(
			{
				//人物判断
				label: "PersonalJudgment",
				labelname: "人物判断",			//ラベル名称、現在のモード読み上げ等に使用
				word:[/人物/,/判断/],
				message:"人物判断を行います",
				messageafter:function(sender,event,param) {
					SimpleAI.Personinformation(
						{
							done:function(data) {
								var output=document.getElementById("denaripamSimpleAI_responseTextArea");
								if(output) {
									var responsedata = JSON.parse(output.value);
									//responsedata.Processingtext=Processingtext;
									if(responsedata[0]) SimpleAI.SpeechSynthesis(responsedata[0].Processingtext);
								}
							},
							fail:function(errstring) {alert("NG!!" + errstring);
							},
						},
					);
				},
			},
			{
				//画面を閉じる
				label: "winEnd",
				labelname: "画面を閉じる",			//ラベル名称、現在のモード読み上げ等に使用
				word:[/画面|アプリ|ウィンドウ/,/閉じる|終了/],
				message:"お疲れさまでした",
				messageafter:function(sender,event,param) {
					window.open('simpleai-kyodai-0.1.0.html','_self').close();
				},
			},
		);
	}
//-----------------------------------------------
	//スマートエージェント　コマンド入力ボタン
	SmartAgentExternalmessagecmd
	var SmartAgentExternalmessagecmd = document.getElementById('SmartAgentExternalmessagecmd');
		SmartAgentExternalmessagecmd.addEventListener('click', function() {
			SimpleAI.param.SmartAgent.Externalmessage.push(document.getElementById('denaripamSimpleAI_SmartAgentExternalmessageText').value);
	  });
//--------------------------------------------
};
//------------------------------------------------------------------------------------------------------------------------
</script>
</head>
<body>
<video id="denaripamControlSensor_video" width=100% height=100% controls autoplay></video>
<canvas hidden id="denaripamControlSensor_snapshot--" width=100% height=100%></canvas><br>
<div id="denaripamSimpleAI_responseRect"></div><br>
<input hidden id="denaripamSimpleAI_responseTextLine" type="text" size="100"><br>
<input hidden id="denaripamSimpleAI_SmartAgentExternalmessageText" type="text" size="100"><button hidden id="SmartAgentExternalmessagecmd">実行</button></p>
<textarea id="denaripamSimpleAI_responseTextArea" class="UIInput" style="width:580px; height:400px;"></textarea><br>
</body>
</html>
```

</div></details>



#余談1：謎のエラーが出ると思ったら、Chromeのオーディオ自動再生の設定の仕様が変わっていた

このデモを作っている途中、気づいた事が一つありました。
マイクが正しく音声を拾っている事を確認する為に表示させたサウンドビジュアライザー（音声を波形で表示する部品）が、1回目の起動では必ずエラーになります。
![2-10.png](https://qiita-image-store.s3.amazonaws.com/0/255412/7e74b578-03b8-fd81-c110-d142e6c79076.png)



ソースは正しいのに、何故？

調べたところ、Chromeのオーディオ自動再生設定が原因でした。
詳細の原文ページはこちら：
[https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio)
2018年4月の仕様変更により、Chromeの設定を自ら変更していない場合、動画や音源は「自動再生しない」になります。
※試してみたところ、実際には「ページ読込時から7秒以上経つと自動再生を開始する」という動作のようです。
　原文を元に中の人が動作確認しただけなので、取り違い等があるやもしれません。詳細は原文をご確認下さい。

エラーを解消するには「ユーザーにクリックして貰う等、ワンクッション挟む」か、或いは「Chromeの設定を変更する」必要があります。
しかし「Chromeの設定を変更する」は環境依存なので、「ワンクッション挟む」が現実的な対応になるでしょう。
他の対処方法をご存じの方がいらっしゃいましたら、コメントいただければ幸いです。


#最後に

今回はここまでです。お疲れ様でした。
次回の記事では、更に機能を追加していきます。