もうええでしょ…😎アプリ作りにコード、書かくなくても！小学生と #書かないGAS

本記事は、[こそだて×生成AI (byこそぷろ👶) Advent Calendar 2024](https://qiita.com/advent-calendar/2024/kosopro2024)の15日目記事です🎄🎅

https://qiita.com/advent-calendar/2024/kosopro2024

昨日の記事は[yuzinet](https://x.com/whi_tanji_y)さん!

https://qiita.com/yuzinet/items/c84ca191dcc984ed072a

こんにちは！4歳と9歳のパパをしている[おきなか](https://twitter.com/okinakamasayos1)です！
生成AIが幅を利かせて久しいので、子どもたちとの「工作」にも活用しよう！ということで、冬休みの宿題がてら、娘と一緒にアプリを作ってみます💻

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/52ba1a1f-a99c-e847-849c-e6e1c381970a.png)

ノーコードだと種類が限られるし、コードも書けない…but**もうええんです！コード書けなくても、生成AI使えばアプリを簡単に作れちゃいます**から、Let's Try!!

## 1年間で500冊本を読むよ！

と、本が大好きな長女📚、そこで**本の表紙を送ると、AIがタイトルを自動抽出して記録し、感想も保存できるLINE Bot＆アプリ**を作りました🤗
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/a7fadacb-fccf-61c8-51c5-513543673deb.png)

- 読んだ本の写真をLINEで送ると画像からAIがタイトル抽出
- 「どこが面白かったかな？」に返信すると、感想として記録
- タイトル/読了日/感想/写真を自動保存
- 保存されたデータが自動でWEBアプリ化されて、家族みんなで確認可能

## 成長の轍

 **青春は短い 宝石の如くにしてそれを惜しめ**

 という言葉の通り、子どもの成長速度には驚くばかり。
 **昨日娘が読んでいる本**をちらっと見てめちゃくちゃ**びっくり( ﾟДﾟ)**
 **空想科学読本…** つい最近まで、**絵本しか読んでいなかったのに…**
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/cf6c45b2-cf47-ad43-76cf-7d4ba8621b53.png)

   <font color="Red">**読む本の軌跡は、本好き娘の成長の轍。**</font>
 **アプリ化して家族みんなで振り返れるようにしていきます📚👀**

 ちょっと前までは絵本しか読んでいなかったのに…(写真は次女)
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/2828aab9-3b88-e820-d059-f5fb396eb16e.png)


 ## 生成AI×コーディング の可能性

  私はエンジニアではないので、娘と一緒にアプリを作るとなると、当然ノーコード。
  それはそれで楽しいのですが、どうしてもノーコードツールの中で出来ることからアプリの機能を選択せざるを得ない。

が、時は生成AI当たり前時代。**『コードが書ける人は自由にアイデアを膨らませていいなぁ……』** というノーコーダーの羨望を、を**生成AIがさらりと解決**してくれます。

 コードが書けないけど、生成AIでコーディング完結させちゃおうぜ、という面白いコミュニティもあります🤗

 https://kakanaigas.connpass.com/

 :::note warn
 GASを使ったLINEアプリを作りたい
 本の写真からタイトルを自動入力、感想も入力出来て、データベースにしたい
:::

たった2行のプロンプトで、コードも手順もサクサク教えてくれます👍

〇〇の機能が欲しい、〇〇はいらいない！と、**娘と、そして生成AIと会話しながら、よりいいアプリに仕上げて**いきます！ノーコードではこのあたりが難しいですよね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/130ae00a-87d9-6c70-896a-62e941d58283.png)
みんなで「もっと〇〇にしようよ！」会話しながら機能実装。すごい時代だ。

## 構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/5fd642e6-c2e9-8ccb-0fc0-e366dbbbca2b.png)

「Google Cloud Vision API」を使って、**手入力しなくても本のタイトルを抽出・記録**できるようにしたところがこだわりです👓

https://sight-r.sts-inc.co.jp/google_cloud_article/vision-api-object-localization/

「Glide」というノーコードツールでスプレッドシートをWEBアプリ化、**家族みんな(URLを知っている人は誰でも)が、長女が読んだ本と、一言感想文を確認できる**ようになりました😍

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/54e4e1f4-6292-a1c3-659e-5b74905c0f48.png)

https://www.worklog-inc.com/about-glide-app-2/

## デモアプリ 雰囲気だけでも📚
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/a0913899-c97c-10a7-7d98-ff093650a38c.png)

