.
前回の記事
f25: Local LLM で レシートの文字起こしテスト
https://qiita.com/cxfgp/items/f557954856ec67b744a1
の派生メモです
レシートの文字起こしの手法として、
Local LLM などで試行錯誤はしておりますが、
ひとまず手っ取り早く実現できる方法を試しましたので、メモです
簡単にいうと、google サービス連動
( google lens + gmail + gas ( google apps script ) + spreadsheet )
で、文字起こししたデータから
必要部分をスプレッドシートに書き込みます
[ 00. メニュー ]
01. キッチン
02. レシピ
03. 仕込み
04. 調理
05. デザート
[ 01. キッチン ]
-
googleレンズ が使えるアンドロイド端末
(iOSでも可能と思われますが未検証です) - googleドライブ (gas) 環境
- よくあるコンビニやスーパーなどで受け取る紙の縦長レシート
[ 02. レシピ ]
「手動」 (スマホ内)
01. 紙のレシートをスマホで撮影
02. 撮影した画像を「共有」で「googleレンズ」に渡す
※ googleレンズという独立した名称ではなく、
「google アプリ」がその画像を受け取って
レンズの解析機能を起動させる仕組み
03. 画像を全選択後、画像についての指示として「文字起こし」を依頼
- 依頼文:「改行付きで、コピペ用のボタン付きで、枠(コードブロック)に入れて文字起こしして」
04. 生成された文字起こしデータを「コピー」し
「共有」で自分宛にメール送信
「自動」 (gas 上)
05. gas のトリガーを設定して自動実行させる
- 日間隔、時間隔、分間隔など、お好みに合わせて設定
-
例(時間隔、毎時の場合):
Time-driven/Hour timer/Every hour
06. 受信メールを監視し、条件にヒットしたらスプレッドシートにインサート
- 例:指定の店舗名がある場合などに、レシートデータの必要な部分を取得して書き込み
[ 03. 仕込み ]
スプレッドシートへの書き込み条件
条件(1)
以下の条件をすべて満たす場合に処理が実行されます
(処理完了後、そのメールは既読になります)
- From: 自分宛て
-
Subject:
a1 - 状態: 未読
条件(2)
テストとして「デニーズ」のレシート取り込みを想定
- レシートに「デニーズ」が含まれる場合、
以下の2行を取得・整形して1行にまとめ、
スプレッドシートにインサート [2026年 8月16日(日) 19:31 00183-1][合 計 ¥2,794]
function processLensEmail() {
// 特定の条件のメール
// (from:me かつ 件名が「a1」かつ 未読)を検索
var searchQuery = 'from:watashi@gmail.com subject:"a1" is:unread';
var threads = GmailApp.search(searchQuery);
if (threads.length === 0) {
return; // 新着メールがなければ処理を終了
}
// スプレッドシートの指定
var spreadsheet = SpreadsheetApp.openById('12345ABCDE'); // URLにあるシートID
var sheet = spreadsheet.getSheetByName('sheet1'); // ワークシート名
// 見つかったメールを1件ずつ処理
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
var message = messages[j];
if (message.isUnread()) {
var rawTextData = message.getPlainBody(); // メール本文を取得
// 【前処理】見えない改行、タブ、連続する空白をすべて半角スペース1つに置換し、前後の余白をトリム
var textData = rawTextData.replace(/[\r\n\t]+/g, ' ').replace(/\s+/g, ' ').trim();
// タイムスタンプ用の現在日時を取得(日付と時刻を2つのセルに分ける)
var now = new Date();
var tsDate = Utilities.formatDate(now, Session.getScriptTimeZone(), 'yyyy/MM/dd');
var tsTime = Utilities.formatDate(now, Session.getScriptTimeZone(), 'HH:mm:ss');
// レシートに「デニーズ」が含まれている場合に処理
if (textData.indexOf('デニーズ') !== -1) {
var formattedDate = "";
var formattedTime = "";
var storeName = "dennys";
var amount = "";
// 日付と時刻の抽出
// 2026年 8月16日(日) 19:31 にマッチ(月日の前の空白も考慮)
var dennysDateTimePattern = /(\d{4})年\s*(\d{1,2})月\s*(\d{1,2})日(?:\s*\([金木水火月土日]\))?\s*(\d{1,2}:\d{2})/;
var dennysDateTimeMatch = textData.match(dennysDateTimePattern);
if (dennysDateTimeMatch) {
var dennysParts = Array.prototype.slice.call(dennysDateTimeMatch);
dennysParts.shift();
var year = dennysParts.shift();
var monthStr = dennysParts.shift();
var dayStr = dennysParts.shift();
var rawTime = dennysParts.shift();
// 月と日を2桁に揃える
var month = ('0' + monthStr.trim()).slice(-2);
var day = ('0' + dayStr.trim()).slice(-2);
formattedDate = year + '/' + month + '/' + day;
formattedTime = rawTime.trim();
}
// 合計金額の抽出
// 「合 計 ¥2,794」のように、合と計の間にスペースがあってもマッチするよう設定
var dennysPricePattern = /合\s*計.*?[¥¥]\s*([\d,]+)/;
var dennysPriceMatch = textData.match(dennysPricePattern);
if (dennysPriceMatch) {
var dennysPriceParts = Array.prototype.slice.call(dennysPriceMatch);
amount = dennysPriceParts.pop().replace(/,/g, "");
}
// スプレッドシートに1行としてインサート
if (formattedDate && formattedTime && amount) {
sheet.appendRow([tsDate, tsTime, formattedDate, formattedTime, storeName, amount]);
} else {
sheet.appendRow([tsDate, tsTime, "デバッグ:" + formattedDate, "デバッグ:" + formattedTime, "dennys 解析失敗", "金額:" + amount + " / 本文:" + textData]);
}
}
// 処理済みのメールを既読にする
message.markRead();
}
}
}
}
[ 04. 調理 ]
自分宛てにメール送信すれば、あとは、gas のトリガーが、
メールを定期チェックして処理してくれますので、
スプレッドシートへの書き込み待ちとなります
ただし、gas のトリガーは、たまに失敗する場合があるのと、
あまり短時間 (5分など) の設定にしておくと
処理が不安定になる場合がありますのでご注意ください
例えば、レシートをまとめて処理したい場合は、
複数メール送信をしておいて、
受信ボックスに入ったことを確認したら、
手動で実行して処理し、普段は、日間隔
Time-driven / Day timer / 1am to 2am など
にしておく、でもいいのかなと思います
[ 05. デザート ]
( レシートの処理条件をどうするかはありますが )
「撮影・文字起こし・メール送信」までの一連の手動操作は、
どのみち撮影する手間に付随するため、ついで感覚で行えます
オンライン前提ですが、googleレンズ の識字率は高品位です
汎用のマルチモーダルモデル、AI-OCR、どちらかということではなく、
両方を「同時に」稼働させてシステム全体で画像を処理しているそうです
(1枚の画像に対して複数のAIが同時に役割を分担している)
(今のところ一度も間違い確認なし)
おそるべし
注意点:google に、レシートに記載されている
「お店情報」や、伏せ字があったりしますが「一部の決済関連情報」等が
取り込まれますので、その点気になる方はご注意ください
( 今回の手法ではありませんが、
- スマホで撮影
- PCに撮影画像をローカル連携
- その PC で Local LLM 処理
が、外部を介さない優位点になります )






