5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

こそだて×生成AI (byこそぷろ👶)Advent Calendar 2024

Day 9

学校配布書類管理アプリ ミキティーが学校の配布書類の管理が困ってるって言ってたので・・夫が寝た後に好きな夫の挑戦①

Last updated at Posted at 2024-12-08

1 はじめに

私、50歳で初めて子供ができたじじパパ。プログラミング初心者ですが、プログラミングで子育てがもっと楽しくならないか模索中。

1-1 夫が寝た後にを見るのが好き

テレビでミキティーが、学校の配布書類の管理が大変!!って言ってたから、なんか管理が楽になるアプリ作れないかなと。

1-2 奥さんにAIを使って欲しい

AIつよつよ夫婦になって、今後のキャリア形成に活かせたらと思い、AI利用を奥さんに勧めるもなかなか上手く行きません(^^;;
なんかAIで便利になるものを実際に作れたら、もっと興味を持ってくれるのでは??と考えました。

詳細はこちらに記載

2 書類管理アプリ調査

AI検索ツール Feloで検索。1分で調べて表にしてくれた。すごい。
詳細:Felo 学校配布書類について教えて

アプリ名 主な機能 料金 対応デバイス 特徴
おたよりクリップ - プリント撮影・保存
- フォルダ分け
- OCR(文字認識)
- カレンダー連携
無料(広告非表示:160円) iOS, Android シンプルで使いやすい。OCR機能でプリント内容をテキスト化可能。
プリゼロ - プリント撮影・保存
- カレンダー連携
- 家族での共有
- タグ付け
無料(プレミアム:月額200円) iOS, Android カレンダー連携でスケジュール管理が簡単。家族全員で情報共有可能。
がくぷり - プリント配信
- アンケート集計
- 出欠連絡
- カレンダー連携
学校が導入費用を負担 iOS, Android, PC 学校全体での導入を前提としたペーパーレス化サービス。事務作業の効率化に最適。
Evernote - 書類保存
- OCR機能
- タグ付け
- デバイス間同期
無料(プレミアム:月額1,100円) iOS, Android, PC 汎用性が高く、学校プリント以外の書類管理にも活用可能。
Microsoft OneNote - 書類保存
- タグ付け
- デバイス間同期
無料 iOS, Android, PC Microsoft Lensと連携して高品質なスキャンが可能。整理機能が柔軟。
tetoru - 学校連絡配信
- 出欠連絡
- 保護者とのメッセージ機能
無料 iOS, Android 学校と保護者間の連絡を効率化するツール。小中学校向け。

正直、無料のアプリでも良さそうなのがあるな。でも自分で作ることに意味がある!はず。

3 記事の内容

学校からの配布書類を管理するアプリを作成したいのですが、難しいので以下記事のアプリ作成に挑戦しました。

• LINEとGASを連携させ、ユーザーのアップロードした画像を処理する方法
• GASを使って画像をDifyに送信する方法
• DifyでAIを活用し画像からデータを抽出し、Googleスプレッドシートに保存する方法

4 アプリの流れ (上記記事から引用)

4-1 利用イメージ

スマホで領収書を写メして、Lineから画像を送付すると、内容がGoogleのスプレッドシートに書き込まれ結果をLineで返してくれるというものです。

今後、学校配布書類管理に応用したいと思います。
配布書類をスマホ撮影
➡️Lineで画像送付
➡️自動で要約された文書と画像リンクが、Notionに保存
後で検索しやすくなれるようにしたいです

4-2 具体的な流れ

①ユーザーがLINEで領収書の写真をアップロード
②LINEからGASへwebhookが送信される
③GASがそのリクエストを受け取り、画像データをDifyに送信
④Difyを通してLLMにて画像を解析し、領収書の内容をJSON形式にする
⑤GASがそのJSONデータをGoogleスプレッドシートに保存し、画像もGoogleドライブに保存する
⑥GASが保存した内容をLINEに返す

スクリーンショット 2024-12-08 10.49.23.jpg

5 アプリ作成

5-1 ②LINEからGASへwebhookが送信される(GoogleDriveに画像保存)

webhookとは

Feloで検索


Webhookとは?

Webhookは、**「特定のイベントが起きたときに、他のサービスやアプリに自動で通知を送る仕組み」**です。これにより、異なるシステム間でリアルタイムな連携が可能になります。


Webhookの仕組み

  1. イベントの発生
    例: システムでデータが更新されたり、新しい情報が追加されたりする。

  2. 通知の送信
    Webhookは、指定されたURL(受信先)にHTTPリクエストを送信します。このリクエストには、イベントに関するデータが含まれています。

    HTTPリクエストとは?
    HTTPリクエストは、インターネットで情報を取得するための「お願い」のようなものです。例えば、あなたがウェブサイトを見たいとき、ブラウザ(インターネットを見るためのアプリ)がサーバー(情報を持っているコンピュータ)に「このページを見せて!」と頼むのがHTTPリクエストです。

  3. 受信先での処理
    通知を受け取ったサービスが、そのデータを使って次のアクションを実行します。


Webhookの例

  • チャット通知
    例: SlackやMicrosoft Teamsに新しいメッセージを自動投稿。

  • Eメール送信
    例: フォームに入力があった際に、管理者へメール通知。

  • データ連携
    例: kintoneでデータが更新されたら、別のシステムにその情報を送信。


Webhookのメリット

  • リアルタイム性
    イベントが発生した瞬間に通知が送られる。

  • 自動化
    手動で確認する必要がなく、効率的。

  • 柔軟な連携
    異なるサービス間で簡単にデータをやり取りできる。


Webhookの注意点

  • 受信先の設定
    Webhookを受け取るサービスが正しく設定されている必要があります。

  • セキュリティ
    不正なリクエストを防ぐために、認証や署名の仕組みを導入することが推奨されます。


Webhookのイメージ

Webhookは、シーソーのように「片方で何かが起きたら、もう片方に通知が飛ぶ」仕組みと考えると分かりやすいです。


このようにWebhookは、システム間の連携をスムーズにし、効率的なワークフローを実現するための重要なツールです。
[1] https://dev.classmethod.jp/articles/teams-webhook-markdown-workflows/
[2] https://note.com/seika_usa/n/n9125e43e9f41
[3] https://github.com/pact-foundation/pact_broker/blob/master/lib/pact_broker/doc/views/webhooks.markdown
[4] https://fider.io/docs/using-webhooks
[5] https://zenn.dev/yukun369/articles/ac2150ec6ab9de
[6] https://devforum.zoom.us/t/incoming-webhook-markdown/27218
[7] https://api.slack.com/incoming-webhooks
[8] https://kintone-blog.cybozu.co.jp/developer/000283.html
[9] https://jamstack.jp/blog/netlifycms_to_microcms/
[10] https://help.zoho.com/portal/ja/kb/connect/developer-tools/webhooks/articles/%E5%8F%97%E4%BF%A1webhook%E3%81%AE%E9%AB%98%E5%BA%A6%E3%81%AA%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E5%BD%A2%E5%BC%8F
[11] https://help.zoho.com/portal/ja/kb/connect/developer-tools/webhooks/articles/%E5%8F%97%E4%BF%A1webhook%E3%81%AE%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E5%BD%A2%E5%BC%8F-15-11-2021
[12] https://stackoverflow.com/questions/66823432/ms-teams-webhook-with-markdown
[13] https://devforum.zoom.us/t/does-incoming-webhook-full-message-format-support-markdown/28685
[14] https://help.zoho.com/portal/en/kb/connect/developer-tools/webhooks/articles/advanced-message-formatting-in-incoming-webhooks
[15] https://qiita.com/ik-fib/items/b4a502d173a22b3947a0
[16] https://community.cisco.com/t5/adopting-webex/webex-teams-webhooks-and-markdown/m-p/4450152
[17] https://thoughtbot.com/blog/blog-in-markdown-deploy-with-webhooks
[18] https://birdie0.github.io/discord-webhooks-guide/other/discord_markdown.html
[19] https://blog.microcms.io/create_markdown_blog/
[20] https://blog.trainocate.co.jp/blog/output_nocode_022

コード解説 doPost関数

作成したLINE公式アカウントにメッセージ(画像)を送ると
指定したURL(このあと設定)にWebhookイベントオブジェクトを含む
HTTP POSTリクエストが送られてきます。
今回はPOSTリクエストを受け取るためにdoPost関数を使います。

以下cloudによる解説

1. doPost関数の定義部分

/**
 * LINE webhook からのリクエスト受け取り処理
 * @param {GoogleAppsScript.Events.DoPost} e
 * @return {GoogleAppsScript.Content.TextOutput} 
 */
function doPost(e) {
  • /** から始まるブロックは「JSDoc」と呼ばれるドキュメンテーションコメントです
  • このコメントは関数の説明を記述する特別な形式です
    • 1行目:この関数の概要説明
    • @param:関数が受け取る引数の説明
    • @return:関数が返す値の型の説明
  • function doPost(e)
    • Google Apps Script(GAS)の特別な関数名で、webhookのPOSTリクエストを受け取ります
    • eは「event」の略で、LINEから送られてくるデータ全体を含むオブジェクトです
    • この関数名は変更できません(GASの規約)

2. データ存在チェック

if (!e) {
  Logger.log('データがありません');
  return ContentService.createTextOutput('データがありません');
}
  • if (!e)
    • !は「否定」を表す演算子です
    • eが以下の場合にtrueとなります:
      • null
      • undefined
      • 空文字列
      • 0
      • false
  • Logger.log()
    • GASのログ機能です
    • 実行ログに「データがありません」と記録します
    • デバッグ時に役立ちます
  • ContentService.createTextOutput()
    • GASの応答を作成するサービス
    • プレーンテキストの応答を生成します
    • LINEサーバーに返すレスポンスとなります

3. JSONデータのパース

const json = JSON.parse(e.postData.contents);
  • const:再代入できない変数を宣言します
  • e.postData:POSTリクエストのデータを含むオブジェクト
  • e.postData.contents
    • リクエストの本文(JSON形式の文字列)
    • 例:
      {
        "events": [{
          "type": "message",
          "replyToken": "12345...",
          "message": {
            "type": "image",
            "id": "789..."
          }
        }]
      }
      
  • JSON.parse()
    • JSON形式の文字列をJavaScriptオブジェクトに変換
    • エラーが発生する可能性がある処理です(try-catchで囲むとより安全)

4. 必要なデータの取り出し

const replyToken = json.events[0].replyToken;
const message = json.events[0].message;
const messageType = message.type;
  • json.events[0]
    • eventsは配列で、複数のイベントを含む可能性があります
    • [0]で最初のイベントを取得
  • replyToken
    • LINEの応答に必要な一時的なトークン
    • 有効期限は約30分
    • このトークンを使って特定のメッセージに返信できます
  • message
    • 送られてきたメッセージの詳細情報を含むオブジェクト
    • 画像の場合:
      {
        "type": "image",
        "id": "画像ID",
        "contentProvider": {
          "type": "line"
        }
      }
      
  • messageType
    • メッセージの種類を示す文字列
    • 可能な値:
      • "text"(テキスト)
      • "image"(画像)
      • "video"(動画)
      • "audio"(音声)
      • "file"(ファイル)
      • "location"(位置情報)
      • "sticker"(スタンプ)

5. リプライトークンの確認

if (typeof replyToken === 'underfined') {
  return ContentService.createTextOutput('リプライトークンが見つかりません');
}
  • typeof:変数の型を調べる演算子
  • バグ修正:'underfined''undefined'が正しい
  • このチェックの目的:
    • replyTokenが存在しない場合のエラー処理
    • LINE APIの仕様上、一部のイベントではreplyTokenが含まれない

6. メッセージタイプの確認と応答

if (messageType !== 'image') {
  replyMessageToLine(replyToken, '画像を送ってください');
  return;
}
  • !==:厳密な不等価演算子
    • 値と型の両方を比較
    • !=より安全
  • 処理の流れ:
    1. メッセージが画像かチェック
    2. 画像でなければ「画像を送ってください」と返信
    3. returnで関数を終了

7. 画像受信確認の応答

replyMessageToLine(replyToken, '画像を受け取れました');
  • replyMessageToLine
    • 別途定義が必要な関数
    • LINE Messaging APIを使用して実際の返信を行う
    • 実装例:
      function replyMessageToLine(replyToken, text) {
        const url = 'https://api.line.me/v2/bot/message/reply';
        const headers = {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN
        };
        const postData = {
          'replyToken': replyToken,
          'messages': [{
            'type': 'text',
            'text': text
          }]
        };
        const options = {
          'method': 'post',
          'headers': headers,
          'payload': JSON.stringify(postData)
        };
        UrlFetchApp.fetch(url, options);
      }
      
コード解説 応答返却(replyMessageToLine関数)

このコードをより詳しく解説していきます。

1. 応答返却(replyMessageToLine)関数の定義部分

/**
 * LINEでリプライメッセージを投稿する
 * @param {string} replyToken リクエストに含まれていたリプライトークン
 * @param {string} messageText 送りたいメッセージ
 * @return {UrlFetchApp.HTTPResponse} リクエスト結果のHTTPレスポンス
 */
function replyMessageToLine(replyToken, messageText) {
  • JSDocによるドキュメント:
    • 1行目:関数の目的
    • @param:2つの引数の説明
      • replyToken:返信先を特定するための一時的なトークン
      • messageText:実際に送信するメッセージの内容
    • @return:返り値の型の説明
  • 引数:
    • replyToken:前のコードで受け取ったLINEからのトークン
    • messageText:送信したいメッセージの文字列

2. LINE APIのURL設定

const url = LINE_URL + '/reply';
  • LINE_URL
    • 別の場所で定義された定数(通常はhttps://api.line.me/v2/bot/message
    • LINEのMessaging APIのベースURL
  • /reply
    • メッセージ返信用のエンドポイント
    • 完成するURL:https://api.line.me/v2/bot/message/reply

3. リクエストオプションの設定

const options = {
  'headers': {
    'Content-Type': 'application/json; charset=UTF-8',
    'Authorization': 'Bearer ' + LINE_TOKEN,
  },
  'method': 'post',
  'payload': JSON.stringify({
    'replyToken': replyToken,
    'messages': [{
      'type': 'text',
      'text': messageText,
    }],
  }),
}
  • headers:HTTPヘッダー情報
    • Content-Type
      • データ形式がJSONであることを指定
      • 文字コードはUTF-8
    • Authorization
      • LINE APIの認証情報
      • Bearer:トークン認証方式を示す接頭辞
      • LINE_TOKEN:LINE Developersで取得したチャネルアクセストークン
  • method
    • HTTPメソッドの指定
    • post:データを送信するための標準的なメソッド
  • payload:送信するデータ
    • JSON.stringify():JavaScriptオブジェクトをJSON文字列に変換
    • データの構造:
      {
        'replyToken': 'reply-token-xxx...',  // 返信先の特定
        'messages': [{                        // メッセージの配列
          'type': 'text',                    // メッセージタイプ
          'text': '実際のメッセージ'          // 送信内容
        }],
      }
      

4. APIリクエストの実行と結果の処理

const response = UrlFetchApp.fetch(url, options);
return JSON.parse(response);
  • UrlFetchApp.fetch()
    • Google Apps Scriptの HTTP通信用メソッド
    • 指定したURLにHTTPリクエストを送信
  • response
    • LINE APIからのレスポンス
    • 成功時のレスポンス例:
      {
        "status": "ok"
      }
      
  • JSON.parse(response)
    • レスポンスをJavaScriptオブジェクトに変換
    • 呼び出し元で結果を扱いやすくするため

6 まとめ

基本的に、参考記事通りにやって成功しました。

✅画像をスマホ撮影
✅Lineで画像送付
✅GoogleDriveに保存(自動)
✅Lineに「画像受け取れました」のメッセージ受取(自動)

以後、続きも記事にします。
◻︎受取画像をDifyに送付
◻︎DifyのLLMで画像のテキストを読み取り
◻︎上記をGoogle Spreadsheetに保存

そして、上記が完成したら、
◻︎Notion に情報管理
に挑戦していきたいと思います。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?