【野球好き必見】Teachable Machineを使ってあなたの球団顔の球場飯を紹介します！

野球好きが高じて、自分がどの球団顔か知りたくなりました！
気になりません？？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/245488e9-7336-8cc6-bc59-99f1eedfa59b.png)


## セリーグの選手・監督の顔をTeachable Machineに学習させる

セリーグだけですが、Teachable Machineに監督、コーチ、選手の顔を学習させました！

これにより自分がどの球団顔かを表示するとこに成功！！

ちなヤクの私はヤクルト顔がよかったのですが、阪神だったり横浜ベイスターズだったりヤクルト要素は残念ながら0%でした。


## Difyでチャレンジ

前回はDifyを使って球団飯を表示させるのを作ったら全員カレーになってしくじった記事はコチラです。

https://qiita.com/n0rimaki_san/items/2b2b3452d2e7645b5fc1

球団飯と生成AIの相性よくないらしおので、あらかじめ球団飯のデータをExcelにまとめたものを呼び出す仕組みにしました。

そうなると、DifyよりもExcel読み込めるmiiboがよさげです！

## miiboで球団飯bot作ってみた

ナレッジは10個まで使えます。
はじめにヤクルトの球場飯でテストして、セリーグ6球団のメイン飯を登録したExcelをアップロード！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/fe98e0e8-016e-ca57-bc7f-4bedc98afd1b.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/1353dfc4-1111-a35e-0cb4-acbc804a6320.png)

ちゃんと表示されます！
やっぱりちゃんと、生成したデータ入れると安心感が違いますね！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3784193/df6bb887-1727-57f1-3e53-8061e1c4adce.png)

今回はmiiboで作成したデータとTeachable Machineで表示した球団名を紐づけて、あなたの球団の球場飯を出したいと思います！

## APIの活用

まずはCodepenでmiiboのAPIを使って表示させます！

表示できたら、Teachable MachineをCodepenで使えるように整えます。

このあたりはChat GPTに手伝ってもらいました。

２つのソースをChat GPTに読み込ませ、連携！！

## 完成？

なんとなく出来てるんやけど、なんか違う。
Codepenのコンソールに出てる情報も出すようにしてるけど、変なタグ入ってしまってますね。

CodepenのConsoleのタグ全部表示されてしまいました。
こまった。こまった。


表示したいのはbestResponse のテキストだけ。
bestResponse のテキストだけ表示できるようにChatGPTにがんばってもらいました。

## 完成！！

https://x.com/n0rimaki_san/status/1819018074546491828



<details open><summary>javascriptのソースはこんな感じです。</summary>

```js
    const URL = "https://teachablemachine.withgoogle.com/models/2LE898Bvs/";

    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; // whether to flip the webcam
        webcam = new tmImage.Webcam(200, 200, flip); // width, height, flip
        await webcam.setup(); // request access to the webcam
        await webcam.play();
        window.requestAnimationFrame(updateWebcam);

        document.getElementById("webcam-container").appendChild(webcam.canvas);
        labelContainer = document.getElementById("label-container");
        labelContainer.innerHTML = ""; // Clear previous label container
    }

    async function updateWebcam() {
        webcam.update();
        window.requestAnimationFrame(updateWebcam);
    }

    async function predict() {
        const prediction = await model.predict(webcam.canvas);
        // Find the prediction with the highest probability
        let highestPrediction = prediction[0];
        for (let i = 1; i < maxPredictions; i++) {
            if (prediction[i].probability > highestPrediction.probability) {
                highestPrediction = prediction[i];
            }
        }
        // Display the highest prediction's className only
        labelContainer.innerHTML = highestPrediction.className;

        // Set the predicted className to the input field
        document.getElementById('text').value = highestPrediction.className;
    }

    // Initialize webcam and model on page load
    window.onload = init;

    document.addEventListener('DOMContentLoaded', () => {
      const button = document.getElementById('button');

      button.addEventListener('click', async () => {
        const textContent = document.getElementById('text').value;

        const apiKey = "**********************";
        const agentId = "**********************";
        const utterance = `${textContent}のご飯`;
        const uid = "**********************";

        const requestData = {
          api_key: apiKey,
          agent_id: agentId,
          utterance: utterance,
          uid: uid
        };

        async function postData() {
          try {
            const response = await fetch('https://api-mebo.dev/api', {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json'
              },
              body: JSON.stringify(requestData)
            });

            if (!response.ok) {
              throw new Error('Network response was not ok');
            }

            const data = await response.json();
            // Display the bestResponse.utterance text in the result-container div
            document.getElementById('result-container').innerText = data.bestResponse.utterance;
          } catch (error) {
            console.error('Error:', error);
            document.getElementById('result-container').innerText = 'Error: ' + error.message;
          }
        }

        postData();
      });
    });
  ```
</details>


## 遊んでみてください！

https://n0rimaki.net/baseball_meal.html

スマホでは動作しません。
誰かスマホ特にiPhoneで動作する方法を教えてください！！

パソコンで遊んでもらって、コメントにどの球団顔だったか教えてもらえるとうれしいです！

ちなヤクのりまきでした！