AI連携FW『シンプルエーアイ』を使ってみた(4)：より「魔法の鏡」らしく

#はじめに

AI連携フレームワーク『シンプルエーアイ』を使って遊ぶ、第4回目です。
・[(1)準備編](https://qiita.com/denaripam/items/0c128c50788d9553f88e)
・[(2)：AIっぽい事をさせてみたい(その1)](https://qiita.com/denaripam/items/1aede5526136729ea0c5)
・[(2)：AIっぽい事をさせてみたい(その2)](https://qiita.com/denaripam/items/c53c01ea8856ab18f0f0)
・[(3)：「魔法の鏡」を作るぞ](https://qiita.com/denaripam/items/80e0e8b3e68585c2e921)

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


#実用性も大事ですが…

前回の『[(3)：「魔法の鏡」を作るぞ](https://qiita.com/denaripam/items/80e0e8b3e68585c2e921)』では、起動したら現在日時が表示されている鏡が表示され、「人物判断して」と声を掛けると、結果が鏡に表示されるようにしました。
続いては、前回の前書きに書いた「前にどんなお化粧をしたかが判れば便利」という要素の実現を考えていましたが…
折角のお遊びですので、今回は更に”魔法の鏡”っぽい、使う楽しみを上乗せする方向で進めたいと思います。


#”魔法の鏡らしさ”とは何ぞや

とは言うものの、”らしさ”って何だろう？
色々考えてみましたが、やはりここは『シンプルエーアイ』の使いやすさを生かした、お遊び要素を加える事にします。

『シンプルエーアイ』は、AIの返答の仕方等も柔軟に変更することができます。
今は「了解」と返事をしてくれるのですが、これを変えてしまいます。
そもそも「人物判断」という言葉も、実際の機能が分かり辛いので、一緒に変更します。

それから、お化粧する時に音楽が流れていたら、作業が捗るのではないでしょうか。
ですので、「音楽をかけて」等と呼びかけると、音楽を流すようにしたいと思います。
ついでと言っては何ですが、天気予報やニュースも見られるようにしてしまいましょう。


#やりたい事

今回の記事では、以下のような機能を追加します。

* AIの応答の言葉を変える
* 人物判断の言葉の変更
* 「音楽をかけて」と呼びかけると、鏡の上部に画面を開いて音楽を流す（Youtube起動）
* 「天気教えて」や「ニュースを見たい」と呼びかけると、鏡の上部に天気予報やニュースを表示する（Youtube起動）


#AIの応答の言葉を変える

それでは、本記事で想定しているサンプルプログラムの動作を説明します。
まず、鏡に呼びかけた時に「かしこまりました」と返答をしてくれるようにします。

『シンプルエーアイ』のスマートエージェント機能には様々なパラメータがあります。
サンプルプログラムでは「SimpleAI.param.SmartAgent」と記述している部分が、そのパラメータ部分です。
このうちの「Prompt」が応答の言葉なので、この値を設定しましょう。スマートエージェント開始処理の後に行って下さい。

またAIのお喋りの語尾を変えることも出来ます。「PromptEnd」というパラメータです。
ここで冒頭に「、」を入れているのは、お喋りする際に一泊置いてもらう為です。
ここでは、語尾に「ご主人様」と言うようにしました。

追加部分のソースは以下の通りです。

```js
//AIの応答の言葉を変更する
SimpleAI.param.SmartAgent.Prompt = "かしこまりました、";
//AIの語尾の言葉を変更する
SimpleAI.param.SmartAgent.PromptEnd = "、ご主人様";
```


#人物判断の言葉の変更

続けて、人物判断を呼び出す言葉・音声キーを変更します。
お化粧情報も含めて表示するので、「メイクチェック」などの言葉にしましょう。

まず、以前に設定した、人物判断処理追加部分のソースがこちら。

```js
//人物判断（スマートエージェントコマンド追加サンプル）
var cmd;
cmd=SimpleAI.getSmartAgentCommand();
cmd.MainCommand.push(
	{
		//人物判断の音声キーを追加する
		label: "PersonalJudgment",
		labelname: "人物判断",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/人物/,/判断/],
				message:"人物判断を行います",
```

おさらいになりますが、音声キーそのものは「word:」の部分を設定すればOKです。
ただし「message:」の部分にも”人物判断”という言葉が入っているので、今回は併せて変更します。

変更後のソースはこちらです。

```js
//人物判断の音声キーを追加する
label: "PersonalJudgment",
labelname: "人物判断",				//ラベル名称、現在のモード読み上げ等に使用
word:[/メイク|make|化粧|けしょう|仕上げ/,/check|確認|判断|判定|見て/],
message:"しばらくお待ちください",
```

###余談：AIが聞き取り辛い言葉がある

当初は「幾つに見える？」という言葉にしようとしたのですが、AIにとっては大変聞き取り辛い言葉らしく、うまく判定してくれませんでした。
「メイク」という言葉も同様で、なぜか違う言葉に判断されてしまいがちです。

では、AIが言葉をどのように聞き取ったかを、どうやって確認すればいのでしょう。
ブラウザの機能の一つである開発ツールを使えば、AIがどのように判断したかを見る事ができます。

Chromeの場合は、画面右上のメニューより「その他のツール」→「デベロッパーツール」を開いて下さい。
「Console」欄が開いていない場合は、クリックして開きます。

すると、以下のように処理ログが表示されるようになります。
下図の場合で言うと、上の赤枠部分は「メイクチェック」と呼びかけた場合、下の赤枠は「メイク判断」と呼びかけた場合です。
「メイクチェック」という言葉が、うまく聞き取られていない事が判りますね。
![4-1.png](https://qiita-image-store.s3.amazonaws.com/0/255412/bf1865a1-fca4-d81a-0d3f-b29926fef33b.png)

　

ですので今回は、「メイク」だけではなく「化粧」など、幾つかの言葉を設定しました。
このように、AIにとって聞き取り易い／聞き取り辛い言葉がありますので、キーワードを設定する際は、何度か試す必要があるでしょう。


#「音楽をかけて」と呼びかけると、鏡の上部に画面を開いて音楽を流す（Youtube起動）

それでは次に、音楽を流す処理を追加したいと思います。

サンプルプログラムの動作を説明します。
「音楽をかけて」「音楽ききたい」といった呼びかけをすると、Youtubeの小さな画面を鏡の右上に上乗せして開き、指定したキーワードに該当する音楽を流してくれるようにします。
音楽呼び出し後の画面は、こんな風になります。画面右上の赤枠部分がYoutubeの画面です。
![4-2.png](https://qiita-image-store.s3.amazonaws.com/0/255412/5b37a167-feb8-c41f-2b75-fa867f77ef42.png)


###Youtubeを扱えるようにする

この動作を行うためには、まずはYoutube動画を扱えるように変更する必要があります。

まずHTMLのヘッダ部分に、Youtubeを扱う為の宣言を追加して下さい。
追加部分のソースは以下の通りです。

```html
<script type="text/javascript" src="https://www.youtube.com/iframe_api"></script>

```

また、Youtubeを表示する部分をHTMLに追加します。
サンプルプログラムでは、情報表示部分とvideoタグの間に挿入しました。
修正後のソースは以下の通りです。

```html
<p class="msg-over-top" id="dispMsg"></p>
<p class="youtube-over-top" id="dispYTPlayer"></p>
<div class="video-wrap">
  <video id="denaripamControlSensor_video" width="800px" height="600px" controls autoplay>
  </video>
</div>
```

勿論、CSS側にもYoutube重ね合わせ表示の追加が必要です。サンプルプログラムのソースは以下の通り。

```css
/* YoutubePlayer表示部 */
.youtube-over-top {
	opacity: 0.5;	/* 対象の透過度(0:完全透明 1:不透明) */
	position: absolute;
	left: 580px;
	top: 2%;
	z-index: 1;
	padding-left: 5px; padding-right: 5px;
}
```

続いて、JavaScriptでYoutube起動処理を組み込みます。
サンプルプログラムでは YouTubePlayerAPI を利用する事にしました。
最初に YouTubePlayerAPI のオブジェクトを作成し、「YouTubeIframeAPI=true;」で有効にします。

それから「YouTubeplayer_start」という関数を作成し、実際のYoutube起動処理を記述します。
オブジェクトがあればいったん停止処理を行い、そして改めてnewで作成しています。
Youtubeの表示サイズ等は、ここで指定します。

追加部分のソースは以下の通り。

```js
//youtube
var YouTubeplayer;
var YouTubeIframeAPI=false;
 function onYouTubeIframeAPIReady() {
	YouTubeIframeAPI=true;
}
//youtube表示ウィンドウ
var html_temp_modal = 
	 '<!-- YoutubePlayer -->'
	+'<div class="embed-responsive embed-responsive-16by9">'
	+'	<div class="embed-responsive-item" id="player"></div>'
	+'</div>';
//youtube起動
var YouTubeplayer_start=function(keyword,volume) {
	if(YouTubeIframeAPI) {
		YouTubeplayer_stop();
		YouTubeplayer = new YT.Player('player', {
			height: '150',
			width: '200',
			controls: 2,		//コントロールの表示
			iv_load_policy: 3,	//アノテーション非表示
			showinfo: 0,		//インフォメーション非表示
			events: {
				onReady: function(event){
					if(keyword) YouTubeplayer.loadPlaylist({listType:"search",list:keyword,});
					if(volume)  YouTubeplayer.setVolume(100);
				},
			},
		});
	}
};
```

起動処理と対になる停止処理も、ここで入れてしまいましょう。
「YouTubeplayer_stop」という関数を作成し、Youtube停止処理を記述します。ここではdestroy、つまり破棄をしています。

追加部分のソースは以下の通り。

```js
//youtube停止
var YouTubeplayer_stop=function() {
	if(YouTubeplayer)YouTubeplayer.destroy();
};
```

###音楽をかける音声キーの追加

これでYoutubeを扱えるようになりましたが、勿論これだけでは足りませんね。音声キーの追加が必要です。
以前に追加した「人物判断」の後ろに処理を加えましょう。

音声キーの追加そのものは以前の記事で行っていますので、今回のサンプルプログラムにおける新しい要素だけを説明します。
まず、サンプルプログラムの対象部分のソースを見て下さい。

```js
//音楽をかける音声キーを追加する
{
	label: "PlayMusics",
	labelname: "音楽をかける",				//ラベル名称、現在のモード読み上げ等に使用
	word:[/音楽|mugic|曲/,/かける|かけて|流す|流して|きく|きかせて｜ききたい/],
	message:"こちらの曲をどうぞ",
	messageafter:function(sender,event,param) {
		document.getElementById("dispYTPlayer").innerHTML = html_temp_modal;
		YouTubeplayer_start("やる気の出る クラシック音楽 ピアノBGM");
	},
},
```

先程追加したJavaScript関数「YouTubeplayer_start」を呼び出す際に、キーワードを指定していますね。
これは実際にYoutubeで検索処理を行う為のキーワードで、この言葉をYouTubeIframeAPIに引き渡して検索処理を行うようになっています。
下記ソースの「if(keyword) YouTubeplayer.loadPlaylist({listType:"search",list:keyword,});」の部分です。
なお、次行の「if(volume)  YouTubeplayer.setVolume(100);」の部分で、音量を設定しています。

```js
if(keyword) YouTubeplayer.loadPlaylist({listType:"search",list:keyword,});
if(volume)  YouTubeplayer.setVolume(100);
```

以上の処理で、鏡に向かって「音楽かけて」等と告げると、鏡の下にYoutubeの音楽動画が表示されるようになりました。

###音楽を止める音声キーの追加

始まりがあれば終わりがあるので、音楽を止める音声キーも必要ですね。さくっと追加してしまいましょう。
先程作成した「YouTubeplayer_stop」を呼び出すようにして下さい。
対象部分のソースは以下の通りです。

```js
//音楽を止める音声キーを追加する
{
	label: "StopMusics",
	labelname: "音楽を止める",				//ラベル名称、現在のモード読み上げ等に使用
	word:[/音楽|mugic|曲/,/止める|止めて|やめる|やめて|終わり|終了/],
	messageafter:function(sender,event,param) {
		YouTubeplayer_stop();
	},
},
```


#「天気教えて」や「ニュースを見たい」と呼びかけると、鏡の上部に天気予報やニュースを表示する（Youtube起動）

Youtubeの起動/停止という、大きな処理が追加できました。
ここをクリアしたら、天気予報やニュースの表示も軽いものです。

やり方は音楽呼び出しとそれ程変わらず、それぞれの起動処理と停止処理の音声キーを追加します。
それでは、サンプルプログラムの追加部分のソースを見て下さい。

```js
//朝のニュースを呼び出す音声キーを追加する
{
	label: "ShowNews",
	labelname: "ニュース表示",				//ラベル名称、現在のモード読み上げ等に使用
	word:[/ニュース/,/見る|見せて|見たい|流す|流して/],
	message:"どうぞ",
	messageafter:function(sender,event,param) {
		document.getElementById("dispYTPlayer").innerHTML = html_temp_modal;
		var date = new Date();
		YouTubeplayer_start("nhk 朝のニュース");
		//前ゼロなし日付だと予想と異なるものが表示される。前ゼロ付きスラッシュ日付だと、うまく再生できなくなる。
		//YouTubeplayer_start("nhk ニュース " + formatYMD(date));
	},
},
//朝のニュースを止める音声キーを追加する
{
	label: "StopNews",
	labelname: "ニュース停止",				//ラベル名称、現在のモード読み上げ等に使用
	word:[/ニュース/,/止める|止めて|やめる|やめて|終わり|終了/],
	messageafter:function(sender,event,param) {
		YouTubeplayer_stop();
	},
},
//天気予報を呼び出す音声キーを追加する
{
	label: "ShowWeatherForecast",
	labelname: "天気予報表示",				//ラベル名称、現在のモード読み上げ等に使用
	word:[/天気/,/教えて|見る|見せて|見たい/],
	message:"どうぞ",
	messageafter:function(sender,event,param) {
		document.getElementById("dispYTPlayer").innerHTML = html_temp_modal;
		var date = new Date();
		YouTubeplayer_start("全国の天気予報 朝");
	},
},
//天気予報を止める音声キーを追加する
{
	label: "StopWeatherForecast",
	labelname: "天気予報停止",				//ラベル名称、現在のモード読み上げ等に使用
	word:[/天気/,/止める|止めて|やめる|やめて|終わり|終了/],
	messageafter:function(sender,event,param) {
		YouTubeplayer_stop();
	},
},
```

###余談：YoutubePlayerAPIにスラッシュ編集の日付をキーワードとして引き渡すと、うまく引き当ててくれない

ニュースにしても天気予報にしても当日の日付が必要だろうと、スラッシュ編集した（つまり'2018/05/16’のような書式ですね）日付をキーワードに引き渡したところ、なぜかうまく動画が表示されません。
YoutubePlayerの枠は表示されるのですが、どうやらキーワード検索が出来ていないようです。
もし、解決方法など詳しい方がいらっしゃいましたら、コメントいただければ幸いです。


#サンプルコード

最後に、今回作成したサンプルプログラムの全文を記載しておきます。

<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 type="text/javascript" src="https://www.youtube.com/iframe_api"></script>
<script>
//------------------------------------------------------------------------------------------------------------------------
//起動時処理
window.onload = function () {
	var SimpleAI = new denaripamSimpleAI(
		this,
		{},
		{
			initCamera:true,
			initMicrophone:true,
			VoiceRecognition:{listen:true},

//-----uriBase、APIキーを設定してください START-----
			MicrosoftAzureFaceAPI:true,
			MicrosoftAzureFaceAPIuriBase:"",											//FaceAPIのエンドポイントを入力
			MicrosoftAzureFaceAPIsubscriptionKey:"",									//FaceAPIのキー②を入力
			MicrosoftAzureFaceAPIparams:{
				"returnFaceAttributes": "gender,age,glasses,facialHair,makeup",			//取得したい情報をここで指定する
			},

			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-----
		},
	);
//-----------------------------------------------
	//情報表示用
	var msg="";
	//現在日時のタイマー起動
	setInterval('showClock()',1000);

	if(SimpleAI) {
		//スマートエージェント開始
		SimpleAI.SmartAgent();

		//AIの応答の言葉を変更する
		SimpleAI.param.SmartAgent.Prompt = "かしこまりました、";
		//AIの語尾の言葉を変更する
		SimpleAI.param.SmartAgent.PromptEnd = "、ご主人様";

		//人物判断（スマートエージェントコマンド追加サンプル）
		var cmd;
		cmd=SimpleAI.getSmartAgentCommand();
		cmd.MainCommand.push(
			{
				//人物判断の音声キーを追加する
				label: "PersonalJudgment",
				labelname: "人物判断",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/メイク|make|化粧|けしょう|仕上げ/,/check|確認|判断|判定|見て/],
				message:"しばらくお待ちください",
//				word:[/人物/,/判断/],
//				message:"人物判断を行います",
				messageafter:function(sender,event,param) {
					SimpleAI.Personinformation(		//人物判断処理
						{
							done:function(data) {
								msg = "";
								var output=document.getElementById("denaripamSimpleAI_responseTextArea");
								if(output) {
									var responsedata = JSON.parse(output.value);
									//判断結果を画面表示用に編集する
									if(responsedata[0]) {
										if(responsedata[0].faceAttributes.gender){
											if(responsedata[0].faceAttributes.gender=='female'){
												msg = msg + "性別：女性" + '<br>';
											} else {
												msg = msg + "性別：男性" + '<br>';
											}
										}
										if(responsedata[0].faceAttributes.age){
											msg = msg + "年齢：" + responsedata[0].faceAttributes.age + '<br>';
										}
										if(responsedata[0].faceAttributes.glasses){
											if(responsedata[0].faceAttributes.glasses=='NoGlasses'){
												msg = msg + "眼鏡：なし" + '<br>';
											} else {
												msg = msg + "眼鏡：あり" + '<br>';
											}
										}
										if(responsedata[0].faceAttributes.makeup.eyeMakeup){
											msg = msg + "アイメイク：あり" + '<br>';
										} else {
											msg = msg + "アイメイク：なし" + '<br>';
										}
										if(responsedata[0].faceAttributes.makeup.lipMakeup){
											msg = msg + "リップメイク：あり" + '<br>';
										} else {
											msg = msg + "リップメイク：なし" + '<br>';
										}
										document.getElementById("dispMsg").innerHTML = msg;
									} else {
										msg = "認識できませんでした。明るい所で鏡に映るようにして下さい。";
									}
								} else {
									msg = "認識できませんでした。明るい所で鏡に映るようにして下さい。";
								}
								document.getElementById("dispMsg").innerHTML = msg;
							},
							fail:function(errstring) {
								msg = "APIサービスが無効です。";
								document.getElementById("dispMsg").innerHTML = msg;
								//alert("NG!!" + errstring);
							},
						},
					);
				},
			},
			//音楽をかける音声キーを追加する
			{
				label: "PlayMusics",
				labelname: "音楽をかける",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/音楽|mugic|曲/,/かける|かけて|流す|流して|きく|きかせて｜ききたい/],
				message:"こちらの曲をどうぞ",
				messageafter:function(sender,event,param) {
					document.getElementById("dispYTPlayer").innerHTML = html_temp_modal;
					YouTubeplayer_start("やる気の出る クラシック音楽 ピアノBGM");
				},
			},
			//音楽を止める音声キーを追加する
			{
				label: "StopMusics",
				labelname: "音楽を止める",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/音楽|mugic|曲/,/止める|止めて|やめる|やめて|終わり|終了/],
				messageafter:function(sender,event,param) {
					YouTubeplayer_stop();
				},
			},
			//朝のニュースを呼び出す音声キーを追加する
			{
				label: "ShowNews",
				labelname: "ニュース表示",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/ニュース/,/見る|見せて|見たい|流す|流して/],
				message:"どうぞ",
				messageafter:function(sender,event,param) {
					document.getElementById("dispYTPlayer").innerHTML = html_temp_modal;
					var date = new Date();
					YouTubeplayer_start("nhk 朝のニュース");
					//前ゼロなし日付だと予想と異なるものが表示される。前ゼロ付きスラッシュ日付だと、うまく再生できなくなる。
					//YouTubeplayer_start("nhk ニュース " + formatYMD(date));
				},
			},
			//朝のニュースを止める音声キーを追加する
			{
				label: "StopNews",
				labelname: "ニュース停止",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/ニュース/,/止める|止めて|やめる|やめて|終わり|終了/],
				messageafter:function(sender,event,param) {
					YouTubeplayer_stop();
				},
			},
			//天気予報を呼び出す音声キーを追加する
			{
				label: "ShowWeatherForecast",
				labelname: "天気予報表示",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/天気/,/教えて|見る|見せて|見たい/],
				message:"どうぞ",
				messageafter:function(sender,event,param) {
					document.getElementById("dispYTPlayer").innerHTML = html_temp_modal;
					var date = new Date();
					YouTubeplayer_start("全国の天気予報 朝");
				},
			},
			//天気予報を止める音声キーを追加する
			{
				label: "StopWeatherForecast",
				labelname: "天気予報停止",				//ラベル名称、現在のモード読み上げ等に使用
				word:[/天気/,/止める|止めて|やめる|やめて|終わり|終了/],
				messageafter:function(sender,event,param) {
					YouTubeplayer_stop();
				},
			},
		);
	}
//--------------------------------------------
};
//--------------------------------------------
//現在日時表示
function showClock(){
	var now = new Date();
	document.getElementById("dispClock").innerHTML = now.toLocaleString();
}
//--------------------------------------------
//youtube
var YouTubeplayer;
var YouTubeIframeAPI=false;
 function onYouTubeIframeAPIReady() {
	YouTubeIframeAPI=true;
}
//youtube表示ウィンドウ
var html_temp_modal = 
	 '<!-- YoutubePlayer -->'
	+'<div class="embed-responsive embed-responsive-16by9">'
	+'	<div class="embed-responsive-item" id="player"></div>'
	+'</div>';
//youtube起動
var YouTubeplayer_start=function(keyword,volume) {
	if(YouTubeIframeAPI) {
		YouTubeplayer_stop();
		YouTubeplayer = new YT.Player('player', {
			height: '150',
			width: '200',
			controls: 2,		//コントロールの表示
			iv_load_policy: 3,	//アノテーション非表示
			showinfo: 0,		//インフォメーション非表示
			events: {
				onReady: function(event){
					if(keyword) YouTubeplayer.loadPlaylist({listType:"search",list:keyword,});
					if(volume)  YouTubeplayer.setVolume(100);
				},
			},
		});
	}
};
//youtube停止
var YouTubeplayer_stop=function() {
	if(YouTubeplayer)YouTubeplayer.destroy();
};
//--------------------------------------------
//前ゼロ付き日付変換
function formatYMD(date){
	if (date){
		var yyyy = date.getFullYear();
		var mm = ("0"+ (date.getMonth()+1) ).slice(-2);	// 前ゼロ付き2桁
		var dd = ("0"+date.getDate()).slice(-2);		// 前ゼロ付き2桁
		return yyyy + '年' + mm + '月' + dd + "日";
	}
};
//------------------------------------------------------------------------------------------------------------------------
</script>
<style>/** CSS：Area */
/* 鏡フレーム */
.img-over-top {
	position: absolute;
	z-index: 1;
}
/* 鏡本体 */
.video-wrap {
  position: relative;

}
/* 時計表示部 */
.clock-over-top {
	background: #cbb994;
	color: #eaf4fc;
	font-family: serif;
	font-size: 100%;
	position: absolute;
	left: 2%;
	top: 2%;
	z-index: 1;
	padding-left: 5px; padding-right: 5px;
}
/* 情報表示部 */
.msg-over-top {
	background: #cbb994;
	color: #eaf4fc;
	font-family: serif;
	font-size: 80%;
	position: absolute;
	left: 2%;
	top: 7%;
	z-index: 1;
	padding-left: 5px; padding-right: 5px;
}
/* YoutubePlayer表示部 */
.youtube-over-top {
	opacity: 0.5;	/* 対象の透過度(0:完全透明 1:不透明) */
	position: absolute;
	left: 580px;
	top: 2%;
	z-index: 1;
	padding-left: 5px; padding-right: 5px;
}
</style>
</head>
<body>
<img class="img-over-top" src="fl_001.png" width="800px" height="600px">
<p class="clock-over-top" id="dispClock"><script>showClock();</script></p>
<p class="msg-over-top" id="dispMsg"></p>
<p class="youtube-over-top" id="dispYTPlayer"></p>
<div class="video-wrap">
  <video id="denaripamControlSensor_video" width="800px" height="600px" controls autoplay>
  </video>
</div>
<div hidden id="denaripamSimpleAI_responseRect"></div><br>
<textarea hidden id="denaripamSimpleAI_responseTextArea" class="UIInput" style="width:580px; height:400px;"></textarea><br>
</body>
</html>
```

</div></details>

#最後に

今回はここまでです。お疲れ様でした。

数回に分けて掲載してきた「AI連携FW『シンプルエーアイ』を使ってみた」、如何でしたか？
まだ前書きの冒頭で書いた機能が残っているのですが、『シンプルエーアイ』に関する大まかな機能や使い方はご紹介できましたので、これで一区切りとさせていただきます。

また日を改めて、新しい記事を投稿することもあるやもしれません。その際はお付き合いいただければ幸いです。
記事をご覧下さった皆さま、また記事に関してご指摘下さった方々、有難うございました。