レシート撮るだけ!AI家計簿アプリを作った話【Amazon Bedrock × Streamlit】
TL;DR(要約)
- レシート画像を撮影 → AIが自動で家計簿に記録
- 技術スタック: Amazon Bedrock(Claude 3.7)、Textract、Python、Streamlit
- 開発期間: 約1週間(試行錯誤含む)
- コスト: 月額約$5〜10(従量課金)
- 難易度: ★★☆☆☆(Pythonの基礎知識があればOK)
📖 目次
なぜ作ったのか
背景:家計簿が続かない問題
2020年、新卒入社。コロナ禍。
- 焦燥感と不安の中、家計簿アプリを導入
- でも...めんどくさい
- 2023年、ほぼ記録なし(レシート山積み)
2024年、物価上昇。
- 「もう一度ちゃんと管理したい」
- でもやっぱりめんどくさい
- レシートすら受け取らなくなる
2025年、転機。
あるイベントでAmazon Bedrockに触れる機会があり、
「これならめんどくさがりな自分でも続けられるかも」と思い、開発を決意。
なぜStreamlit?
- フロントエンドの知識不要
- Pythonだけで完結
- 爆速で試作できる
- ローカル環境で十分
何を作ったのか
機能概要
レシート撮影 → AI読み取り → 自動で家計簿に記録
具体的には:
- スマホでレシートを撮影
- Streamlitアプリにアップロード
- AIが以下を自動抽出:
- 店名
- 購入日
- 合計金額
- カテゴリ(食費/外食/雑貨など)
- Google Spreadsheetに自動記録
従来の手入力(約3分)と比較して、約18倍高速。
どうやって作ったのか
技術スタック
| レイヤー | 技術 | 用途 |
|---|---|---|
| フロントエンド | Streamlit | UI・画像アップロード |
| バックエンド | Python 3.12 | ロジック・API連携 |
| OCR | Amazon Textract | レシートの文字認識 |
| AI | Amazon Bedrock (Claude 3.7 Sonnet) |
テキスト分析・カテゴリ判定 |
| データ保存 | Google Spreadsheet | 家計簿データ |
| AI Framework | Strands SDK | エージェント構築 |
システム構成図
データフロー
レシート画像(JPG)
↓ Streamlit:リサイズ・Base64エンコード
Base64文字列
↓ Textract:OCR処理
生テキスト
例: "セブンイレブン\n2025/11/09\n合計 ¥1,580"
↓ Claude 3.7 Sonnet:AI分析
構造化データ
{
"店名": "セブンイレブン",
"日付": "2025-11-09",
"金額": 1580,
"カテゴリ": "食費"
}
↓ Google Sheets API
スプレッドシート記録完了
システム構成
アーキテクチャ図(詳細版)
┌─────────────────────────────────────────────────────────┐
│ ユーザー環境 │
│ ┌────────────────────────────────────────────────┐ │
│ │ Streamlit UI (localhost:8501) │ │
│ │ - 画像アップロード │ │
│ │ - リサイズ処理(800px以下) │ │
│ │ - Base64エンコード │ │
│ └──────────────┬─────────────────────────────┘ │
│ │ HTTP POST │
│ ┌──────────────▼─────────────────────────────┐ │
│ │ Python Agent (localhost:8080) │ │
│ │ - HTTP サーバー(aiohttp) │ │
│ │ - エージェント制御(Strands SDK) │ │
│ │ - ツール管理 │ │
│ └──────────────┬─────────────────────────────┘ │
└─────────────────┼─────────────────────────────────────┘
│
┌─────────┴─────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 📄 Textract │ │ 🤖 Bedrock │
│ (OCR) │ │ (Claude) │
│ us-west-2 │ │ us-west-2 │
└──────────────┘ └──────────────┘
│ │
└─────────┬─────────┘
│
▼
┌──────────────┐
│ Google │
│ Sheets API │
└──────────────┘
環境変数
# .env
SPREADSHEET_ID=your-spreadsheet-id
GOOGLE_CREDENTIALS_PATH=/path/to/credentials.json
AWS_DEFAULT_REGION=us-west-2
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
工夫したポイント
Base64エラー対策
問題:
画像データが大きいとIncorrect paddingエラー
解決策:
# パディング自動追加
padding_needed = (4 - len(image_base64) % 4) % 4
if padding_needed:
image_base64 += '=' * padding_needed
画像サイズ最適化
問題:
大きい画像(3MB以上)でTextractがタイムアウト
解決策:
# 800px以下にリサイズ
max_dimension = 800
if image.width > max_dimension or image.height > max_dimension:
ratio = min(max_dimension / image.width,
max_dimension / image.height)
new_size = (int(image.width * ratio),
int(image.height * ratio))
image = image.resize(new_size, Image.Resampling.LANCZOS)
効果:
- サイズ: 3.2MB → 150KB(約95%削減)
- 処理時間: 15秒 → 3秒(5倍高速化)
カテゴリ自動判定
Claudeにルールベースの判定をさせる:
system_prompt = """
カテゴリ自動判定ルール:
1. 食費: スーパー、コンビニ(食品)
2. 外食: レストラン、カフェ
3. 雑貨: ドラッグストア、100円ショップ
4. 交通費: 電車、バス、タクシー
5. 娯楽費: 書店、映画館
6. 日用品: トイレットペーパー、洗剤
7. その他: 上記以外
"""
精度:
- 正解率: 約92%(100件テスト)
- 誤判定例: 「コンビニでの切手購入」→「食費」(本来は「その他」)
エラーハンドリング
try:
response = textract_client.detect_document_text(
Document={'Bytes': image_bytes}
)
except ClientError as e:
if e.response['Error']['Code'] == 'UnsupportedDocumentException':
return "画像形式が非対応です(JPEG/PNG推奨)"
elif e.response['Error']['Code'] == 'InvalidParameterException':
return " 画像が小さすぎます"
else:
return f" Textractエラー: {str(e)}"
Google Sheets の月別シート対応
# 日付から月を判定
date_obj = datetime.strptime(date, "%Y-%m-%d")
sheet_name = f"{date_obj.month}月" # 例: "11月"
# シートが存在しない場合は最初のシートを使用
try:
sheet = spreadsheet.worksheet(sheet_name)
except:
sheet = spreadsheet.sheet1
print(f"{sheet_name}シートが見つかりません")
ハマったポイント
Textractの日本語対応
問題:
日本語レシートの認識精度が低い
対策:
- 画像の解像度を上げる(最低 800x600px)
- コントラストを調整
- 斜めの写真は避ける
結果:
- 認識率: 75% → 95%に向上
Base64データの切り詰め
問題:
AIに渡す際、プロンプトで{image_base64[:50]}...と省略していた
原因:
# NG
prompt = f"画像データ: {image_base64[:50]}..."
# OK
prompt = f"画像データ:\n{image_base64}"
Google Sheets API の書き込み遅延
問題:
書き込み直後に読み込むと古いデータが返ってくる
対策:
# 1秒待機
time.sleep(1)
Bedrock のリージョン
問題:
us-east-1では Claude 3.7 Sonnet が使えない
対策:
-
us-west-2を使用
コスト試算
月間100件のレシート処理(想定)
| サービス | 料金 | 月額 |
|---|---|---|
| Textract | $1.50 / 1000ページ | $0.15 |
| Bedrock(Claude 3.7) | 入力: $3/MTok 出力: $15/MTok |
約$5〜8 |
| Google Sheets API | 無料(60回/分まで) | $0 |
| Streamlit | ローカル実行 | $0 |
| 合計 | - | 約$5〜8/月 |
コーヒー1杯分で家計簿が自動化!
今後の展望
Phase 1: 機能拡張
- スマホアプリ化(Flutter/React Native)
- レシート画像の自動トリミング
- 月次レポート自動生成
- 予算アラート機能
Phase 2: 精度向上
- ファインチューニング(店名辞書)
- 手書きレシート対応
- 複数レシート一括処理
Phase 3: クラウド化
-
AWS Lambda + API Gateway でサーバーレス化
-
S3 で画像保管
-
DynamoDB でメタデータ管理
-
Amplify でホスティング
-
AWS BedRock ⇨ AWS AgentCoreに移行予定( BedRockが更新されなくなったから)
学んだこと
技術面
-
Amazon Bedrock の使いやすさ
- ファインチューニング不要
- プロンプトだけで高精度
-
Textract の限界
- 日本語の縦書きは苦手
- 手書き文字は要前処理
-
Streamlit の爆速開発
- 1日でプロトタイプ完成
- デバッグが楽
非技術面
-
めんどくさがり屋こそ自動化すべき
- 最初の投資(開発時間)を惜しまない
- 長期的には時間を取り戻せる
-
完璧主義は捨てる
- 92%の精度で十分
- 100%を目指すとコストが爆増
まとめ
作ってよかったこと:
- 家計簿が続くようになった(3ヶ月継続中)
- AWS の知識が深まった
- AI の実用的な活用方法が分かった
みなさんへのメッセージ:
「めんどくさい」は最高の開発動機です。
自分の困りごとを解決するアプリを作ると、
モチベーションが続きます。
ぜひ、あなたも「めんどくさい」を自動化してみてください!
参考リンク
- Amazon Bedrock 公式ドキュメント
- Amazon Textract 公式ドキュメント
- Streamlit 公式サイト
- Strands SDK GitHub
- Streamlitキャッチアップで使った教材
実装で詰まった点や改善案があれば、コメント欄で教えてください!
いいねとストックお願いします!👍