Schedule reminders by mentioning the Discord bot
メンション本文にリマインド系のキーワードが含まれていたとき、LLM に create_reminder / list_reminders / cancel_reminder の3ツールを渡し、 自然言語から日時と用件を取り出して reminders テーブルに保存する。 system メッセージに現在時刻を入れてあるので『明日』『30分後』のような 相対表現はモデル側が絶対日時に直す。扱うのは一回きりの通知のみ。 配信は APScheduler の discord_reminders ジョブ(既定30秒間隔)が担い、 Webhook ではなく Bot クライアントから登録元チャンネルへ依頼者を メンションして送るため、専用の Webhook URL 設定は要らない。 - 日時は他テーブルと同じく UTC で保存し、ユーザー・LLM とのやり取りは ローカル時刻で行って reminders.py の境界で変換する - 過去・REMINDER_MAX_AHEAD_DAYS より先・解釈不能な日時はツール結果として エラー文をモデルに返し、聞き直させる - 一覧・取り消しは依頼者の user_id で絞るため他人のリマインドには触れない - 配信に5回失敗したら notified_at を立てて諦める(チャンネル削除などで ポーリングのたびにエラーログを出し続けるのを防ぐ)。カウンタは プロセス内のみなので、再起動すればまた試す Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,10 @@ backend/
|
||||
│ │ ├── search/
|
||||
│ │ │ └── websearch.py # Tavily による web_search ツール
|
||||
│ │ ├── discord/ # Discord Bot・定期通知
|
||||
│ │ │ ├── discord_bot.py # メンションへの返信(天気 / 雑談 / リマインドで分岐)
|
||||
│ │ │ ├── scheduler.py # APScheduler ジョブ(天気通知・Tips・リマインド配信)
|
||||
│ │ │ ├── reminders.py # リマインドの登録ツールと配信ジョブ
|
||||
│ │ │ └── notify.py # Webhook 送信
|
||||
│ │ ├── settings_store.py # GUI 設定を os.environ へ反映
|
||||
│ │ └── auth.py / site_auth.py # 設定画面パスワード・サイトログイン
|
||||
│ └── db/
|
||||
@@ -71,6 +75,7 @@ backend/
|
||||
| `app_settings` | key, value, updated_at | GUI 設定画面から編集した接続情報 |
|
||||
| `model_presets` | id, label, value, created_at | モデル選択プルダウンの選択肢 |
|
||||
| `api_logs` | id, session_id, model, request_json, response_text, error, latency_ms, created_at | LLM API 呼び出しログ |
|
||||
| `reminders` | id, channel_id, user_id, user_name, content, due_at, created_at, notified_at, cancelled_at | Discord Bot が預かった一回きりのリマインド(`due_at` は UTC) |
|
||||
|
||||
### コンテキスト管理(`core/memory_kb/`)
|
||||
|
||||
@@ -172,6 +177,47 @@ data: {"type":"error","value":"エラー内容"} # 例外発生時
|
||||
|
||||
バッファリング防止のため `Cache-Control: no-cache` と `X-Accel-Buffering: no` を付与する。
|
||||
|
||||
### Discord Bot(`core/discord/`)
|
||||
|
||||
`main.py` の lifespan が `start_discord_bot()`(メンション応答)と `start_scheduler()`(定期ジョブ)を起動する。
|
||||
|
||||
`on_message` はメンション本文をキーワードで見て分岐する。判定順は **リマインド → 雑談 → 天気** で、
|
||||
先にマッチしたものが返信を返して終わる。
|
||||
|
||||
| 分岐 | キーワード例 | 動作 |
|
||||
|---|---|---|
|
||||
| リマインド | リマインド / 忘れないように / 覚えといて / アラーム | `reminders.handle_reminder_request()` に渡す |
|
||||
| 雑談 | どうでもいい / 雑談 / 暇 | 『どうでもいいTips』へ誘導しつつ、話題に近いタグで Tips を1本投稿 |
|
||||
| 天気 | 天気 / 洗濯 / 雨 | 気象庁の明日の予報を system メッセージに足してから返信 |
|
||||
|
||||
APScheduler に登録されるジョブは 3 つ。
|
||||
|
||||
| ジョブ | トリガー | 内容 |
|
||||
|---|---|---|
|
||||
| `weather_laundry_notification` | Cron(`WEATHER_NOTIFY_HOUR:MINUTE`) | 明日の天気と洗濯指数を Webhook で投稿 |
|
||||
| `useless_tips` | Interval(`USELESS_TIPS_INTERVAL_HOURS`) | どうでもいい Tips を Webhook で投稿(3時台のみ抑制) |
|
||||
| `discord_reminders` | Interval(`REMINDER_CHECK_INTERVAL_SECONDS`) | 期限を過ぎたリマインドを配信 |
|
||||
|
||||
#### リマインド(`core/discord/reminders.py`)
|
||||
|
||||
一回きりのリマインドのみを扱う(繰り返しには非対応)。
|
||||
|
||||
- **登録**: LLM に `create_reminder` / `list_reminders` / `cancel_reminder` の 3 ツールを渡し、
|
||||
自然言語から日時と用件を取り出させる。system メッセージに現在時刻と曜日を入れてあるので、
|
||||
『明日』『30分後』といった相対表現はモデル側が絶対日時に直す。使うモデルは
|
||||
`REMINDER_MODEL` →`WEATHER_NOTIFY_MODEL` → `DEFAULT_MODEL` の順にフォールバックするが、
|
||||
**tool calling 対応モデルでないと動かない**(非対応時はエラー文を返す)
|
||||
- **バリデーション**: 過去・`REMINDER_MAX_AHEAD_DAYS` より先・解釈不能な日時はツール結果として
|
||||
エラー文をモデルに返し、モデルに聞き直させる
|
||||
- **配信先**: Webhook ではなく Bot クライアントから、登録されたチャンネルへ依頼者をメンションして投稿する。
|
||||
そのため専用の Webhook URL 設定は要らない
|
||||
- **タイムゾーン**: DB は他テーブルと同じく UTC。ユーザーおよび LLM とのやり取りはすべて
|
||||
このマシンのローカル時刻で行い、`reminders.py` の境界で変換する
|
||||
- **配信の失敗**: チャンネル削除などで送れない場合はプロセス内カウンタで数え、5 回失敗したら
|
||||
`notified_at` を立てて諦める(毎回エラーログを出し続けるのを防ぐ)。カウンタは DB に持たないので
|
||||
バックエンドを再起動すればまた試す
|
||||
- **バックエンド停止中に期限を迎えた分**: 起動して Bot が ready になった直後にまとめて配信される
|
||||
|
||||
---
|
||||
|
||||
## フロントエンド
|
||||
|
||||
Reference in New Issue
Block a user