• #tax-assistant
  • #claude-code
  • #implementation
開発完了

勘定科目AI判定機能の実装

概要

/validate-receipts のサブエージェントに勘定科目の判定も行わせ、Gemini OCRの結果と照合する機能を追加する。

現状(Before)

勘定科目UI - Before

  • サブエージェントは日付・金額・支出先・摘要のみ読み取り
  • 勘定科目はGemini OCRの結果のみ表示
  • AIによるダブルチェックがない

目標(After)

  • サブエージェントが勘定科目も判定
  • Gemini OCRとサブエージェントの結果を照合
  • 不一致の場合、UIで視覚的に表示

実装内容

1. DB変更

subagent_reads テーブルに勘定科目フィールドを追加:

ALTER TABLE subagent_reads ADD COLUMN read_account_category TEXT;
ALTER TABLE subagent_reads ADD COLUMN account_category_confidence INTEGER DEFAULT 100;

2. スキル修正(/validate-receipts)

サブエージェントに渡すプロンプトに勘定科目の判定を追加:

1. 各画像を読み取り、以下の情報を抽出:
   - 日付 (YYYY/MM/DD形式)
   - 金額 (円単位、整数)
   - 支出先 (支払先の店舗名・会社名)
   - 摘要 (取引内容の簡潔な要約)
   - 勘定科目 (以下から選択)  ← 追加
   - 信頼度 (0-100、読み取りにくい場合は下げる)
   - 手書きフラグ

勘定科目の選択肢:

  • 会議費
  • 接待交際費
  • 消耗品費
  • 旅費交通費
  • 新聞図書費
  • 通信費
  • 支払手数料
  • 車両費
  • 仮払金

3. 比較スクリプト修正(validation.py)

compare_batch_reads 関数で勘定科目の比較を追加:

# 勘定科目は完全一致で判定
account_cmp = compare_values(
    ocr["account_category"], row["read_account_category"],
    "account_category", row["account_category_confidence"] or 100
)

4. UI修正(ReceiptForm.vue)

勘定科目ボタンの表示ロジックを変更:

条件表示
OCR結果 = サブエージェント結果青ボタン(現状通り)
OCR結果 ≠ サブエージェント結果サブエージェント結果のボタンに紫枠線 + エージェントアイコン

UIイメージ

勘定科目
┌─────────┐  ┌─────────────┐  ┌─────────┐
│ 会議費  │  │ 接待交際費  │  │ 消耗品費 │
│ (青)    │  │ (グレー)    │  │ (グレー) │
└─────────┘  └─────────────┘  └─────────┘

┌─────────────┐  ┌─────────────┐
│ 🤖         │  │             │
│ 旅費交通費  │  │  新聞図書費  │
│ (紫枠線)   │  │  (グレー)   │
└─────────────┘  └─────────────┘
  • エージェントアイコン(🤖)はボタンの左上に小さく表示
  • 紫枠線で「AIが別の勘定科目を提案している」ことを示す
  • 判定詳細は不要(ボタンを見れば違いがわかる)

実装順序

  1. DB: subagent_reads テーブルにカラム追加
  2. Python: db.pysave_read_result 関数を修正
  3. スキル: /validate-receipts のプロンプトを修正
  4. Python: validation.py の比較ロジックを修正
  5. API: 勘定科目の比較結果を返すように修正
  6. Vue: ReceiptForm.vue のボタン表示ロジックを修正

注意事項

  • 勘定科目の選択肢はクライアントごとに異なる可能性あり(将来的にはDBで管理)
  • 現状は固定の選択肢で実装

実装結果(After)

勘定科目UI - After

  • サブエージェントが勘定科目も判定するようになった
  • OCR結果(会議費)とAI判定(接待交際費)が異なる場合、紫枠線+🤖アイコンで表示
  • 不一致はoverall_scoreにも反映(勘定科目30%の重みで減点)

実装で修正したファイル

ファイル修正内容
src/db.pysubagent_readsテーブルへのカラム追加、save_read_result関数の修正
src/validation.py勘定科目の比較ロジック追加、overall_scoreへの反映
src/ocr_server.pyAPIレスポンスにread_account_categoryを追加
.claude/commands/validate-receipts.mdサブエージェントプロンプトに勘定科目判定を追加
frontend/app/components/receipt/AccountCategory.vueAIの提案を紫枠線+🤖アイコンで表示
frontend/app/components/receipt/ReceiptForm.vue不一致時のみ紫枠線を表示するスタイル修正
frontend/app/composables/useReceipts.tsクリック時のバリデーションデータ消失バグを修正

バグ修正

クリック時にバリデーションデータが消える問題

原因: selectItem関数でfile_nameのみで検索していたため、複数バッチがある場合に別のバッチのアイテムを見つけてしまっていた。

修正: batch_idfile_nameの両方で比較するように変更。

// Before
const globalIdx = allItems.value.findIndex(i => i.file_name === item.file_name)

// After
const globalIdx = allItems.value.findIndex(
  i => i.batch_id === item.batch_id && i.file_name === item.file_name
)