https://s-google-sheets-app-aqdo.glide.page

## GASのコードや注意点など

　<details><summary>GASのコードはこちら **(クリックで表示)** </font></summary><div><br>

 ```js
 // 必要なトークンや設定
const LINE_ACCESS_TOKEN = '取得して入力'; // LINEアクセストークン
const SHEET_ID = '取得して入力'; // スプレッドシートID
const VISION_API_KEY = '取得して入力'; // Google Vision APIキー

/**
 * LINEからのWebhookを処理
 */
function doPost(e) {
  const json = JSON.parse(e.postData.contents);
  const events = json.events;

  events.forEach(event => {
    if (event.type === 'message' && event.message.type === 'image') {
      const replyToken = event.replyToken;
      const imageId = event.message.id;

      // LINEから画像を取得
      const imageBlob = getLineImage(imageId);

      // Googleドライブに画像を保存し、URLを取得
      const imageUrl = saveImageToDrive(imageBlob, imageId);

      // Vision APIで画像から文字を抽出
      const extractedText = analyzeImageWithVisionAPI(imageBlob);

      // Googleスプレッドシートに保存
      saveToSheet(extractedText, '', imageUrl);

      // ユーザーに返信
      replyToLine(replyToken, `読んだ本を記録したよ！\n: ${extractedText}\n\nどんなところが面白かった？`);
    } else if (event.type === 'message' && event.message.type === 'text') {
      const userMessage = event.message.text;

      // 最新の記録に感想を追加
      addCommentToLatestEntry(userMessage);

      // 感想追加の完了を通知
      replyToLine(event.replyToken, '読んだ思い出も記録したよ！ \n GlideのURL入力');
    }
  });

  return ContentService.createTextOutput('OK');
}

/**
 * LINEで送信された画像を取得
 */
function getLineImage(messageId) {
  const url = `https://api-data.line.me/v2/bot/message/${messageId}/content`;
  const options = {
    headers: { 'Authorization': `Bearer ${LINE_ACCESS_TOKEN}` },
    method: 'get'
  };
  return UrlFetchApp.fetch(url, options).getBlob();
}

/**
 * Googleドライブに画像を保存し、URLを取得
 */
function saveImageToDrive(imageBlob, imageId) {
  const folder = DriveApp.getFolderById('取得して入力'); // 保存先フォルダのIDを指定
  const fileName = `line_image_${imageId}.jpg`;
  const file = folder.createFile(imageBlob.setName(fileName));
  return file.getUrl(); // ファイルの公開URLを取得
}

/**
 * Vision APIで画像から文字を抽出
 */
function analyzeImageWithVisionAPI(imageBlob) {
  const url = `https://vision.googleapis.com/v1/images:annotate?key=${VISION_API_KEY}`;
  const payload = {
    requests: [{
      image: { content: Utilities.base64Encode(imageBlob.getBytes()) },
      features: [{ type: 'TEXT_DETECTION' }]
    }]
  };
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload)
  };
  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());
  return json.responses[0].fullTextAnnotation?.text || '文字が検出されませんでした';
}

/**
 * Googleスプレッドシートの上部にデータを追加
 */
function saveToSheet(title, comment, imageUrl) {
  const sheet = SpreadsheetApp.openById(SHEET_ID).getSheets()[0];
  const date = getFormattedDate(); // フォーマット済みの日付を取得

  // 新しいデータを配列にまとめる
  const newRow = [title, comment, imageUrl, date];

  // 既存データを1行下にずらして新しいデータを上部に挿入
  sheet.insertRowBefore(2); // 1行目はヘッダー行として仮定
  sheet.getRange(2, 1, 1, newRow.length).setValues([newRow]);
}

/**
 * 最新の記録に感想を追加
 */
function addCommentToLatestEntry(comment) {
  const sheet = SpreadsheetApp.openById(SHEET_ID).getSheets()[0];
  const latestRow = 2; // 最新データは常に2行目
  const currentComment = sheet.getRange(latestRow, 2).getValue(); // 現在の感想を取得
  const updatedComment = currentComment ? `${currentComment}\n${comment}` : comment; // 既存感想に追加
  sheet.getRange(latestRow, 2).setValue(updatedComment); // 2列目（感想列）を更新
}

/**
 * 日付を「YYYY-MM-DD」の形式で取得
 */
