名刺画像を自動で前処理し、YomiToku + Gemini を用いた OCR/要約結果を Supabase に保存、Next.js ダッシュボードで閲覧できる統合ワークフローです。ローカル PC での展示運用を想定しつつ、クラウド連携もサポートしています。
| レイヤー | 技術 | 主な役割 |
|---|---|---|
| フロントエンド | Next.js 16 (App Router) + Supabase JS | 名刺一覧・検索・詳細表示、プロジェクト管理、スキャン UI(ファイル選択/カメラ撮影/HEIC 対応) |
| バックエンド | Next.js API Route (/api/cards/scan) |
アップロード受付、Python スクリプトによる前処理/OCR のワーカージョブ実行 |
| データパイプライン | Python (preprocess_images.py, yomitoku.py) |
画像補正・フォーマット変換、YomiToku OCR、Gemini によるフィールド抽出、Supabase 永続化 |
| ストレージ/DB | Supabase Storage + Postgres | 原本・前処理済み画像、OCR 結果、プロジェクト・カード情報 |
- 依存インストール(
uv推奨):uv sync
- 主要ライブラリ:
yomitoku,google-generativeai,opencv-python-headless,pillow-heif,easyocr, ほか。 - 初回のみ Gemini API キーを設定:
cp .env.local .env.local.sample # 既存テンプレートを確認 # .env.local に GEMINI_API_KEY および Supabase キーを設定
cd web
cp .env.local.example .env.local # Supabase URL/Anon/SERVICE_ROLE/PYTHON_BIN などを設定
npm install
npm run devPYTHON_BINを指定すると/api/cards/scanから Python 仮想環境を確実に呼び出せます(未設定の場合は.venv/bin/python→python3順で探索)。- Next.js 実行中はローカルで
http://localhost:3000にアクセスします。
.env.local(Python 側)・web/.env.local(Next.js 側)に以下を揃えてください。
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=service-role-key
SUPABASE_SOURCE_BUCKET=source-images
SUPABASE_PROCESSED_BUCKET=processed-images- SERVICE ROLE KEY はサーバーサイド専用です。クライアントからは
NEXT_PUBLIC_SUPABASE_URLとNEXT_PUBLIC_SUPABASE_ANON_KEYのみを公開します。 - 架空ユーザーでのテストには Supabase Auth の UUID を
--user-idやアップロード時に付与してください。
uv run python preprocess_images.py photo \
--output-dir photo_preprocessed \
--record-to-db \
--user-id <Supabase User UUID> \
--project-id <既存プロジェクトID>pillow-heifにより.heic / .heifを自動で読み込み可能。- 処理内容: EXIF 向き補正、短辺 720px 以上へのアップスケール、ノイズ除去、CLAHE、アンシャープマスク、ガンマ補正。
--record-to-dbオプションで原本/補正画像やメタデータを Supabase に保存。Manifest (manifest.json) も出力されます。
uv run python yomitoku.py photo_preprocessed \
--record-to-db \
--manifest photo_preprocessed/manifest.json \
--user-id <Supabase User UUID> \
--project-id <既存プロジェクトID>- YomiToku の解析結果を Gemini API で整形し、
yomitoku_results/summary.csvを作成。 - Supabase には
yomitoku_resultsとyomitoku_result_fieldsが保存され、Web ダッシュボードから閲覧可能。 --disable-geminiで Gemini 不使用モードに切り替え可能。
uv run ocr-local photo/IMG_0001.jpg --output-dir ocr_outputs| 画面 | 機能概要 |
|---|---|
/ Dashboard |
名刺一覧(検索/並び替え/ページネーション)、各カードのプロジェクト・解析状況を表示。カードをクリックで詳細へ遷移。 |
/cards/[id] |
原本・前処理済み画像、抽出された連絡先フィールド、Gemini 生テキストを確認。 |
/scan |
複数ファイル一括アップロード、削除、カメラ撮影対応。撮影画像は縦向き補正+明るさ調整後にプレビュー表示されます。HEIC もブラウザ内で JPEG に変換して取り込めます。 |
/projects |
プロジェクトの新規作成/削除(確認ダイアログ付き)、右カラムで詳細・カード一覧を表示。 |
- ファイル選択または「カメラで撮影」から名刺を追加(HEIC も可)。
- 画面下部にプレビューカードが表示され、不要なものは「削除」で除去。
- 「解析キューに送信」で
/api/cards/scanに POST → Python スクリプトがバックグラウンド実行。 - Supabase への書き込みが完了次第、Dashboard に反映されます(リロードまたは検索し直すと確認可能)。
- 受信したファイルを一時ディレクトリに保存。
preprocess_images.py→yomitoku.pyを順番に呼び出し、Supabase へ原本・前処理済み画像・OCR 結果を登録。- 処理は非同期で進むため、API レスポンスは 202 Accepted を返します。ログは Next.js 側に出力されるので、問題発生時はターミナルを確認してください。
- Python:
uv run/uv pipを利用すると依存を隔離したまま動作確認できます。 - Web: Turbopack のキャッシュ不整合が起きた場合は
npm run dev -- --turboではなくnext dev --no-turboで切り替えると安定することがあります。 - カメラ撮影が「デバイスが見つかりません」となる場合はブラウザの権限や外付けカメラの接続を確認し、再読み込みしてください。
- Supabase 側で RLS を有効化する場合は JWT のクレームや Policy を別途構成してください(本プロジェクトはローカル展示用のため SERVICE_ROLE を直接使用しています)。
プロジェクト固有のライセンスが未定義の場合は、利用するサービス・ライブラリの規約に従ってください。
PR 時は uv format や npm run lint を実行し、Python/Next.js の依存ロックファイルを更新した場合は一緒にコミットしてください。開発中はタスクごとに Conventional Commit (feat:, fix: など) を守る運用としています。