やりたかったこと
確定申告の医療費控除に向けて、手元に溜まったレシート画像87件を国税庁の医療費集計フォーム(Excel、v3.1)に入力する必要があった。手作業だと1件あたり数分かかるので、OCRで読み取ってExcelに自動入力する仕組みを作った。
全体の流れ
- レシート画像をGemini APIでOCR
- 読み取り結果をExcelの所定フォーマットに書き込み
- レシート画像をルールに従ってリネーム
- 重複チェックと集計シート追加
Gemini APIによるOCR処理
レシート画像87件をGemini APIに投げてOCR処理した。読み取り対象は以下の項目。
- 患者名
- 医療機関名
- 診療日
- 支払金額
- 治療内容(医療費の区分判定用)
結果、87件すべてエラーなしで読み取り完了。手書きレシートや感熱紙でかすれたものも含まれていたが、Geminiの画像認識精度が高く、目視確認で修正が必要だったのは数件程度だった。
Excel入力の自動化
国税庁フォーマットへの対応
医療費集計フォーム v3.1 は、シートの保護やセル結合が多く、プログラムから書き込む際にいくつかハマりどころがあった。
日付入力の問題
最初の実装ではExcelの日付型(シリアル値)で書き込んでいた。しかし、国税庁フォームは日付セルを文字列として扱う想定になっており、シリアル値だと表示がずれる。
修正として、日付を文字列「YYYY/M/D」形式(例: 2026/1/15)で書き込むように変更した。月・日のゼロ埋めなし形式が国税庁フォームの表示と一致する。
スラッシュコマンド化
この処理を繰り返し使えるように、/import-medical-receipts というスラッシュコマンドとして実装した。
tax-assistant の既存パターンをベースにした構成で、以下の機能を持つ。
- レシート画像ディレクトリを指定して一括OCR
- OCR結果のプレビュー表示(書き込み前に確認できる)
- Excelファイルへの書き込み
- 重複チェック
- 集計シート生成
レシート画像のリネーム
OCR後にレシート画像を整理しやすくするため、命名規則を決めてリネームを行った。
命名規則
{患者名}_{医療機関名}_{YYYYMMDD}_{金額}円.jpg
例: 山田太郎_A内科_20260115_1520円.jpg
リネームの手順
- 元画像のバックアップコピーを作成
- バックアップが完了してからリネーム実行
バックアップを先に取ることで、リネーム中のエラーで元ファイルが失われるリスクを避けた。
患者名が不明な場合のルール
レシートによっては患者名が印字されていないものがある。その場合は以下のルールで推定した。
- 同日の他レシートから推定: 同じ日に別の医療機関で受診したレシートに患者名が書いてあれば、同一人物と推定
- 複数候補がある場合: レシート件数が多い方、件数が同じなら合計金額が大きい方を採用
完全に推定できないケースはファイル名に「不明」を入れて、後から手動で確認できるようにした。
重複チェック
同じレシートを二重に入力しないよう、以下の条件で重複判定を行った。
- 患者名
- 医療機関名
- 診療日
- 金額
4項目すべて一致した場合に重複と判定し、スキップする。同日・同医療機関でも金額が異なれば別レシートとして扱う(再診料と検査料が別レシートになるケースがある)。
集計シート
Excelに集計用のシートを追加した。Google Spreadsheetで先に作っていた集計表のレイアウトを参考に、患者別の合計金額を表示するシートを生成する。
集計内容:
- 患者別の医療費合計
- 医療機関別の内訳
- 月別の推移
Excelのバージョン管理ルール
国税庁のExcelフォームは「元ファイルを直接変更しない」運用とした。
- 元ファイルのコピーを作成
- コピーに対して変更を加える
- 元ファイルは常にオリジナルの状態で残す
こうすることで、スクリプトのバグで書き込みが壊れた場合でもやり直せる。確定申告関連のファイルは特に慎重に扱いたい。
振り返り
- Gemini APIのOCR精度が想像以上に高く、87件エラー0件は期待を上回った
- 日付のフォーマット問題は、国税庁フォームの仕様を先に調べておけば防げた
- スラッシュコマンド化しておくと、来年以降もそのまま使い回せる
- レシートのリネームは地味だが、後から探すときに助かる