出勤したらやること教えて、おねえさん!
こんにちは、業務効率化おねえさんを作成することに命をかける女、ゆいです。
突然ですが、人間は忘れる生き物です。
毎日同じことをしているはずなのにどうしても抜け漏れが発生します。
私は小売業で働く社員です。出勤した直後に何をすべきかを毎日洗い出してパートさんに指示を出していました。
ですが、だんだんルーティンタスクを抜かしてしまい、いつもであればできていたことを「うっかり」やり忘れてしまうことがたまに起きてしまうことがありました。
(「うっかり」報告書の提出を忘れたり、「うっかり」POPの外し忘れがおきたり…)
また、社員である私とパートさんでは取り組む業務に違いがあります。私と同じように動いてもらおうとしてもうまくいくわけがありません。
なので今回は、Teachable Machineを使って社員かパートかを判別し、各々に割り当てられたタスクを表示するというアプリを作成することにしました!
ただシンプルなアプリだと使いたいと思ってもらえないかもしれないので、かわいいおねえさんを表示して親しみをもってもらうことにしました。
(↑今回のおねえさん)
今回はほぼclaudeにやってもらいましたと一緒につくりました。
作成する物自体はほぼclaudeが作成してるので、今回は「どんな過程を辿ったか」を遺しておきます。
今回のおねえさんのなかみのご紹介
今回はTeachable Machineを使って、画面に映った人間の役職を判別し、役職に合わせたルーティンタスクをお知らせしてくれるアプリになります。
用意するものは以下です。
・Teachable MachineのモデルURL
・Teachable Machineが駆動するコードを内包したhtmlファイル
・表示したい画像
準備するのはこの3つです。
完成系はこんな感じ↑。
おねえさんを作る手順
●Teachable Machineのモデルをつくる
Teachable Machineにアクセスしてモデルを作っていきます。
今回は画像認識を学習してもらうので、画像プロジェクトを選びます。
今回は社員(チーフ)の画像パターンと、パートさんの画像パターンを学習させました。
(※なお、区分けの方法は着用している制服で判別しているのですが、今回制服でどこの企業か判別できてしまうので隠させていただきました。)
学習パターンはそれぞれ100枚ずつ撮影し、記録しています。
学習を終えたらモデルをエクスポートして、必ずURLをコピーしておくようにしましょう。
あとで使います。
●テキストエディタでコードをコピペする書く
おねえさんが動くようにHTML形式のコードを書いたファイルを用意します。
私はmacbookAirを使用しているので初期装備の「テキストエディット」で作成しました。
(WindowsであればメモでもOKです。拡張子が.htmlにできるものであればとにかくOKです。)
この真っ黒な画面にいよいよコードをコピペします書いていきます。
必要なものは生成AIのclaudeです。(chatGPTとかでもできると思いますが、今回はあんまりまだ使ってる人がQiitaにいなさそうだったclaudeを使用しました。)
がっちがちのプロンプトじゃなくてもそれっぽいのをまず作ってくれるので、まずは「どんなことをしたいのか」を相談してみるような使い方をしてみるのも良いと思います。
ほんとにこのプロンプトを入れただけで下記のような答えが出てきます。
はい、Teachable Machineを使って人間を認識し、その結果に基づいてTodoリストや連絡事項を表示するシステムを作ることは可能です。以下に、そのようなシステムを構築するための大まかな手順を説明します:
1. Teachable Machineで人間認識モデルを作成:
- Teachable Machineのウェブサイトで、画像プロジェクトを作成します。
- 「人間がいる」と「人間がいない」の2つのクラスを作り、それぞれに対応する画像をアップロードして学習させます。
- モデルをトレーニングし、エクスポートします。
2. ウェブアプリケーションの作成:
- HTML、CSS、JavaScriptを使用してウェブアプリケーションを作成します。
- カメラからの入力を取得し、Teachable Machineモデルで分析します。
- 人間が認識されたら、Todoリストや連絡事項を表示する機能を実装します。
このようなシステムの基本的な実装例を示しましょう。以下は、HTML、JavaScript、CSSを使用したシンプルな実装です:
```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>人間認識Todoシステム</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@latest/dist/teachablemachine-image.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.container {
text-align: center;
background-color: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
#webcam-container {
margin-bottom: 20px;
}
#todo-list {
text-align: left;
max-width: 300px;
margin: 0 auto;
}
</style>
</head>
<body>
<div class="container">
<h1>人間認識Todoシステム</h1>
<div id="webcam-container"></div>
<div id="todo-list" style="display:none;">
<h2>今日のTodo:</h2>
<ul>
<li>朝のミーティング (9:00)</li>
<li>プロジェクト提案書作成</li>
<li>顧客とのビデオ会議 (14:00)</li>
<li>週報の提出</li>
</ul>
<h2>連絡事項:</h2>
<p>明日は社内研修があります。9時に会議室Aに集合してください。</p>
</div>
<div id="label-container"></div>
</div>
<script>
const URL = "YOUR_TEACHABLE_MACHINE_MODEL_URL";
let model, webcam, labelContainer, maxPredictions;
async function init() {
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
model = await tmImage.load(modelURL, metadataURL);
maxPredictions = model.getTotalClasses();
const flip = true;
webcam = new tmImage.Webcam(200, 200, flip);
await webcam.setup();
await webcam.play();
window.requestAnimationFrame(loop);
document.getElementById("webcam-container").appendChild(webcam.canvas);
labelContainer = document.getElementById("label-container");
for (let i = 0; i < maxPredictions; i++) {
labelContainer.appendChild(document.createElement("div"));
}
}
async function loop() {
webcam.update();
await predict();
window.requestAnimationFrame(loop);
}
async function predict() {
const prediction = await model.predict(webcam.canvas);
for (let i = 0; i < maxPredictions; i++) {
const classPrediction =
prediction[i].className + ": " + prediction[i].probability.toFixed(2);
labelContainer.childNodes[i].innerHTML = classPrediction;
}
if (prediction[0].className === "人間がいる" && prediction[0].probability > 0.8) {
document.getElementById("todo-list").style.display = "block";
} else {
document.getElementById("todo-list").style.display = "none";
}
}
init();
</script>
</body>
</html>
感謝しながらコピーして、テキストエディットに貼り付けましょう。
●実装→点検→修正をくりかえす
この時点で「うっかり」おねえさんを表示するようにプロンプトを出すのを忘れていることに気づきました。
あらかた実装できているのを確認したらこれを基に肉付けをしていきます。
もう一度生成AIに聞いてみましょう。
<div id="app-container">
<h1>役職認識アシスタント</h1>
<img id="character-image" src="your_image.png" alt="アシスタントキャラクター" />
<button type="button" onclick="init()">開始</button>
<div id="webcam-container"></div>
<div id="dialogue-box">
<div id="dialogue-content">
こんにちは!私はあなたの役職認識アシスタントです。カメラを通して役職を認識し、ToDoリストをお知らせします。「開始」ボタンを押してください。
</div>
<div id="todo-list"></div>
</div>
</div>
const URL = "https://teachablemachine.withgoogle.com/models/1WEs92J8P/";
let model, webcam, maxPredictions;
let lastRecognizedRole = "";
let noPersonCounter = 0;
async function init() {
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
model = await tmImage.load(modelURL, metadataURL);
maxPredictions = model.getTotalClasses();
const flip = true;
webcam = new tmImage.Webcam(400, 400, flip);
await webcam.setup();
await webcam.play();
window.requestAnimationFrame(loop);
document.getElementById("webcam-container").appendChild(webcam.canvas);
document.getElementById("dialogue-content").innerText = "カメラの準備ができました。あなたの役職を認識しています...";
}
async function loop() {
webcam.update();
await predict();
window.requestAnimationFrame(loop);
}
async function predict() {
const prediction = await model.predict(webcam.canvas);
let maxProbability = 0;
let recognizedRole = "";
for (let i = 0; i < maxPredictions; i++) {
if (prediction[i].probability > maxProbability) {
maxProbability = prediction[i].probability;
recognizedRole = prediction[i].className;
}
}
if (maxProbability > 0.8) {
noPersonCounter = 0;
if (recognizedRole !== lastRecognizedRole) {
showTodoList(recognizedRole);
lastRecognizedRole = recognizedRole;
}
} else {
noPersonCounter++;
if (noPersonCounter > 30) {
document.getElementById("dialogue-content").innerText = "誰もいないようですね。戻ってきたらまたお知らせします!";
document.getElementById("todo-list").innerHTML = "";
lastRecognizedRole = "";
}
}
}
function showTodoList(role) {
let todos;
let dialogue;
if (role === 'チーフ') {
dialogue = "チーフさん、お疲れ様です!今日のToDoリストをお知らせします:";
todos = ['スタッフのシフト確認', '広告商品の点検', '清掃、売り場点検', '在庫整理'];
} else if (role === 'パート') {
dialogue = "パートさん、こんにちは!今日のToDoリストはこちらです:";
todos = ['商品陳列補充', '発注点検', '清掃', '期限チェック'];
}
document.getElementById("dialogue-content").innerText = dialogue;
let todoHtml = "<ul>";
for (let todo of todos) {
todoHtml += `<li>${todo}</li>`;
}
todoHtml += "</ul>";
document.getElementById("todo-list").innerHTML = todoHtml;
}
コード3行目の
<img id="character-image" src="your_image.png" alt="アシスタントキャラクター" />
このyour_image.png
の部分が自分の使いたい画像を登録する部分です。名前は必ずファイルと同じ名前にしておいてください。
また、
const URL = "https://teachablemachine.withgoogle.com/models/1WEs92J8P/";
let model, webcam, maxPredictions;
のcountURLの部分には、先ほどメモしておいた自分の作ったTeachable MachineのURLを登録します。
おねえさんが相手を判別して仕事を指示してくれる!!
実際に動かしてみると、私を認識して今日の仕事を教えてくれました!
パートさんに実際に立ってもらってみると、ちゃんと認識してる様子!
最低限パートさんにやってもらいたいTodoも表示されてるので、抜け漏れ防止になりそうです!
(※制服で認識させてしまっているので隠さざるをえなくてこんな形になってしまいましたが本当に認識しています!)
今後のおねえさんのアプデ予定
実際パートさんに触ってもらってみて、出た案が以下です。
・従業員一人一人を認識させて、個別の指示を出せるようにしてほしい
→今は社員とパートの区分だが、ひとりひとりにあわせたタスク管理ができるといいかも!
・パソコンじゃなくてスマホでできるようにして欲しい
→モバイルアプリとして実装できるか試してみる?