📢 2026.05.13 追記: この記事をちょこちょこ見ていただけているようなので、リポジトリを公開しました。
https://github.com/Oakums/receipt-reader-public
リファクタリングを行いGASにパラメータを持たせる形に変更しています。
1. はじめに
既存の家計簿アプリでは痒い所に手が届かず、年末休暇を利用して「わが家専用」の精算システムを構築しました。解決したかったのは以下の3点です。
-
手計算の排除
レシートから個人分を抜き出す作業の自動化。 -
転記の自動化
スプレッドシート(GSS)への自動入力。 -
運用負荷の軽減
LINEで写真を送るだけで完結させる。
当初はネイティブアプリを作る気満々でGeminiに相談したのですが、そこで思わぬ 「逆提案」 を食らいました。
Gemini:「UIの実装やストア公開は面倒ですよ。LINE Bot + GAS + Gemini APIの構成なら、今すぐ無料で実用的なものが作れます。それで十分じゃないですか?」
正直、意表を突かれましたが、AIに開発の方向性を論破されるのも面白いなと思い、その提案に乗っかることにしました。
2. システム構成と開発環境
「サクッと作る」とはいえ、後で自分が苦しまないように開発環境はモダンに整えました。GASのエディタは使わず、VSCodeでガシガシ書いています。
設計やプロンプトの叩き台は Gemini 1.5 Pro と対話し、実際のコーディングやユニットテストの量産には VSCode + GitHub Copilot を活用しました。
「AIに設計を相談し、AIに実装を補完させる」というフローにより、年末年始の数日間で使えるくらいのものにはなりました。
3. AIとの責任分界点
AI(Gemini)には 「人間が読み取るのが面倒な情報の構造化」 に専念させ、計算などの 「決定的な算術処理」 はプログラム(GAS)側で行うよう責務を厳密に分離しました。
| コンポーネント | 役割 (Responsibility) | 設計のポイント |
|---|---|---|
| Gemini API | 画像 → JSONへの構造化 | OCR結果から「品目」「単価」「割引」を抽出。 |
| GAS (Logic層) | ビジネスロジック (案分) | 抽出データから「特定商品の除外」や「割引の案分」を算術計算。 |
| Google Sheets | 永続化層 (Database) |
LockService を活用し、同時実行時の競合(Race Condition)を防止 |
4. 実装のキモ-共同作業-
AIには「レシートの各行に番号を振ったJSON」を返させ、ユーザーが特定の番号を指定して「このお酒分だけ引いておいて」とGAS側に計算させる仕組みにしました。
これにより機能追加をプロンプト(ガチャ)ではなく関数で実装できるようにしました。
プロンプトの工夫(System Instruction)
Geminiには、計算をさせず「抽出」に徹するように以下のニュアンスで指示を出しています。
「レシート画像を解析し、各商品に1から順に番号を振ったリストを作成してください。また、レシート全体の『小計』『割引額』も個別に抽出してJSON形式で返してください。計算は不要です。」
案分計算のロジック(抜粋)
全体の割引額(クーポンなど)を考慮し、特定の商品を除外した際の実質価格を算出するロジックです。ここはハルシネーションを防ぐため、敢えてGAS側でガチガチに計算しています。
/**
* 商品価格から、全体割引の比率を考慮して実質価格を算出する
* 外部APIに依存しない純粋関数のため、Jestでのテスト対象とする
*/
export function calculateActualPrice(itemPrice: number, subtotal: number, totalDiscount: number): number {
if (subtotal <= 0) return itemPrice;
// 割引率を算出して適用(端数は四捨五入)
const discountAmount = Math.round(itemPrice * (totalDiscount / subtotal));
return itemPrice - discountAmount;
}
5. 今後の課題:あえて「完璧」を目指さない
実際に運用してみると、いくつか技術的な限界も見えてきました。
-
重複登録防止の精度
LockService.getScriptLock().waitLock(30000)を使用していますが、GSS側の反映遅延により稀に動作が不安定になることがあります。 -
例外フォーマットへの対応
店舗ごとに異なるレシートレイアウトや、税率混在(8%/10%)への対応はプロンプトの調整が必要です。
「仕様書をガチガチに固めて、一度作ったら不変!」みたいな堅苦しい開発は、もうやめました。
家族の要望が変わったら、またGeminiとあーだこーだ言いながらコードを書き換える。
そんな、AIと「二人三脚でゆるく育てていく」くらいのスタンスが、個人開発にはちょうどいいみたいです。
6. 結び
導入後、レシートの写真を撮って送るだけでよくなり、レシートはその場で捨てられるようになりました。
「もしバグが出て困るなら、またGeminiと対話してその場でロジックを直してもらえばいい」という緩いスタンスで、今後も「わが家専用」をアップデートし続けていきます。