💰

「Gemini API」で家計簿更新UXをちょっぴり向上させてみた

2025/02/13に公開

ウチでは、家計簿管理をスプレッドシートで行っています。
毎月の食費予算を設定しており、今月の予算残高はいくらか、今年の予算積算状況などを確認することができます。

しかし、普段からパソコンをよく利用しており、仕事でも良くスプレッドシートを利用している私にとってはついでに家計簿を更新することができても、普段からパソコンを開かない、ツールなどに慣れていない人にとっては、家計簿入力のハードルが高すぎたようで、あまり更新されなくなっていました。(スマホでもできますが、小さすぎてやりづらい)

そこで今回「LINE Bot」と「Google Apps Script」、「Google AI Studio」を活用し、LINEからスプレッドシートの情報を確認、更新できるようにしました!

今回実現したこと

  • 家計簿として運用しているスプレッドシートの情報をLINEから確認することができる
    • 例)「今月の予算残高は?」という定型文に反応し、スプレッドシートの情報をレスポンスする
  • LINEから入力情報を送信するとその情報が自動的にスプレッドシートに反映される
    • 例)「2/5 OKストアで食費を7500円」と送信するとその情報がスプレッドシートに登録される

今回の記事では、二つ目のAIを活用した、LINEからスプレッドシート自動反映を紹介します!

前提

まず、LINEを使ってサードパーティー連携を行う方法として、LINEのMessaging APIを利用する方法があります。

今回のアーキテクチャは、GASで発行したアプリケーションURLをLINEのWebhook URLに設定し、LINEから送信されたメッセージをGASで受け取れるようにします。

LINEのビジネスアカウントを開設し、そのアカウントに紐づいたMessaging APIで設定を行いました。
この辺りの詳しい手順や方法はLINE Developersの公式マニュアルなどを参考にしていただければ開設可能だと思いますので、ここでは割愛します。(要望があれば...。)

LINEからスプレッドシートを更新するための課題

ここまでで、LINEのビジネスアカウントが開設され、家計簿の情報をレスポンスするGASのウェブアプリURLの発行が完了しているとします。

発行したGASのウェブアプリURLをLINE Developers管理画面のWebhook APIに設定することで、「今月の予算残高は?」という定型文に反応し、スプレッドシートの情報をレスポンスするといった昨日の実現は問題なくできます。

ただ、LINEからスプレッドシートを更新するとなると一筋縄ではいきません。。

まず、課題となるのが、LINEから送信されたメッセージの内容を正しく解読する方法がありません。
送信メッセージが正しく解読できなければ、スプレッドシートのセルに情報を埋め間違える事態が発生します。これはなるべく避けたい。

トランザクションを張って、「req: 家計簿登録」→「res: 日付?」→「req: 2/5」...といった感じで、リクエストメッセージの識別が行えれば問題なさそうですが、LINEが提供しているWebhook APIとGASでこれを実現するのは難しそう。。

AIのAPIとしてGoogle AI Studioの利用

そこで真っ先に考えたのが、AIの活用です!
当初は、LINEからレシートなどの画像情報を送信し、そこから画像解析によって、日付、用途、金額を取得するという方法です。

しかし、ChatGPTの画像認識APIは流石に無料で提供されていなそうでしたので、今回、Googleの生成AI「Gemini」を利用することにしました。

Geminiは「Google AI Studio」を活用して、無料でGeminiのAPIを利用することができます!

API Keyを発行し、GASからGemini APIを叩いてメッセージ情報を解析して、日付、ショップ、金額情報を取得します!
https://aistudio.google.com/app/apikey?hl=ja

AIでメッセージの解読を行うGAS

LINEから受け取ったメッセージとプロンプトを掛け合わせた文字列を引数に受け取るcallGeminiAPI関数を作成しました。