function getFormattedDate() {
  const date = new Date();
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0'); // 月を2桁に
  const day = String(date.getDate()).padStart(2, '0'); // 日を2桁に
  return `${year}-${month}-${day}`; // フォーマット済みの日付を返す
}

/**
 * LINEに返信
 */
function replyToLine(replyToken, message) {
  const url = 'https://api.line.me/v2/bot/message/reply';
  const headers = {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${LINE_ACCESS_TOKEN}`
  };
  const payload = {
    replyToken: replyToken,
    messages: [{ type: 'text', text: message }]
  };
  UrlFetchApp.fetch(url, { method: 'post', headers: headers, payload: JSON.stringify(payload) });
}
```
</div></details>

　<details><summary>注意点①：Vision APIの設定手順 **(クリックで表示)** </font></summary><div><br>
- Google Cloud Platformでプロジェクトを作成
Google Cloud Consoleにアクセスします。
プロジェクトを新規作成します（任意の名前をつけてください）。
- Vision APIを有効化
プロジェクトを選択した状態で、左のメニューから「APIとサービス」 > 「ライブラリ」を選択。
検索バーで「Vision API」と入力し、「Cloud Vision API」をクリック。
「有効にする」をクリック。
- サービスアカウントキーの作成
左メニューから「APIとサービス」 > 「認証情報」を選択。
「認証情報を作成」 > 「サービスアカウント」を選択。
サービスアカウント名を入力し、続行。
「キーを作成」を選択し、JSON形式でダウンロード。
このJSONファイルは、GASプロジェクトにアップロードして使用します。
- GASプロジェクトでVision APIキーを使用
ダウンロードしたJSONファイルをGASプロジェクトにアップロードします。
VISION_API_KEYにキーを入力するか、JSONファイルをプログラムで読み込む設定を行います。
 </div></details>

 　<details><summary>注意点②:サービスアカウントキーの作成方法 **(クリックで表示)** </font></summary><div><br>
- Google Cloud Consoleを開く
Google Cloud Console にログイン。
プロジェクトを選択してください。
- サービスアカウントの画面を開く
左上にある 3本線（ハンバーガーメニュー） をクリック。
メニューから「IAMと管理」 > 「サービス アカウント」を選択。
- サービスアカウントを作成
画面右上の青いボタン 「＋サービス アカウントを作成」 をクリック。
以下を入力します：
サービスアカウント名: 任意の名前（例: vision-api-user）。
サービスアカウントID: 自動で入力されます。
説明: 必要なら説明を入力（例: Vision API用）。
「作成して続行」 をクリック。
- サービスアカウントにロールを付与
「ロールを選択」 をクリック。
ドロップダウンから「プロジェクト」を選択。
サブメニューから「オーナー」または「Cloud Vision API ユーザー」を選択。
「続行」 をクリック。
- キーを作成する
サービスアカウントの一覧画面に戻ります。
目的のサービスアカウントの右側にある 「オプションメニュー（縦3点のアイコン）」 をクリック。
「キーを管理」 をクリック。
「キーを追加」 ボタンをクリックし、「新しいキーを作成」 を選択。
JSON形式 を選び、キーを生成。
JSONファイルが自動的にダウンロードされます。
 </div></details>

  　<details><summary>注意点③:APIキー取得方法 **(クリックで表示)** </font></summary><div><br>
Google Cloud Console にログイン。
左上の「3本線メニュー」から「APIとサービス > 認証情報」を選択。
「認証情報」画面で、画面上部の「＋ 認証情報を作成」をクリック。
「APIキー」を選択。
生成されたAPIキーが表示されます。このキーをコピーして利用します。
    </div></details>

分からなくても全然OK。悩む前に生成AIに「このやり方を初心者用に懇切丁寧に教えて」って聞きましょう。筆者も意味は全く分かっていません。それでええねん。

**生成AIの心の広さと可能性は無限大∞**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/13fdda1a-6b76-0098-3981-dd78f2b4630e.png)

## 「できるのかな…」なんて言う前に…創って使ってまた創って

が生成AI時代の合言葉✨

**子どもたちの頭の中にあるキラキラを、パパママと一緒に形に**していきましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/7c7d0c1e-668b-a610-e252-70c2300ba0d4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793443/afa5afa2-65b0-66bf-c30d-12b54d3967c2.png)


明日は[CHIZU](https://qiita.com/chizukonakajima321)さん！お楽しみに！**こそぷろわいわい☺**

https://qiita.com/advent-calendar/2024/kosopro2024