Skip to content

Commit b9efa2d

Browse files
committed
feat: add notification noise controls
1 parent 6c5a17a commit b9efa2d

24 files changed

Lines changed: 1193 additions & 9 deletions

.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,15 @@ AGENT_SKILLS=
483483
# NOTIFICATION_ALERT_CHANNELS=
484484
# NOTIFICATION_SYSTEM_ERROR_CHANNELS=
485485
#
486+
# 【通知降噪机制】(Issue #1200 P4)
487+
# 默认全部关闭;仅影响静态通知渠道,不影响机器人触发会话回执。
488+
# NOTIFICATION_DEDUP_TTL_SECONDS=0 # 同一稳定去重 key 在 TTL 内只发送一次;0 关闭
489+
# NOTIFICATION_COOLDOWN_SECONDS=0 # 同一冷却 key 在窗口内限频;0 关闭
490+
# NOTIFICATION_QUIET_HOURS= # 静默时段,格式 HH:MM-HH:MM,支持跨午夜
491+
# NOTIFICATION_TIMEZONE= # 静默时段时区,如 Asia/Shanghai;留空跟随 TZ/系统本地时区
492+
# NOTIFICATION_MIN_SEVERITY= # info,warning,error,critical;留空保持现状
493+
# NOTIFICATION_DAILY_DIGEST_ENABLED=false # 预留配置;当前不会发送每日摘要
494+
#
486495
# 【实时行情预取】(Issue #455)
487496
# PREFETCH_REALTIME_QUOTES=true # 设为 false 可禁用,避免 efinance/akshare_em 全市场拉取;tushare 为单股接口,预取仅拉首股
488497

.github/workflows/daily_analysis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,12 @@ jobs:
324324
NOTIFICATION_REPORT_CHANNELS: ${{ vars.NOTIFICATION_REPORT_CHANNELS || secrets.NOTIFICATION_REPORT_CHANNELS }}
325325
NOTIFICATION_ALERT_CHANNELS: ${{ vars.NOTIFICATION_ALERT_CHANNELS || secrets.NOTIFICATION_ALERT_CHANNELS }}
326326
NOTIFICATION_SYSTEM_ERROR_CHANNELS: ${{ vars.NOTIFICATION_SYSTEM_ERROR_CHANNELS || secrets.NOTIFICATION_SYSTEM_ERROR_CHANNELS }}
327+
NOTIFICATION_DEDUP_TTL_SECONDS: ${{ vars.NOTIFICATION_DEDUP_TTL_SECONDS || secrets.NOTIFICATION_DEDUP_TTL_SECONDS || '0' }}
328+
NOTIFICATION_COOLDOWN_SECONDS: ${{ vars.NOTIFICATION_COOLDOWN_SECONDS || secrets.NOTIFICATION_COOLDOWN_SECONDS || '0' }}
329+
NOTIFICATION_QUIET_HOURS: ${{ vars.NOTIFICATION_QUIET_HOURS || secrets.NOTIFICATION_QUIET_HOURS }}
330+
NOTIFICATION_TIMEZONE: ${{ vars.NOTIFICATION_TIMEZONE || secrets.NOTIFICATION_TIMEZONE }}
331+
NOTIFICATION_MIN_SEVERITY: ${{ vars.NOTIFICATION_MIN_SEVERITY || secrets.NOTIFICATION_MIN_SEVERITY }}
332+
NOTIFICATION_DAILY_DIGEST_ENABLED: ${{ vars.NOTIFICATION_DAILY_DIGEST_ENABLED || secrets.NOTIFICATION_DAILY_DIGEST_ENABLED || 'false' }}
327333

328334
# ==========================================
329335
# 自选股配置

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1515
- [新功能] Web 系统设置页开放 `.env` 配置备份导入/导出,复用键级覆盖、配置版本冲突保护和重载链路;Web 端在 `ADMIN_AUTH_ENABLED=false` 时该入口为禁用状态。
1616
- [chore] 精简仓库根目录:将文档图片资源迁入 `docs/assets/`,将东方财富请求补丁迁入 `src/patches/`,并下移 CI 专用依赖文件与技能适配服务。
1717
- [文档] 更新多语言 README 首页浅色工作台 GIF,并精简功能特性表,保留原有赞助商、快速开始和推送效果结构。
18+
- [新功能] 通知网关新增默认关闭的进程内降噪配置,支持去重、冷却、静默时段和最低严重级别,并将每日摘要开关标记为预留能力。
1819

1920
## [3.16.0] - 2026-05-10
2021

