feat(baoyu-wechat-summary): add @bot Q&A section to normal and roast digests

This commit is contained in:
Jim Liu 宝玉
2026-05-29 18:59:26 -05:00
parent 77dd193b58
commit a85c81e8db
5 changed files with 71 additions and 4 deletions
+1 -1
View File
@@ -1128,7 +1128,7 @@ Custom style descriptions are also accepted, e.g., `--style "poetic and lyrical"
#### baoyu-wechat-summary #### baoyu-wechat-summary
Summarize WeChat group chat highlights into a structured digest. Extracts topics, quotes, and stats from group messages using [wx-cli](https://github.com/jackwener/wx-cli). Maintains per-group history and per-user profiles across runs. Supports normal and roast (毒舌) versions. Summarize WeChat group chat highlights into a structured digest. Extracts topics, quotes, and stats from group messages using [wx-cli](https://github.com/jackwener/wx-cli). Maintains per-group history and per-user profiles across runs. Supports normal and roast (毒舌) versions, and answers `@bot` questions raised in the chat.
```bash ```bash
# Summarize a group's recent messages # Summarize a group's recent messages
+1 -1
View File
@@ -1119,7 +1119,7 @@ AI 驱动的生成后端。
#### baoyu-wechat-summary #### baoyu-wechat-summary
微信群聊精华提取。使用 [wx-cli](https://github.com/jackwener/wx-cli) 从群消息中提取话题、引言和统计数据,生成结构化简报。支持跨次运行的群聊历史和群友画像维护,可生成正常版和毒舌版。 微信群聊精华提取。使用 [wx-cli](https://github.com/jackwener/wx-cli) 从群消息中提取话题、引言和统计数据,生成结构化简报。支持跨次运行的群聊历史和群友画像维护,可生成正常版和毒舌版,并在简报中回应群里向 `@bot` 提出的问题
```bash ```bash
# 总结群最近消息 # 总结群最近消息
@@ -31,3 +31,9 @@ default_version: normal
# resolves to `{project_root}/wechat`. Useful if you want a shared archive # resolves to `{project_root}/wechat`. Useful if you want a shared archive
# outside the current project. # outside the current project.
# data_root: ~/Documents/wechat-digests # data_root: ~/Documents/wechat-digests
# OPTIONAL — 触发「🤖 @bot 答疑」小节的名字(逗号分隔)。消息含 @<别名> 即视为
# 冲总结 bot 提的问题/请求,会在每版简报里专门答复。
# 请选用群里【不存在】的人物/机器人名,以免与真人 @ 混淆。
# Default: bot, 精华bot
# bot_aliases: bot, 精华bot
+25
View File
@@ -73,6 +73,7 @@ EXTEND.md is plain text with `key: value` or `key=value` lines, `#` for comments
| `default_version` | `normal` / `roast` / `both` | `normal` | Which version(s) to generate when the user doesn't say otherwise. | | `default_version` | `normal` / `roast` / `both` | `normal` | Which version(s) to generate when the user doesn't say otherwise. |
| `default_time_range` | string (e.g. `7d`, `24h`, `1d`) | (none) | Default range when the user omits time and there's no incremental anchor. | | `default_time_range` | string (e.g. `7d`, `24h`, `1d`) | (none) | Default range when the user omits time and there's no incremental anchor. |
| `data_root` | path | `{project_root}/wechat` | Override where digest folders live. | | `data_root` | path | `{project_root}/wechat` | Override where digest folders live. |
| `bot_aliases` | comma-separated strings | `bot, 精华bot` | Names that trigger the 「@bot 答疑」 section. A message containing `@<alias>` (case-insensitive) is treated as a question/request aimed at the digest bot. Pick names that do NOT match any real group member or existing bot, to avoid ambiguity. |
A starter template lives at [EXTEND.md.example](EXTEND.md.example). A starter template lives at [EXTEND.md.example](EXTEND.md.example).
@@ -239,6 +240,26 @@ If a match is found:
This is a heuristic — when uncertain (multiple matches, malformed title), default to `history.json` and tell the user what was skipped. This is a heuristic — when uncertain (multiple matches, malformed title), default to `history.json` and tell the user what was skipped.
### Step 3.9: Detect @bot requests (if any)
Some group members address the digest bot directly — e.g. `@bot 帮我把昨天的讨论捋一下` or `@精华bot 这个链接讲了啥`. Catch these so each digest can answer them in a dedicated section instead of dropping them as noise.
**Trigger**: a message whose text contains `@<alias>` for any alias in `bot_aliases` (from EXTEND.md; default `bot`, `精华bot`; case-insensitive). Aliases are stored as bare names — match the `@` prefix plus the alias.
**Extract** into an internal worklist `== @bot 请求清单 ==` (working memory only — never written to the final digest):
- Asker's real name — after Step 3.6 resolution; substitute `self_display` for the `self_wxid` user.
- Request body — the text after stripping the `@<alias>` prefix. If the message is a reply (per Step 3.5's quote/reply fields), include the quoted message as context.
- Anchor `local_id` for back-reference.
**Misfire filtering**: if a real member's nickname happens to equal an alias, judge by context. Keep only messages genuinely aimed at the digest bot (a question or request for it); skip clear person-to-person talk — a reply to that real person, or banter teasing them. (Choosing a `bot_aliases` value no real member uses avoids this at the source; the filter is a backstop.) Pure greetings/banter (`@bot 在吗`) may be kept with a brief reply.
**Answer-source constraint** (honored when rendering the section per [references/output-formats.md](references/output-formats.md)): answer from the group chat context plus your own knowledge only — **no web access**. For any request needing real-time or external information you can't verify, say so honestly (`这个我查不到实时数据,需要联网确认`) rather than fabricating.
**No hits** → both versions omit the @bot 答疑 section entirely.
Do this in the same read-through as Round 1's skeleton (via its `== @bot 请求清单 ==` block) so the messages aren't scanned twice.
Generate the digest in three rounds so nothing slips through. The methodology stays here in SKILL.md; the content/style rules live in [references/output-formats.md](references/output-formats.md) — read that file in Round 2 before drafting. Generate the digest in three rounds so nothing slips through. The methodology stays here in SKILL.md; the content/style rules live in [references/output-formats.md](references/output-formats.md) — read that file in Round 2 before drafting.
#### Round 1 — Build the skeleton #### Round 1 — Build the skeleton
@@ -258,6 +279,10 @@ Internal working format (not written to the final file):
== 发言统计 == == 发言统计 ==
1. XXX — N 条 2. YYY — N 条 ... 1. XXX — N 条 2. YYY — N 条 ...
== @bot 请求清单(如有)==
1. {提问者真名}(锚点 id:54080)— {去掉 @别名的请求正文}(reply 时附被回复内容)
(本期无 @bot 请求则写「无」)
``` ```
Topic principles: Topic principles:
@@ -17,6 +17,7 @@ Both versions share the same overall layout and writing rules; the differences a
[群友画像 — one entry per active user (3+ msgs)] [群友画像 — one entry per active user (3+ msgs)]
[Categorized body — 3-6 self-named sections per day] [Categorized body — 3-6 self-named sections per day]
[Optional pain-point section] [Optional pain-point section]
[Optional @bot Q&A section]
[Fixed footer] [Fixed footer]
``` ```
@@ -116,7 +117,23 @@ Example:
``` ```
- Skip the section entirely if there are no genuine pain points — don't pad with trivial questions. - Skip the section entirely if there are no genuine pain points — don't pad with trivial questions.
### 1.8 Footer ### 1.8 @bot 答疑 section (optional)
- 仅当 SKILL.md Step 3.9 本批捕获到至少一条真实 @bot 请求时出现;否则整段省略。
- Heading: `🤖 @bot 答疑`
- 一条请求一个条目(• 请求行 + 缩进的 🤖 答复行)。多人问同一件事合并成一答。
- **请求行措辞自由发挥**:点出提问者真名 + 自然转述其请求即可,别套「X 问:」这类固定句式。
- 语气:真诚、热心、有用的助手——与普通版整体一致。答复落地、给具体建议,别空泛。
- 来源:仅群聊上下文 + 自有知识,不联网。需实时/外部数据又无法核实的,如实说明(`这个我查不到实时数据,需要联网确认`),不编造。
- Format(遵守 §3:不用 markdown、列表用 •、标题一个 emoji):
```
🤖 @bot 答疑
• {提问者 + 自然转述的请求}
🤖 {真诚、简洁、有用的回答;查不到实时信息就如实说明}
```
### 1.9 Footer
Fixed line, last in file: Fixed line, last in file:
@@ -130,7 +147,7 @@ No date, no signature, no version number.
## 2. Roast version (毒舌版) ## 2. Roast version (毒舌版)
Roast 版基于普通版的话题骨架和素材,用毒舌、尖锐、挑衅的风格重写。整体结构与普通版相同(统计区块、开头概览、群友画像、正文分类、结尾),但风格完全不同。痛点部分省略。仅当 `include_roast=true` 时生成。标题加 "毒舌版" 后缀。 Roast 版基于普通版的话题骨架和素材,用毒舌、尖锐、挑衅的风格重写。整体结构与普通版相同(统计区块、开头概览、群友画像、正文分类、@bot 答疑(毒舌值班版,如有)、结尾),但风格完全不同。痛点部分省略。仅当 `include_roast=true` 时生成。标题加 "毒舌版" 后缀。
风格要求: 风格要求:
- 你是一位以尖锐和挑衅风格著称的专业评论员 - 你是一位以尖锐和挑衅风格著称的专业评论员
@@ -140,6 +157,14 @@ Roast 版基于普通版的话题骨架和素材,用毒舌、尖锐、挑衅
- 开头概览用更戏谑的口吻,突出荒诞和讽刺 - 开头概览用更戏谑的口吻,突出荒诞和讽刺
- 正文话题标题可以改得更损 - 正文话题标题可以改得更损
- 引用原话时配上辛辣点评 - 引用原话时配上辛辣点评
- @bot 答疑改为「毒舌值班版」(本批有 @bot 请求时才出现,见 SKILL.md Step 3.9,放结尾前;无则省略):照样把干货答出来,但裹上调侃、嘴硬、吐槽提问者的口吻,与 roast 整体一致;来源同样只用群聊上下文 + 自有知识、不联网,查不到就嘴硬地承认查不到;同守下方红线。请求行措辞自由发挥,用调侃口吻点出提问者和请求即可,别套「又来了」这类固定句式。标题如 `🤖 bot 答疑(毒舌值班版)`,结构示意:
```
🤖 bot 答疑(毒舌值班版)
• {提问者 + 请求,调侃口吻}
🤖 {带刺但仍有实质内容的回答}
```
- 结尾改为:本简报由一个没有感情的 AI 自动生成,如有冒犯,概不负责 - 结尾改为:本简报由一个没有感情的 AI 自动生成,如有冒犯,概不负责
注意:毒舌但不恶毒,调侃但不人身攻击。目标是让群友看了会笑,而不是生气。具体红线: 注意:毒舌但不恶毒,调侃但不人身攻击。目标是让群友看了会笑,而不是生气。具体红线:
@@ -227,6 +252,11 @@ When you forget the structure mid-write, this is the skeleton:
状态: ⚠️ 部分解决 状态: ⚠️ 部分解决
方案: {若有} 方案: {若有}
🤖 @bot 答疑(可选,没有就不写)
• {提问者 + 请求,自然转述}
🤖 {真诚有用的回答}
本简报由 AI 自动生成 本简报由 AI 自动生成
``` ```
@@ -252,6 +282,11 @@ When you forget the structure mid-write, this is the skeleton:
{保留真实引用的毒舌叙述} {保留真实引用的毒舌叙述}
🤖 bot 答疑(毒舌值班版,可选)
• {提问者 + 请求,调侃口吻}
🤖 {带刺但仍有实质的回答}
本简报由一个没有感情的 AI 自动生成,如有冒犯,概不负责 本简报由一个没有感情的 AI 自动生成,如有冒犯,概不负责
``` ```
@@ -271,3 +306,4 @@ Before writing the digest file, mentally walk through:
8. No markdown bold/heading/link syntax leaked through? 8. No markdown bold/heading/link syntax leaked through?
9. (Roast only) Every roast bullet would pass the §2 红线 audit? 9. (Roast only) Every roast bullet would pass the §2 红线 audit?
10. Footer line exact match? 10. Footer line exact match?
11. (本批有 @bot 请求时)两版各有对应 @bot 答疑小节?普通版真诚有用、毒舌版带刺仍有干货?无编造的实时信息?