## Summary 本 issue 作为 umbrella 跟踪“通知报告渲染体验 2.0”。目标不是重做报告样式,也不是把完整报告默认替换成摘要,而是在保留当前推送报告内容结构和样式骨架的前提下,参考 `hermes-agent` 的平台适配经验,增加渠道感知的格式化与分片能力,让同一份完整报告在飞书、企业微信、Telegram、Slack、邮件、Discord、Custom Webhook 等不同渠道里都尽量好看、可读、稳定。 默认策略: - 默认继续发送完整报告。 - 默认不改变现有通知渠道选择、路由、降噪、图片 opt-in 语义。 - 飞书、企业微信作为优先验收渠道,但设计目标是全渠道适配。 - Web 报告链接、飞书云文档、图片快照都作为可选增强,不替代默认报告正文。 - 如果没有可访问的 Web base URL,不生成 report URL;尤其不能生成误导性的 `localhost` / `127.0.0.1` 链接。 - 渲染、分片、artifact 创建或发送失败时,必须回退现有文本 / 分片路径,不影响主分析流程和其他渠道。 ## Current Baseline - `NotificationService` 已支持企业微信、飞书、Telegram、邮件、PushPlus、Server酱、ntfy、Gotify、Discord、Slack、Custom Webhook、AstrBot 等多渠道发送。 - 企业微信聚合报告已走 `generate_wechat_dashboard()` / `templates/report_wechat.j2` 精简 dashboard。 - 飞书当前使用 `interactive` card + `lark_md`,并通过 `format_feishu_markdown()` 做标题、引用、分割线、表格的基础降级。 - 飞书超长内容按 `FEISHU_MAX_BYTES` 分片发送;企业微信按 `WECHAT_MAX_BYTES` / `WECHAT_MSG_TYPE` 分片发送。 - `MARKDOWN_TO_IMAGE_CHANNELS` 已支持 telegram、wechat、custom、email、slack,失败时回退文本。 - `src/feishu_doc.py` 已有飞书云文档创建能力,但尚未成为通知渲染链路的一等 artifact provider。 - Web 历史报告可以查看 Markdown,但通知中不能假设一定存在可访问公网/内网 URL。 ## Hermes Lessons To Borrow - **平台能力 profile**:像 `hermes-agent` 的平台默认配置一样,把每个渠道支持的 Markdown 类型、长度限制、是否支持 card/image/file/link、是否适合完整报告等能力沉淀为代码真源。 - **平台 formatter**:像 Hermes 的 `format_message()` 一样,每个平台负责把通用 Markdown 转成自己的安全子集,例如飞书 `lark_md`、Slack mrkdwn、Telegram MarkdownV2、Email HTML。 - **结构感知分片**:像 Hermes 的 `truncate_message()` 一样,分片时保留 fenced code、inline code、链接、段落、列表和分页标记,不切坏 Markdown。 - **表格降级策略**:对不适合 pipe table 的 IM 渠道,把表格降级成移动端可读的 key-value / bullet group,而不是让用户看到难读的管道表格。 - **分层 fallback**:format failure、chunk failure、artifact failure、delivery failure 应能区分记录,并回退到 legacy 文本发送。 ## Scope - 保留当前报告章节、标题层级、信号/结论顺序、个股信息密度和核心字段。 - 建立 `ChannelProfile` / `NotificationChannelCapability`,覆盖所有已支持通知渠道。 - 建立 `PreparedMessage` 或等价结构,表达某渠道的 text/card/fallback/attachment 准备结果,但不改变报告语义。 - 引入结构感知 chunker,替换易切坏 Markdown 的简单字节/字符分片。 - 逐渠道优化飞书、企业微信、Telegram、Slack、Email 等报告渲染效果。 - 可选附加 Web report URL,但只有配置了可访问 base URL 且能拿到历史记录时才生成。 - 可选生成飞书云文档,不替代默认飞书消息。 - 图片快照继续 opt-in,不作为长报告默认载体。 ## Non-goals - 不大爆炸式重写 `NotificationService`。 - 不替代通知路由、降噪和长尾渠道治理。 - 不把默认完整报告改成 summary-only。 - 不为了某个渠道大改所有渠道的报告结构。 - 不默认把长报告转成长图。 - 不强制飞书云文档。 - 不在 README 扩写细节;细节进入 `docs/notifications.md`、`docs/full-guide.md` / `docs/full-guide_EN.md` 或专题文档。 - Bot 命令 ack / progress / final status 属于交互体验,应另开 sibling issue。 ## Phases ### Phase 1:渠道适配层与现有样式保真 目标:先建立“不大改报告样式”的技术边界,让同一份完整报告在不同渠道经过各自 formatter 后仍保持当前风格。 - 新增 `ChannelProfile` / `NotificationChannelCapability`: - Markdown 类型:markdown、lark_md、mrkdwn、HTML、plain text。 - 单条长度 / 字节限制。 - 是否支持 card、image、file、link。 - 默认投递策略:full report、wechat dashboard、HTML、plain fallback 等。 - 新增 `PreparedMessage` 或等价结构: - `text` - `formatted_text` - `card_payload` - `fallback_text` - `attachments` - `diagnostics` - 新增结构感知 chunker: - 保留 fenced code、inline code、链接、段落、列表边界。 - 支持字节、字符、UTF-16 等不同计长方式。 - 分页标记稳定,不破坏 Markdown。 - 准备 golden fixtures: - 聚合日报。 - 单股报告。 - 大盘复盘。 - 包含表格、长链接、代码块、emoji、中英文混排的报告样例。 建议 PR: - `feat: add notification channel profiles and prepared messages` - `fix: preserve report formatting when chunking notifications` ### Phase 2:全渠道报告格式化优化 目标:不同渠道都好看,但每个渠道只做“适配性美化”,不重写报告内容。 - 飞书: - 保留现有报告章节顺序。 - 优化 `lark_md` 标题、引用、分割线、列表渲染。 - 表格降级为移动端可读的短列表 / key-value 块。 - 长报告继续按结构感知 chunker 分片。 - 如使用 card,也必须保持报告结构,不默认替换成摘要卡。 - 企业微信: - 保留 `templates/report_wechat.j2` / `generate_wechat_dashboard()` 的 dashboard 风格。 - 优化间距、分隔、Top 项展示和风险提示。 - `MARKDOWN_TO_IMAGE_CHANNELS=wechat` 仍只在显式配置时生效。 - Telegram: - 引入 MarkdownV2 或更安全的 Markdown 转换。 - 按 Telegram UTF-16 计长。 - 表格转列表,避免管道表格在移动端不可读。 - Slack: - 标准 Markdown 转 mrkdwn。 - Block Kit section 分块不切断段落 / 链接 / 表格。 - Email: - 继续作为完整 HTML 高保真载体。 - 不被 IM 渲染策略降级。 - Discord / Custom Webhook / ntfy / Gotify / PushPlus / Server酱 / AstrBot: - 保持现有文本内容。 - 应用安全分片和最小格式清洗。 - 不额外引入渠道特定大改。 建议 PR: - `fix: improve Feishu report markdown rendering` - `fix: polish WeChat report dashboard formatting` - `fix: improve Telegram report markdown rendering` - `fix: improve Slack report markdown rendering` ### Phase 3:可选增强:链接、文档、诊断 目标:在报告本身已经稳定可读后,再补“完整报告入口”和“为什么这个渠道这样展示”。 - `ReportUrlResolver`: - 只有存在历史记录 ID 和可访问 base URL 时才生成 report URL。 - 不生成 `localhost` / `127.0.0.1` 误导链接。 - CLI / schedule / GitHub Actions 无可访问 URL 时,不影响原报告正文。 - 如新增配置项,同步 `.env.example`、配置文档、Web 设置帮助和 changelog。 - 飞书云文档: - 作为可选 artifact provider。 - `FEISHU_WEBHOOK_URL` 继续负责群消息。 - `FEISHU_APP_ID` / `FEISHU_APP_SECRET` / `FEISHU_FOLDER_TOKEN` 负责文档 artifact。 - 文档创建失败不影响默认飞书消息。 - 诊断: - `--check-notify` 说明各渠道当前 formatter、chunker、图片、链接、云文档状态。 - 日志区分 format failure、chunk failure、artifact failure、delivery failure、fallback success。 建议 PR: - `feat: attach optional report links to notifications` - `feat: add optional Feishu document report artifact` - `feat: explain notification report rendering modes` ## Acceptance Criteria - [ ] 默认仍发送完整报告,不默认切换为 summary-only。 - [ ] 飞书、企业微信、Telegram、Slack、Email 等主要渠道均有渠道适配后的可读报告。 - [ ] 当前报告的章节、标题层级、信号/结论顺序和核心字段保持稳定。 - [ ] 结构感知 chunker 不切坏 fenced code、inline code、链接、段落、列表和分页标记。 - [ ] 飞书 / Telegram 等不适合 pipe table 的渠道能把表格降级为可读列表。 - [ ] Email 保留完整 HTML 高保真体验。 - [ ] 未配置可访问 Web base URL 时不会生成 report URL。 - [ ] 飞书云文档和图片快照均为可选能力,不影响默认消息。 - [ ] 单一渠道渲染或发送失败不影响其他渠道和主流程。 - [ ] docs、`.env.example`、Web 设置帮助、`docs/CHANGELOG.md` 随用户可见变更同步。 - [ ] 每个 PR 使用 `Refs #1311`,不要用单个阶段 PR 关闭 umbrella issue。 ## Test Plan - Formatter / chunker unit tests:覆盖飞书、企业微信、Telegram、Slack、Email 和通用文本渠道。 - Golden fixture tests:聚合日报、单股报告、大盘复盘、表格、长链接、代码块、emoji、中英文混排。 - Feishu tests:`lark_md` 格式化、表格降级、分片、plain fallback。 - WeChat tests:dashboard 模板、markdown/text 分片、图片 opt-in 和超限回退。 - Telegram tests:MarkdownV2、UTF-16 计长、表格转列表、plain fallback。 - Slack tests:mrkdwn 转换、Block Kit section 安全分块、Webhook/Bot 差异。 - Email tests:完整 HTML 仍能渲染表格、列表、引用和代码块。 - Docs:`git diff --check`,确认 `docs/CHANGELOG.md` `[Unreleased]` 保持扁平格式。 - Backend:风险较高或触及共享发送路径时运行 `./scripts/ci_gate.sh`。 - Web:若改 Web 设置页或 report URL 配置,运行 `cd apps/dsa-web && npm ci && npm run lint && npm run build`。 ## Progress | Phase | 状态 | PR | 说明 | | --- | --- | --- | --- | | Baseline | 已存在 | - | 多渠道发送、企业微信 dashboard、飞书 `lark_md`、Markdown 转图片、飞书云文档雏形 | | Related | 已关闭 | [#1200](https://github.com/ZhuLinsen/daily_stock_analysis/issues/1200) | 通知渠道网关:测试、路由、降噪、长尾渠道 | | Related | Open | [#1202](https://github.com/ZhuLinsen/daily_stock_analysis/issues/1202) | 实时告警中心会复用通知投递能力 | | Phase 1 | 未开始 | - | 渠道 profile、PreparedMessage、结构感知 chunker、golden fixtures | | Phase 2 | 未开始 | - | 飞书、企业微信、Telegram、Slack、Email 等渠道格式化优化 | | Phase 3 | 未开始 | - | 可选 report URL、飞书云文档、诊断说明 |
Summary
本 issue 作为 umbrella 跟踪“通知报告渲染体验 2.0”。目标不是重做报告样式,也不是把完整报告默认替换成摘要,而是在保留当前推送报告内容结构和样式骨架的前提下,参考
hermes-agent的平台适配经验,增加渠道感知的格式化与分片能力,让同一份完整报告在飞书、企业微信、Telegram、Slack、邮件、Discord、Custom Webhook 等不同渠道里都尽量好看、可读、稳定。默认策略:
localhost/127.0.0.1链接。Current Baseline
NotificationService已支持企业微信、飞书、Telegram、邮件、PushPlus、Server酱、ntfy、Gotify、Discord、Slack、Custom Webhook、AstrBot 等多渠道发送。generate_wechat_dashboard()/templates/report_wechat.j2精简 dashboard。interactivecard +lark_md,并通过format_feishu_markdown()做标题、引用、分割线、表格的基础降级。FEISHU_MAX_BYTES分片发送;企业微信按WECHAT_MAX_BYTES/WECHAT_MSG_TYPE分片发送。MARKDOWN_TO_IMAGE_CHANNELS已支持 telegram、wechat、custom、email、slack,失败时回退文本。src/feishu_doc.py已有飞书云文档创建能力,但尚未成为通知渲染链路的一等 artifact provider。Hermes Lessons To Borrow
hermes-agent的平台默认配置一样,把每个渠道支持的 Markdown 类型、长度限制、是否支持 card/image/file/link、是否适合完整报告等能力沉淀为代码真源。format_message()一样,每个平台负责把通用 Markdown 转成自己的安全子集,例如飞书lark_md、Slack mrkdwn、Telegram MarkdownV2、Email HTML。truncate_message()一样,分片时保留 fenced code、inline code、链接、段落、列表和分页标记,不切坏 Markdown。Scope
ChannelProfile/NotificationChannelCapability,覆盖所有已支持通知渠道。PreparedMessage或等价结构,表达某渠道的 text/card/fallback/attachment 准备结果,但不改变报告语义。Non-goals
NotificationService。docs/notifications.md、docs/full-guide.md/docs/full-guide_EN.md或专题文档。Phases
Phase 1:渠道适配层与现有样式保真
目标:先建立“不大改报告样式”的技术边界,让同一份完整报告在不同渠道经过各自 formatter 后仍保持当前风格。
ChannelProfile/NotificationChannelCapability:PreparedMessage或等价结构:textformatted_textcard_payloadfallback_textattachmentsdiagnostics建议 PR:
feat: add notification channel profiles and prepared messagesfix: preserve report formatting when chunking notificationsPhase 2:全渠道报告格式化优化
目标:不同渠道都好看,但每个渠道只做“适配性美化”,不重写报告内容。
lark_md标题、引用、分割线、列表渲染。templates/report_wechat.j2/generate_wechat_dashboard()的 dashboard 风格。MARKDOWN_TO_IMAGE_CHANNELS=wechat仍只在显式配置时生效。建议 PR:
fix: improve Feishu report markdown renderingfix: polish WeChat report dashboard formattingfix: improve Telegram report markdown renderingfix: improve Slack report markdown renderingPhase 3:可选增强:链接、文档、诊断
目标:在报告本身已经稳定可读后,再补“完整报告入口”和“为什么这个渠道这样展示”。
ReportUrlResolver:localhost/127.0.0.1误导链接。.env.example、配置文档、Web 设置帮助和 changelog。FEISHU_WEBHOOK_URL继续负责群消息。FEISHU_APP_ID/FEISHU_APP_SECRET/FEISHU_FOLDER_TOKEN负责文档 artifact。--check-notify说明各渠道当前 formatter、chunker、图片、链接、云文档状态。建议 PR:
feat: attach optional report links to notificationsfeat: add optional Feishu document report artifactfeat: explain notification report rendering modesAcceptance Criteria
.env.example、Web 设置帮助、docs/CHANGELOG.md随用户可见变更同步。Refs #1311,不要用单个阶段 PR 关闭 umbrella issue。Test Plan
lark_md格式化、表格降级、分片、plain fallback。git diff --check,确认docs/CHANGELOG.md[Unreleased]保持扁平格式。./scripts/ci_gate.sh。cd apps/dsa-web && npm ci && npm run lint && npm run build。Progress
lark_md、Markdown 转图片、飞书云文档雏形