docs/full-guide.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ daily_stock_analysis/
102102

103103
> *注:至少配置一个渠道,配置多个则同时推送
104104
>
105-
> 当前默认 `daily_analysis.yml` 只显式映射固定 Secret / Variable 名称,不会自动把 `STOCK_GROUP_1``EMAIL_GROUP_1` 这类任意编号变量导入运行环境。所以分组邮箱功能目前不适用于仓库自带默认 GitHub Actions workflow;它适用于本地 `.env`、Docker,或你自行显式扩展过 `env:` 映射的运行环境。Actions 已显式映射 `CUSTOM_WEBHOOK_BODY_TEMPLATE``WEBHOOK_VERIFY_SSL``FEISHU_WEBHOOK_SECRET``FEISHU_WEBHOOK_KEYWORD``PUSHPLUS_TOPIC` 以及 P3 通知路由键`MARKDOWN_TO_IMAGE_CHANNELS``MERGE_EMAIL_NOTIFICATION` 仍作为行为开关不在默认 workflow 中自动映射。
105+
> 当前默认 `daily_analysis.yml` 只显式映射固定 Secret / Variable 名称,不会自动把 `STOCK_GROUP_1``EMAIL_GROUP_1` 这类任意编号变量导入运行环境。所以分组邮箱功能目前不适用于仓库自带默认 GitHub Actions workflow;它适用于本地 `.env`、Docker,或你自行显式扩展过 `env:` 映射的运行环境。Actions 已显式映射 `CUSTOM_WEBHOOK_BODY_TEMPLATE``WEBHOOK_VERIFY_SSL``FEISHU_WEBHOOK_SECRET``FEISHU_WEBHOOK_KEYWORD``PUSHPLUS_TOPIC`、P3 通知路由键以及 P4 通知降噪键`MARKDOWN_TO_IMAGE_CHANNELS``MERGE_EMAIL_NOTIFICATION` 仍作为行为开关不在默认 workflow 中自动映射。
106106
107107
#### 推送行为配置
108108