callGeminiAPI
function callGeminiAPI(prompt) {
  var API_KEY = 'あなたのAPI Keyに置き換えてね';
  var URL = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=' + API_KEY;

  // AIにLINEメッセージを送信
  var payload = JSON.stringify({
    contents: [{ parts: [{ text: prompt }] }]
  });

  var options = {
    method: 'post',
    contentType: 'application/json',
    payload: payload
  };

  var response = UrlFetchApp.fetch(URL, options);
  var json = JSON.parse(response.getContentText());

  if (json.candidates && json.candidates.length > 0) {
    var responseText = json.candidates[0].content.parts[0].text;

    // MEMO: 意図しないレスポンスであった場合はエラーにする
    if(responseText == EXCEPTION_MSG) return { error: true }

    // AIのレスポンスから情報を抜き出す
    var responseArr = responseText.split(',')
    var date = responseArr[0].trim();
    var store = responseArr[1].trim();
    var category = responseArr[2].trim();
    var amount = responseArr[3].trim();
    
    // スプレッドシートの情報更新
    updateSpreadsheetWithAPIResponse({ date: date, store: store, category: category, amount: amount, error: false })
    return { date: date, store: store, category: category, amount: amount, error: false };
  } else {
    return { error: true };
  }
}

今回、私の場合は、LINEで受信したメッセージが今月の残高、年間積算の定型文に合致しない場合に実行される処理の中で、以下のような形で実行させました。

doPost(e)
function doPost(e) {
    // ...省略...
    var { date, store, category, amount, error } = callGeminiAPI(`${messageText}」の文章から日付(MM/dd)と店舗と食費や固定費などのカテゴリー情報、金額(単位は省略)の情報を抜き出してカンマ区切りの配列でレスポンスして下さい。一つでも情報が抜き出せない場合は、「${EXCEPTION_MSG}」と返事して下さい。`)
             if(!error) {
              resMessage = `日付:${date}\n店舗:${store}\n費目:${category}\n金額:${amount}`
             } else {
              resMessage = EXCEPTION_MSG
             }
    // ...省略...
}

EXCEPTION_MSGには、LINEではこんな感じの構文で送って下さいというような文字列を仕込んでおいて、AIの解析に失敗した場合にリトライしやすくなるようにしてみました。

また、私のプロンプトも参考にしてみて下さい。

「{LINEから受け取ったメッセージ}」の文章から日付(MM/dd)と店舗と食費や固定費などのカテゴリー情報、金額(単位は省略)の情報を抜き出してカンマ区切りの配列でレスポンスして下さい。一つでも情報が抜き出せない場合は、「{入力して欲しいフォーマットの例}」と返事して下さい。

APIのレスポンス情報をオブジェクト構造にフォーマット化し、スプレッドシートのセルに値を入力していくupdateSpreadsheetWithAPIResponse関数を作成して完成です!

updateSpreadsheetWithAPIResponse
function updateSpreadsheetWithAPIResponse(dataArray) {
  if (dataArray.error) {
    return; // エラーがあった場合は処理を終了
  }

  // スプレッドシートを取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  // スプレッドシートの最後の行を取得
  var lastRow = sheet.getLastRow();

  // 次の行にデータを入力
  var newRow = lastRow + 1;

  // APIのレスポンスから取得したデータ
  var date = dataArray.date;
  var store = dataArray.store;
  var category = dataArray.category;
  var amount = dataArray.amount;

  // 取得した情報をスプレッドシートに入力
  sheet.getRange(newRow, 1).setValue(category);    // 1列目に費目
  sheet.getRange(newRow, 2).setValue(store);   // 2列目に店舗
  sheet.getRange(newRow, 3).setValue(date); // 3列目に日付
  sheet.getRange(newRow, 4).setValue(amount);  // 4列目に金額
}

さいごに

以上で、普段から使い慣れたLINEで家計簿の更新ができるようになりましした!
これで、ウチの家計簿がちゃんと更新されるようになればいいなと思います。

AIの登場で、ほんの数時間で今回のアプリケーションが完成させることができました。
家族で利用するツールのUX向上にかなり貢献してくれそうです。

プログラムの量は最小で取得したい情報量を増やすこともできたりすると思うので、より便利なツールへのバージョンアップもやっていきたいです。

みなさんの参考になれば幸いです。
最後まで読んでいただき誠にありがとうございます。

Discussion