実装完了
作成・変更したファイル バックエンド(新規): apps/mail/models.py — MailSender, MailEmail, MailNotificationToken apps/mail/serializers.py apps/mail/views.py — Windmill用API、フィードバック、ルール管理 apps/mail/urls.py apps/mail/admin.py マイグレーション(自動生成・適用済み) バックエンド(変更): settings.py — apps.mail 追加、MAIL_API_KEY/FRONTEND_URL 環境変数 urls.py — /api/mail/ 追加 フロントエンド(新規): mail/feedback/[token]/page.tsx — 認証不要、フィードバック3択+スコープ選択 mail/rules/page.tsx — ルール管理(一覧・追加・削除) フロントエンド(変更): Navbar.tsx — 「メールルール」メニュー追加 types/index.ts — MailSender, MailEmailFeedback 型追加 次のステップ(Windmill側) Keinaシステム側の実装は完了しています。次はWindmillにIMAPポーリングスクリプトを書く必要があります。Windmillのスクリプトが必要になったタイミングでお声がけください。
This commit is contained in:
108
document/メールフィルタ/PythonFilter試案.md
Normal file
108
document/メールフィルタ/PythonFilter試案.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# 最適化フィルタ仕様書 (v2.1)
|
||||
|
||||
## 1. システム目的
|
||||
|
||||
Gmailから取得した生データを、プログラムによる**「脊髄反射的処理(静的フィルタ)」**で徹底的に選別・加工し、人間と同等の判断が必要な**「思考的処理(LLM判定)」**へ渡すトークン量を極限まで削減する。
|
||||
|
||||
## 2. 処理フロー概略
|
||||
|
||||
1. **静的除外**: ドメイン・キーワードによる即時廃棄。
|
||||
2. **定型処理**: 認証・通知・配送状況などの「構造が既知」なメールの自動抽出。
|
||||
3. **クレンジング**: HTML・署名・引用の完全除去による軽量化。
|
||||
4. **LLM判定**: 絞り込まれたテキストのみを最小トークンで判定。
|
||||
|
||||
---
|
||||
|
||||
## 3. 詳細仕様
|
||||
|
||||
### 3.1. フェーズ1:静的フィルタ(LLMバイパス)
|
||||
|
||||
以下の条件に合致する場合、LLMステップを呼び出さず処理を完了させる。
|
||||
|
||||
* **ブラックリスト判定**: 以下のドメイン・送信元は即時廃棄(または「通知不要」としてDB記録)。
|
||||
* `mail.aliexpress.com`, `instagram.com`, `facebookmail.com`, 各種メルマガ(件名に「PR」「メルマガ」を含むもの)。
|
||||
|
||||
|
||||
* **認証・セッション系**:
|
||||
* **対象キーワード**: `認証コード`, `セキュリティコード`, `ログインのお知らせ`, `ワンタイムパスワード`.
|
||||
* **処理**: `From` と `Subject` を結合した文字列のみをLINE通知へ送り、終了。
|
||||
|
||||
|
||||
* **重複排除(Deduplication)**:
|
||||
* 過去24時間以内に同一の「送信者+送り状番号(ヤマト等)」または「送信者+件名」を処理済みの場合、ステータス更新のみを行い、新規通知としては扱わない。
|
||||
|
||||
|
||||
|
||||
### 3.2. フェーズ2:定型データ抽出(正規表現エンジン)
|
||||
|
||||
LLMに文脈を読ませるのではなく、正規表現で特定の値を抜き出し、通知文を自己生成する。
|
||||
|
||||
* **配送状況(ヤマト運輸・Amazon等)**:
|
||||
* `[0-9]{4}-[0-9]{4}-[0-9]{4}`(伝票番号)を抽出。
|
||||
* 「お届け予定」「完了」などのキーワードを抽出し、固定フォーマット化。
|
||||
|
||||
|
||||
* **金融・決済(JAバンク・カード会社)**:
|
||||
* `[0-9,]+円`(金額)および `[0-9/]{5,10}`(日付)を抽出。
|
||||
* 「支払金額:〇〇円、期日:〇〇」として構造化。
|
||||
|
||||
|
||||
|
||||
### 3.3. フェーズ3:テキスト・プリプロセッサ(クレンジング)
|
||||
|
||||
LLMに渡す場合でも、以下の処理を「必ず」事前に行う。
|
||||
|
||||
1. **HTML剥離**: `BeautifulSoup` 等を用い、タグ・スタイル・スクリプトを完全除去。
|
||||
2. **ノイズ除去**:
|
||||
* `https?://\S+` → `[URL]` へ置換。
|
||||
* 行頭の `>`(引用)および、空行・連続スペースの削除。
|
||||
* 定型フッター(「本メールに心当たりがない場合」「配信停止は」等)をキーワードリストに基づき一括削除。
|
||||
|
||||
|
||||
3. **ペイロード制限**:
|
||||
* `From`, `Subject`, `Body`(先頭300文字)をJSON形式にパックする。
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 4. LLM判定フェーズ(最終関門)
|
||||
|
||||
### 4.1. プロンプト定義
|
||||
|
||||
出力トークンを最小化するため、LLMには**「1文字のランク」**のみを返させる。
|
||||
|
||||
* **Input**: `{"from": "...", "sub": "...", "body": "..."}`
|
||||
* **System Prompt**: 「このメールが吉田さんの業務(農業・システム開発)や資産保護において、即座に確認すべき『重要』なものか判定せよ。
|
||||
* `1`: 即時通知が必要(重要・緊急)
|
||||
* `2`: 1日の終わりにまとめて通知(低緊急・要確認)
|
||||
* `3`: 通知不要
|
||||
出力は数字1文字のみとせよ。」
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 5. フィードバック・学習仕様
|
||||
|
||||
システムを改善し続けるためのデータ循環構造。
|
||||
|
||||
* **通知インターフェース**: LINE通知の下部に「不要」「毎日」のリンクを設置。
|
||||
* **データベース(PostgreSQL)**:
|
||||
* `feedback_table`: `sender_domain`, `subject_pattern`, `user_decision` を記録。
|
||||
|
||||
|
||||
* **動的更新**: `user_decision` が `ignore` になったドメインは、自動的に「3.1. ブラックリスト」へ同期される。
|
||||
|
||||
---
|
||||
|
||||
## 6. 実装上の留意点(Antigravity等)
|
||||
|
||||
* **タイムアウト対策**: 1通あたりの処理時間を最小化するため、DB照会はインデックスを貼った高速なものにすること。
|
||||
* **エラーハンドリング**: Gmail APIの取得失敗時や、LLMが数字以外を返した際のデフォルト値は「通知(1)」として、重要なメールの消失を防ぐ。
|
||||
|
||||
---
|
||||
|
||||
仕様書は以上となります。Antigravityでの実装において、具体的なPythonコードの記述や、LINE Botとの連携部分でサポートが必要になりましたら、いつでもお声がけください。
|
||||
|
||||
次は何をお手伝いしましょうか?
|
||||
265
document/メールフィルタ/mail_filter_spec.md
Normal file
265
document/メールフィルタ/mail_filter_spec.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# メールフィルタリング機能 仕様書
|
||||
|
||||
> **作成**: 2026-02-21
|
||||
> **ステータス**: 仕様確定 → 実装フェーズへ
|
||||
|
||||
---
|
||||
|
||||
## 概要
|
||||
|
||||
複数のメールアカウントに届くメールをLLMで重要度判定し、重要なメールだけをLINEで通知する。
|
||||
フィードバックを積み重ねることで判定が賢くなっていく仕組みを持つ。
|
||||
|
||||
---
|
||||
|
||||
## システム構成
|
||||
|
||||
```
|
||||
[Xserver/Gmail/Hotmail IMAP]
|
||||
↓ Windmill スケジュール実行(ポーリング)
|
||||
[メール取得・正規化]
|
||||
↓
|
||||
[重要度判定エンジン](Django API経由でDBを参照)
|
||||
├─ アドレスルールあり → ルールに従う(never_notify → スキップ)
|
||||
├─ ドメインルールあり → ルールに従う(never_notify → スキップ)
|
||||
└─ ルールなし → LLM(Claude API)に判定させる
|
||||
↓ 文脈として「過去フィードバック集計」を渡す
|
||||
↓ 重要と判断されたメール
|
||||
[LINE Messaging API で通知]
|
||||
「件名: ○○ / 送信者: △△
|
||||
👉 https://keinafarm.net/mail/feedback/{token}」
|
||||
↓ タップ
|
||||
[KeinaシステムのDjangoビュー /mail/feedback/{token}]
|
||||
↓ フィードバック選択
|
||||
[KeinaシステムのPostgreSQL更新]
|
||||
↓ 次回ポーリング時にWindmillが参照
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 技術スタック
|
||||
|
||||
| 役割 | 技術 |
|
||||
|------|------|
|
||||
| ワークフロー実行 | Windmill(既にサーバーで稼働中) |
|
||||
| メール取得 | IMAP統一(Xserver/Gmail/Hotmail) |
|
||||
| LLM判定 | Claude API |
|
||||
| LINE通知 | LINE Messaging API(既に連携済み) |
|
||||
| フィードバック画面・API | Keinaシステム(Django)に機能追加 |
|
||||
| DB | KeinaシステムのPostgreSQL |
|
||||
| Windmill ↔ Keinasystem連携 | Django REST API(APIキー認証) |
|
||||
|
||||
---
|
||||
|
||||
## メールアカウント
|
||||
|
||||
- Xserver のメールサービス(自前ドメイン)→ IMAP
|
||||
- Gmail → IMAP
|
||||
- Hotmail(Outlook)→ IMAP
|
||||
|
||||
ルールは複数アカウントをまたいで共通(アカウントを区別しない)。
|
||||
|
||||
---
|
||||
|
||||
## 判定フロー(詳細)
|
||||
|
||||
```
|
||||
新着メール受信
|
||||
↓
|
||||
1. mail_senders に一致するアドレスルールがあるか?
|
||||
→ never_notify: スキップ(LLM呼ばない、記録もしない)
|
||||
↓
|
||||
2. mail_senders に一致するドメインルールがあるか?
|
||||
→ never_notify: スキップ(LLM呼ばない、記録もしない)
|
||||
↓
|
||||
3. LLM判定(Claude API)
|
||||
入力:
|
||||
- 送信者メールアドレス・ドメイン
|
||||
- 件名
|
||||
- 本文冒頭(200字程度)
|
||||
- 過去フィードバック集計(後述)
|
||||
出力:
|
||||
- important / not_important
|
||||
↓
|
||||
4. important → mail_emails に記録 → トークン発行 → LINE通知
|
||||
not_important → mail_emails に記録(通知なし)
|
||||
```
|
||||
|
||||
### 優先順位
|
||||
|
||||
**アドレスルール > ドメインルール > LLM判断**(具体的なほど優先)
|
||||
|
||||
### LLMに渡す過去フィードバック集計
|
||||
|
||||
トークン肥大化を防ぐため、生の履歴ではなく集計値を渡す:
|
||||
|
||||
```
|
||||
送信者: promo@example.com (example.com)
|
||||
過去に通知したメール: 8通
|
||||
- 重要だった: 2回
|
||||
- 普通のメール: 5回
|
||||
- 今後通知しない: 0回
|
||||
- フィードバック未提供: 1回
|
||||
|
||||
件名: ××のご案内
|
||||
本文冒頭: ...(200字)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## データモデル
|
||||
|
||||
### `mail_senders`(送信者ルール)
|
||||
|
||||
| フィールド | 型 | 説明 |
|
||||
|---|---|---|
|
||||
| id | AutoField | |
|
||||
| email | EmailField (nullable) | アドレス指定 例: info@amazon.co.jp |
|
||||
| domain | CharField (nullable) | ドメイン指定 例: amazon.co.jp |
|
||||
| rule | CharField | 'never_notify' のみ(MVP) |
|
||||
| note | TextField | メモ(「○○の営業メール」など) |
|
||||
| created_at | DateTimeField | |
|
||||
| updated_at | DateTimeField | |
|
||||
|
||||
- `email` か `domain` のどちらか一方のみ設定する
|
||||
- アドレスルールとドメインルールが両方存在する場合、アドレスが優先
|
||||
|
||||
### `mail_emails`(通知メール記録)
|
||||
|
||||
| フィールド | 型 | 説明 |
|
||||
|---|---|---|
|
||||
| id | AutoField | |
|
||||
| account | CharField | 'xserver' / 'gmail' / 'hotmail' |
|
||||
| message_id | CharField (unique) | メールのMessage-ID(重複防止) |
|
||||
| sender_email | EmailField | |
|
||||
| sender_domain | CharField | |
|
||||
| subject | CharField | |
|
||||
| body_preview | TextField | 本文冒頭200字程度 |
|
||||
| received_at | DateTimeField | |
|
||||
| llm_verdict | CharField | 'important' / 'not_important' |
|
||||
| notified_at | DateTimeField (nullable) | LINE通知日時 |
|
||||
| feedback | CharField (nullable) | 'important' / 'not_important' / 'never_notify' |
|
||||
| feedback_at | DateTimeField (nullable) | フィードバック日時 |
|
||||
|
||||
### `mail_notification_tokens`(フィードバック用トークン)
|
||||
|
||||
| フィールド | 型 | 説明 |
|
||||
|---|---|---|
|
||||
| id | AutoField | |
|
||||
| email | OneToOneField(MailEmail) | 1メール1トークン |
|
||||
| token | UUIDField (unique) | 推測不可能なランダムUUID |
|
||||
| created_at | DateTimeField | |
|
||||
|
||||
- 有効期限なし
|
||||
- フィードバック変更可能(同じURLで何度でも再選択できる)
|
||||
|
||||
---
|
||||
|
||||
## API エンドポイント(WindmillからDjangoへ)
|
||||
|
||||
認証: リクエストヘッダー `X-API-Key: <secret>` で行う。
|
||||
|
||||
| メソッド | URL | 用途 |
|
||||
|---|---|---|
|
||||
| GET | `/api/mail/sender-rule/` | 送信者ルール確認 |
|
||||
| GET | `/api/mail/sender-context/` | LLM用フィードバック集計取得 |
|
||||
| POST | `/api/mail/emails/` | メール記録+トークン発行 |
|
||||
|
||||
### GET `/api/mail/sender-rule/`
|
||||
|
||||
クエリパラメータ: `?email=promo@example.com&domain=example.com`
|
||||
|
||||
レスポンス例:
|
||||
```json
|
||||
{
|
||||
"matched": true,
|
||||
"rule": "never_notify",
|
||||
"match_type": "domain"
|
||||
}
|
||||
```
|
||||
|
||||
### GET `/api/mail/sender-context/`
|
||||
|
||||
クエリパラメータ: `?email=promo@example.com&domain=example.com`
|
||||
|
||||
レスポンス例:
|
||||
```json
|
||||
{
|
||||
"total_notified": 8,
|
||||
"important": 2,
|
||||
"not_important": 5,
|
||||
"never_notify": 0,
|
||||
"no_feedback": 1
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/mail/emails/`
|
||||
|
||||
リクエストボディ:
|
||||
```json
|
||||
{
|
||||
"account": "gmail",
|
||||
"message_id": "<xxx@gmail.com>",
|
||||
"sender_email": "promo@example.com",
|
||||
"sender_domain": "example.com",
|
||||
"subject": "○○のご案内",
|
||||
"body_preview": "...",
|
||||
"received_at": "2026-02-21T10:30:00Z",
|
||||
"llm_verdict": "important"
|
||||
}
|
||||
```
|
||||
|
||||
レスポンス(important の場合のみトークンを返す):
|
||||
```json
|
||||
{
|
||||
"id": 42,
|
||||
"feedback_url": "https://keinafarm.net/mail/feedback/550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## フロントエンド画面
|
||||
|
||||
### 1. フィードバックページ(`/mail/feedback/{token}`)
|
||||
|
||||
- 認証不要(LINEからタップ一発でアクセス)
|
||||
- 表示内容: 送信者、件名、受信日時、本文冒頭
|
||||
- 現在のフィードバック状態を表示(変更済みの場合、どれを選んでいるか分かるように)
|
||||
- フィードバック選択肢:
|
||||
1. ✅ 重要だった
|
||||
2. 📧 普通のメール
|
||||
3. 🔇 今後通知しない
|
||||
|
||||
「今後通知しない」を選ぶと展開:
|
||||
```
|
||||
○ このアドレスだけ(promo@example.com)
|
||||
○ このドメインごと(example.com)
|
||||
[確定する]
|
||||
```
|
||||
|
||||
- 送信後: 「受け付けました」と表示
|
||||
- 再選択可能(同じURLを再度開いて変更できる)
|
||||
|
||||
「今後通知しない」でフィードバック確定時、`mail_senders` にルールを自動追加する。
|
||||
|
||||
### 2. ルール管理ページ(`/mail/rules/`)
|
||||
|
||||
ナビゲーションにメニュー追加。
|
||||
|
||||
表示内容:
|
||||
- ルール一覧テーブル(種別、値、メモ、設定日、削除ボタン)
|
||||
- 手動でルール追加フォーム(アドレスまたはドメイン、メモを入力)
|
||||
|
||||
---
|
||||
|
||||
## 実装順序
|
||||
|
||||
1. **DBテーブル定義・マイグレーション**(Django apps/mail/)
|
||||
2. **Windmill向けDjango API**(sender-rule, sender-context, emails POST)
|
||||
3. **フィードバックページ**(/mail/feedback/{token})
|
||||
4. **ルール管理ページ**(/mail/rules/)
|
||||
5. **WindmillのIMAPポーリングスクリプト**(まず1アカウントから)
|
||||
6. **LLM判定ロジック**(Claude API呼び出し、集計文脈付き)
|
||||
7. **LINE通知**(フィードバックURL付き)
|
||||
8. **残りのメールアカウントを追加**
|
||||
Reference in New Issue
Block a user