@@ -123,6 +123,12 @@ daily_stock_analysis/
123123
| `NOTIFICATION_REPORT_CHANNELS` | report 路由渠道(单股推送、聚合日报、大盘复盘、合并推送等);留空表示所有已配置渠道 | 可选 |
124124
| `NOTIFICATION_ALERT_CHANNELS` | alert 路由渠道(EventMonitor 告警);留空表示所有已配置渠道 | 可选 |
125125
| `NOTIFICATION_SYSTEM_ERROR_CHANNELS` | system_error 预留路由渠道;当前不新增自动系统错误生产者,留空表示所有已配置渠道 | 可选 |
126+
| `NOTIFICATION_DEDUP_TTL_SECONDS` | 通知去重 TTL 秒数,`0` 关闭;同一稳定去重 key 在 TTL 内只发送一次 | 可选 |
127+
| `NOTIFICATION_COOLDOWN_SECONDS` | 通知冷却秒数,`0` 关闭;同一冷却 key 在窗口内限频 | 可选 |
128+
| `NOTIFICATION_QUIET_HOURS` | 通知静默时段,格式 `HH:MM-HH:MM`,支持跨午夜;留空关闭 | 可选 |
129+
| `NOTIFICATION_TIMEZONE` | 静默时段使用的 IANA 时区,如 `Asia/Shanghai`;留空跟随 `TZ` 或系统本地时区 | 可选 |
130+
| `NOTIFICATION_MIN_SEVERITY` | 最低通知级别:`info``warning``error``critical`;留空保持现状 | 可选 |
131+
| `NOTIFICATION_DAILY_DIGEST_ENABLED` | 每日摘要预留开关;当前不会发送摘要或持久化摘要内容 | 可选 |
126132
| `MARKDOWN_TO_IMAGE_MAX_CHARS` | 超过此长度不转图片,避免超大图片(默认 15000) | 可选 |
127133
| `MD2IMG_ENGINE` | 转图引擎:`wkhtmltoimage`(默认,需 wkhtmltopdf)或 `markdown-to-file`(emoji 更好,需 `npm i -g markdown-to-file`| 可选 |
128134
| `PREFETCH_REALTIME_QUOTES` | 设为 `false` 可禁用实时行情预取,避免 efinance/akshare_em 全市场拉取(默认 true) | 可选 |
@@ -258,6 +264,12 @@ daily_stock_analysis/
258264
| `NOTIFICATION_REPORT_CHANNELS` | report 路由渠道,逗号分隔;允许值:wechat,feishu,telegram,email,pushover,pushplus,serverchan3,custom,discord,slack,astrbot | 可选 |
259265
| `NOTIFICATION_ALERT_CHANNELS` | alert 路由渠道,逗号分隔;留空保持全渠道 | 可选 |
260266
| `NOTIFICATION_SYSTEM_ERROR_CHANNELS` | system_error 预留路由渠道,逗号分隔;留空保持全渠道 | 可选 |
267+
| `NOTIFICATION_DEDUP_TTL_SECONDS` | 通知去重 TTL 秒数,`0` 关闭 | 可选 |
268+
| `NOTIFICATION_COOLDOWN_SECONDS` | 通知冷却秒数,`0` 关闭 | 可选 |
269+
| `NOTIFICATION_QUIET_HOURS` | 静默时段,格式 `HH:MM-HH:MM`,支持跨午夜 | 可选 |
270+
| `NOTIFICATION_TIMEZONE` | 静默时段时区,如 `Asia/Shanghai`;留空跟随 `TZ` 或系统本地时区 | 可选 |
271+
| `NOTIFICATION_MIN_SEVERITY` | 最低通知级别:info, warning, error, critical;留空保持现状 | 可选 |
272+
| `NOTIFICATION_DAILY_DIGEST_ENABLED` | 每日摘要预留开关;当前不会发送摘要 | 可选 |
261273

262274
> 说明:默认 `daily_analysis` GitHub Actions workflow 只映射固定变量名,不会自动导入任意编号的 `STOCK_GROUP_N` / `EMAIL_GROUP_N`。因此分组邮箱目前仅在本地 `.env`、Docker 或其他已显式注入这些环境变量的运行环境中生效;若你要在自己的 GitHub Actions 中使用,需在 workflow 的 job `env:` 中逐组显式映射。
263275

docs/full-guide_EN.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Go to your forked repo → `Settings` → `Secrets and variables` → `Actions`
103103

104104
> *Note: Configure at least one channel; multiple channels will all receive notifications
105105
>
106-
> The default `daily_analysis.yml` in this repository only exports fixed Secret / Variable names. Arbitrary numbered env vars such as `STOCK_GROUP_1` and `EMAIL_GROUP_1` are not auto-injected into the job, so grouped email routing is not available in the stock workflow unless you explicitly extend the workflow's `env:` mapping in your own fork. Actions now maps `CUSTOM_WEBHOOK_BODY_TEMPLATE`, `WEBHOOK_VERIFY_SSL`, `FEISHU_WEBHOOK_SECRET`, `FEISHU_WEBHOOK_KEYWORD`, `PUSHPLUS_TOPIC`, and the P3 notification route keys; `MARKDOWN_TO_IMAGE_CHANNELS` and `MERGE_EMAIL_NOTIFICATION` remain behavior toggles outside the default workflow mapping.
106+
> The default `daily_analysis.yml` in this repository only exports fixed Secret / Variable names. Arbitrary numbered env vars such as `STOCK_GROUP_1` and `EMAIL_GROUP_1` are not auto-injected into the job, so grouped email routing is not available in the stock workflow unless you explicitly extend the workflow's `env:` mapping in your own fork. Actions now maps `CUSTOM_WEBHOOK_BODY_TEMPLATE`, `WEBHOOK_VERIFY_SSL`, `FEISHU_WEBHOOK_SECRET`, `FEISHU_WEBHOOK_KEYWORD`, `PUSHPLUS_TOPIC`, the P3 notification route keys, and the P4 notification noise-control keys; `MARKDOWN_TO_IMAGE_CHANNELS` and `MERGE_EMAIL_NOTIFICATION` remain behavior toggles outside the default workflow mapping.
107107
108108
#### Push Behavior Configuration
109109

@@ -121,6 +121,12 @@ Go to your forked repo → `Settings` → `Secrets and variables` → `Actions`
121121
| `NOTIFICATION_REPORT_CHANNELS` | Report route channels for single-stock, aggregate daily, market review, merged push, and Feishu document success notifications. Empty means all configured channels | Optional |
122122
| `NOTIFICATION_ALERT_CHANNELS` | Alert route channels for EventMonitor notifications. Empty means all configured channels | Optional |
123123
| `NOTIFICATION_SYSTEM_ERROR_CHANNELS` | Reserved system_error route channels. No automatic system error producer is added in P3; empty means all configured channels | Optional |
124+
| `NOTIFICATION_DEDUP_TTL_SECONDS` | Dedup TTL in seconds. `0` disables dedup; the same stable dedup key sends only once within the TTL | Optional |
125+
| `NOTIFICATION_COOLDOWN_SECONDS` | Cooldown window in seconds. `0` disables cooldown; the same cooldown key is rate-limited within the window | Optional |
126+
| `NOTIFICATION_QUIET_HOURS` | Quiet-hours window in `HH:MM-HH:MM` format, supports overnight ranges. Empty disables quiet hours | Optional |
127+
| `NOTIFICATION_TIMEZONE` | IANA timezone for quiet hours, e.g. `Asia/Shanghai`. Empty follows `TZ` or the local system timezone | Optional |
128+
| `NOTIFICATION_MIN_SEVERITY` | Minimum severity: `info`, `warning`, `error`, `critical`. Empty keeps current behavior | Optional |
129+
| `NOTIFICATION_DAILY_DIGEST_ENABLED` | Reserved daily digest flag. The current implementation does not send or persist digests | Optional |
124130

125131
#### Other Configuration
126132

@@ -233,6 +239,12 @@ For the P0 notification baseline and diagnostics, see [Notification Baseline](no
233239
| `NOTIFICATION_REPORT_CHANNELS` | Report route channels, comma-separated. Allowed values: wechat,feishu,telegram,email,pushover,pushplus,serverchan3,custom,discord,slack,astrbot | Optional |
234240
| `NOTIFICATION_ALERT_CHANNELS` | Alert route channels, comma-separated. Empty keeps all configured channels | Optional |
235241
| `NOTIFICATION_SYSTEM_ERROR_CHANNELS` | Reserved system_error route channels, comma-separated. Empty keeps all configured channels | Optional |
242+
| `NOTIFICATION_DEDUP_TTL_SECONDS` | Dedup TTL in seconds. `0` disables dedup | Optional |
243+
| `NOTIFICATION_COOLDOWN_SECONDS` | Cooldown window in seconds. `0` disables cooldown | Optional |
244+
| `NOTIFICATION_QUIET_HOURS` | Quiet-hours window in `HH:MM-HH:MM` format, supports overnight ranges | Optional |
245+
| `NOTIFICATION_TIMEZONE` | Quiet-hours timezone, e.g. `Asia/Shanghai`; empty follows `TZ` or local system timezone | Optional |
246+
| `NOTIFICATION_MIN_SEVERITY` | Minimum severity: info, warning, error, critical. Empty keeps current behavior | Optional |
247+
| `NOTIFICATION_DAILY_DIGEST_ENABLED` | Reserved daily digest flag. It does not send digests yet | Optional |
236248

237249
> Note: the default `daily_analysis` GitHub Actions workflow only maps fixed variable names. It does not automatically import arbitrary numbered variables such as `STOCK_GROUP_N` / `EMAIL_GROUP_N`. This feature therefore works in local `.env`, Docker, or any runtime where you explicitly inject those variables.
238250

docs/notifications.md

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 通知能力基线
22

3-
本文档记录通知能力 P0-P3 基线:渠道、配置 key、GitHub Actions 映射、Web 设置元数据、CLI 诊断口径、Web 一键测试、自定义 Webhook Body 模板语义和通知路由策略。P0 只做基线与只读诊断;P1 增加 Web 单渠道真实测试;P2 产品化现有 Body 模板;P3 增加 report / alert / system_error 路由,不包含降噪、per-URL 模板或新增一等渠道
3+
本文档记录通知能力 P0-P4 基线:渠道、配置 key、GitHub Actions 映射、Web 设置元数据、CLI 诊断口径、Web 一键测试、自定义 Webhook Body 模板语义、通知路由策略和降噪机制。P0 只做基线与只读诊断;P1 增加 Web 单渠道真实测试;P2 产品化现有 Body 模板;P3 增加 report / alert / system_error 路由;P4 增加进程内降噪,不包含 per-URL 模板、跨进程持久化、真实每日摘要或新增一等渠道
44

55
## 渠道基线
66

@@ -26,7 +26,8 @@
2626
- Minimal key:足以启用一个通知渠道的最小配置。
2727
- Advanced key:只影响认证、安全、格式、线程、群组、证书校验或展示行为,不能单独启用渠道。
2828
- P3 的 `NOTIFICATION_*_CHANNELS` 属于 Advanced key:只收窄已启用渠道,不会单独启用渠道。
29-
- 降噪、长尾渠道和更细粒度路由不在 P3 范围内;相关配置如未来引入,应先更新本文档、`.env.example`、Web 元数据与回归测试。
29+
- P4 的 `NOTIFICATION_DEDUP_TTL_SECONDS``NOTIFICATION_COOLDOWN_SECONDS``NOTIFICATION_QUIET_HOURS``NOTIFICATION_TIMEZONE``NOTIFICATION_MIN_SEVERITY``NOTIFICATION_DAILY_DIGEST_ENABLED` 属于 Advanced key:只影响已启用静态渠道的发送策略,不会单独启用渠道。
30+
- 长尾渠道、更细粒度路由、跨进程降噪和真实每日摘要不在 P4 范围内;相关配置如未来引入,应先更新本文档、`.env.example`、Web 元数据与回归测试。
3031

3132
## GitHub Actions 映射
3233

@@ -44,6 +45,15 @@ P3 补齐以下通知路由映射:
4445
- `NOTIFICATION_ALERT_CHANNELS`
4546
- `NOTIFICATION_SYSTEM_ERROR_CHANNELS`
4647

48+
P4 补齐以下通知降噪映射:
49+
50+
- `NOTIFICATION_DEDUP_TTL_SECONDS`
51+
- `NOTIFICATION_COOLDOWN_SECONDS`
52+
- `NOTIFICATION_QUIET_HOURS`
53+
- `NOTIFICATION_TIMEZONE`
54+
- `NOTIFICATION_MIN_SEVERITY`
55+
- `NOTIFICATION_DAILY_DIGEST_ENABLED`
56+
4757
默认 workflow 仍不映射 `MARKDOWN_TO_IMAGE_CHANNELS``MERGE_EMAIL_NOTIFICATION`。它们是发送形态或聚合行为开关,不是渠道凭证;在 Actions 中自动开始读取同名 Secret/Variable 会引入额外行为变化。
4858

4959
## CLI 诊断
@@ -126,6 +136,35 @@ P3 新增三类通知路由配置:
126136
- `MERGE_EMAIL_NOTIFICATION` 不需要额外配置;只要 `email` 仍在 report 路由后的渠道中,现有合并邮件行为保持不变。
127137
- `--check-notify` 会把未知渠道值报为 error,把合法但未启用的路由目标报为 warning。
128138

139+
## 通知降噪机制
140+
141+
P4 新增进程内降噪,只影响静态配置渠道,不影响 `send_to_context()` 的机器人触发会话回执。默认所有配置关闭,未设置时保持旧行为。
142+
143+
| 配置 key | 默认值 | 说明 |
144+
| --- | --- | --- |
145+
| `NOTIFICATION_DEDUP_TTL_SECONDS` | `0` | 同一稳定去重 key 在 TTL 内只发送一次;`0` 关闭 |
146+
| `NOTIFICATION_COOLDOWN_SECONDS` | `0` | 同一冷却 key 在窗口内限频;`0` 关闭 |
147+
| `NOTIFICATION_QUIET_HOURS` || 静默时段,格式 `HH:MM-HH:MM`,支持跨午夜 |
148+
| `NOTIFICATION_TIMEZONE` || 静默时段时区,如 `Asia/Shanghai`;留空跟随 `TZ` 或系统本地时区 |
149+
| `NOTIFICATION_MIN_SEVERITY` || `info`, `warning`, `error`, `critical`;留空不过滤 |
150+
| `NOTIFICATION_DAILY_DIGEST_ENABLED` | `false` | 预留配置;当前不会发送每日摘要或持久化摘要内容 |
151+
152+
严重级别默认值:
153+
154+
- `report``info`
155+
- `alert``warning`
156+
- `system_error``error`
157+
- 未知或未设置路由:`info`
158+
159+
实现边界:
160+
161+
- 去重 / 冷却状态是当前 Python 进程内 dict,适用于 `main.py` 单进程和 `--serve` 单 worker。
162+
- `uvicorn --workers N`、多容器或多台机器场景下状态不共享,降噪为 per-worker 近似生效。
163+
- report 路径使用稳定 key,避免报告内生成时间变化击穿去重;单股和聚合报告使用不同 key,避免冷却误伤不同股票。
164+
- 未显式传入 `cooldown_key` 的调用按路由和严重级别共享默认冷却槽位,例如 report / info 的普通通知会共用同一个槽位。
165+
- 降噪判断异常时 fail-open:记录日志并继续发送静态渠道。
166+
- GitHub Actions 默认 UTC;如未设置 `TZ`,静默时段按 Actions 运行环境的本地时区解释。建议在 Actions 中显式配置 `NOTIFICATION_TIMEZONE`
167+
129168
## 场景占位
130169

131170
- Local:优先使用 `.env`,可用 `python main.py --check-notify` 做本地诊断。

0 commit comments

Comments
 (0)