#娘も私も絵本の読み聞かせは毎日欠かせない
もうすぐ2歳になる娘は絵本を読んでもらうことが好きで、寝る前に必ず自分で選んだ絵本を持ってくる。仕事で娘に会えない日も、自分の声で読み聞かせてあげることができれば、明日も私を指名して絵本を持ってきてくれるかもしれない。娘のお気に入りの絵本を機械学習が判断し、読み聞かせの音声を再生するWebアプリケーションを作った。
家にいない日も、娘に自分の声で読み聞かせできるようにした。#protoout #機械学習 #絵本読み聞かせ pic.twitter.com/RHQl2OvDRS
— 3do. (@3doHi) November 8, 2020
娘が使う目的なので、画面はできるだけシンプルにして、カメラに絵本をかざせば、すぐに読み聞かせが開始されるようにした。↓が実際の画面。
また、娘が使ってくれたことに気づけるように、LINE Notifyで通知する機能も追加した。(※「あ、今日も読んでくれたんだー」と仕事帰りの電車でニヤニヤするための自己満足)
#構成
1.Teachable Machineを使い、娘のお気に入りの絵本を学習させ、モデルの埋め込み用リンクを発行する。
2.学習モデルを、ml5を使って読み込み、フロントエンドで動くようにする。
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
// 作成したモデルのURL
const imageModelURL = 'https://teachablemachine.withgoogle.com/models/XXXXX/';
// 自作モデルのロード
classifier = ml5.imageClassifier(imageModelURL + 'model.json', video, () => {
// ロード完了
console.log('Model Loaded!');
});
3.収録した読み聞かせ音源が、学習モデルの判断結果によって再生されるように実装する。
<audio id="sound-file1" preload="auto">
<source src="https://dotup.org/uploda/dotup.org2302152.mp3" type="audio/mp3" controls>
</audio>
function storytelling1(){
//音声ファイルを再生する
document.getElementById('sound-file1').play();
//Webhookにアクセス
sendWebhook('「Do you want a Hug?」を読んだよ');
}
4.axiosを使い、音源が再生された際にIntegromatのWebhookURLにアクセスされるようにする。
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
// 引数に送りたいメッセージを入れる
async function sendWebhook(message) {
// Integromatに送る
try {
// 取得したIntegromatのWebhookURL
const res = await axios.get(`https://hook.integromat.com/XXXXXXXXXXXXXXXXXXXXXXXXXX?message=${message}`);
console.log(res.data);
} catch (err) {
console.error(err);
}
}
5.Integromatを使ってWebhookURLとLINE Notificationを連携し、「読み聞かせ」が行われたことを通知する。
#ソース
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Storytelling</title>
</head>
<body>
<h1>Storytelling</h1>
<div id="console_log"></div>
<video id="myvideo" width="640" height="480" muted autoplay playsinline></video>
<audio id="sound-file1" preload="auto">
<source src="https://dotup.org/uploda/dotup.org2302152.mp3" type="audio/mp3" controls>
</audio>
<audio id="sound-file2" preload="auto">
<source src="https://dotup.org/uploda/dotup.org2302153.mp3" type="audio/mp3" controls>
</audio>
<audio id="sound-file3" preload="auto">
<source src="https://dotup.org/uploda/dotup.org2302151.mp3" type="audio/mp3" controls>
</audio>
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// 作成したモデルのURL
const imageModelURL = 'https://teachablemachine.withgoogle.com/models/XXXXXXX/';
console.log = function (log) {
document.getElementById('console_log').innerHTML = log;
}
async function main() {
// カメラからの映像取得
const stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: true,
});
// IDが"myvideo"であるDOMを取得
const video = document.getElementById('myvideo');
// videoにカメラ映像をセット
video.srcObject = stream;
// 自作モデルのロード
classifier = ml5.imageClassifier(imageModelURL + 'model.json', video, () => {
// ロード完了
console.log('Model Loaded!');
});
// 分類処理を連続的に行う
function onDetect(err, results) {
if (results[0]) {
console.log(results[0].label);
//読み聞かせ音を出す
if (results[0].label === 'Do you want a Hug?') {
// storytelling 関数実行
storytelling1();
}
if (results[0].label === 'おつきさまこんばんは') {
storytelling2();
}
if (results[0].label === 'だるまさんと') {
storytelling3();
}
}
classifier.classify(onDetect);
}
classifier.classify(onDetect);
}
// 引数に送りたいメッセージを入れる
async function sendWebhook(message) {
// Integromatに送る
try {
// 取得したIntegromatのWebhookURL
const res = await axios.get(`https://hook.integromat.com/XXXXXXXXXXXXXXXXXXXXXXXXXX?message=${message}`);
console.log(res.data);
} catch (err) {
console.error(err);
}
}
function storytelling1(){
//音声ファイルを再生する
document.getElementById('sound-file1').play();
sendWebhook('「Do you want a Hug?」を読んだよ');
}
function storytelling2(){
//音声ファイルを再生する
document.getElementById('sound-file2').play();
sendWebhook('「おつきさまこんばんは」を読んだよ');
}
function storytelling3(){
//音声ファイルを再生する
document.getElementById('sound-file3').play();
sendWebhook('「だるまさんと」を読んだよ');
}
// 実行
main();
</script>
</body>
</html>
#機械学習入門として作ってみた感想
機械学習ってキーワードから入ると、勉強しなければならないことも多いと思うが、TeachableMachineなどを使えば簡単に学習モデルを作ることができた。また、ml5などのライブラリからモデルを「使う」ことも、そこまで難しくなくできる、という感覚も得られた。ただ、モデルのタイプによっては、色々と制約などもありそうなので、使いながら覚えていきたいと思った。
#おまけ
・絵本の各ページを撮影し、声を吹き込んだ動画を流す案も考えましたが、娘が絵本を読むのは、寝る前であることが多いので、明るい画面を見続けて眠れなくならないように、「音声」での読み聞かせを選びました。
・私にとって、絵本の読み聞かせは、娘と過ごす時間の中でもトップ3に入る好きな時間です。より良い時間にできるアイデアを、また何か考えてみたいものです。