Reading Digest — 文件夹阅读摘要
通用、可移植的阅读摘要技能。扫描一个用户配置的文件夹,自动解压压缩包、抽取并逐字通读文档全文,产出结构化本地 Markdown 摘要。不硬编码任何路径或密码,全部通过 reading_config.json 注入。
配置(必读,运行前必须准备)
本技能不内置路径与密码。运行前需提供一份 reading_config.json,技能按以下顺序查找:
- 环境变量
READING_DIGEST_CONFIG指向的文件路径; - 技能目录下的
reading_config.json; - 待读文件夹内的
.workbuddy/reading_config.json。
reading_config.json 字段说明:
| 字段 | 必填 | 默认值 | 说明 |
|---|---|---|---|
reading_folder |
是 | — | 待扫描的文件夹绝对路径 |
zip_password |
否 | 空 | 若压缩包为 AES 加密,填解密密码;无加密包可省略 |
summary_subdir |
否 | 摘要 |
摘要输出子目录名(位于 reading_folder 下) |
chunk_char_limit |
否 | 60000 |
单文档全文超过此字符数则切块精读 |
output_local_md |
否 | true |
是否写本地 Markdown 摘要(唯一输出方式) |
技能目录已附 reading_config.example.json 模板,复制改名后填入即可。密码仅存于你本机配置,绝不明文写入技能正文或随技能对外分享。
适用场景
- 用户说「形成摘要」(或上述触发词)即启动:扫描
reading_folder中的新文件并生成摘要。 - 也可针对单个文档做全文精读摘要。
- 纯手动触发,由用户发起;可随时用触发词拉起,不必依赖定时任务。
启动模式(手动触发)
- 「形成摘要」「生成摘要」「跑一次阅读摘要」「现在处理」「手动阅读摘要」→ 处理所有未处理的新文件(先解压压缩包,再逐字通读生成摘要)。
- 「只处理 <文件名>」→ 仅处理指定文件。
- 「重跑 <文件名>」「重新生成 <文件名> 摘要」→ 无视台账 done 状态,强制重新处理该文件(覆盖旧摘要)。
- 「看下还有哪些没处理」→ 只对照台账列出待办清单,不实际处理。
执行第 1–6 步流程;跑完更新台账,下次说「形成摘要」不会重复处理已 done 文件。
关键路径(均来自配置)
- 待读文件夹:
{reading_folder}(忽略子目录{summary_subdir}、隐藏文件、.workbuddy/) - 摘要输出:
{reading_folder}/{summary_subdir}/<原文件名>_摘要.md - 已处理台账:
{reading_folder}/.workbuddy/processed_files.json
依赖
- Python 环境(推荐新建虚拟环境
python3 -m venv .venv && .venv/bin/pip install ...以隔离依赖,避免污染用户全局环境)。按需安装(已固定版本,避免供应链投毒):pip install pyzipper==0.63 pdfplumber==3.3.0 ebooklib==0.18 beautifulsoup4==4.12.3 python-docx==1.1.2。 - 可选:
pandoc(EPUB/MOBI/DOCX 抽取更稳,未安装则回退 Python 库)。 - 可选:
unar或7zz(解 RAR/7Z;macOS 自带tar已够处理 TAR/GZ/TGZ/BZ2)。
工作流
第 1 步:发现新文件
- 列出
{reading_folder}顶层文件(只看顶层,扩展名限定:压缩包 zip、rar、7z、tar、gz、tgz、tar.gz、tar.bz2;文档 pdf、epub、mobi、azw3、docx、doc、txt、md)。 - 读取台账 JSON,
processed中已有记录(status 为 done / skipped_*)的文件跳过。 - 无新文件 → 直接结束,不产生任何输出文件。
- 有新文件 → 逐个处理。处理前先在台账写入
{"status": "processing", "started_at": ...};完成后更新为{"status": "done", "finished_at": ..., "summary_file": ...};失败则写{"status": "failed", "error": ...},下次运行会重试一次。
第 1.5 步:压缩包先解压
新文件是压缩包时,先解压到临时目录 /tmp/reading_digest/_extracted/<压缩包名>/(不要解压到待读文件夹内,避免污染和重复扫描):
- 普通 ZIP:用
zipfile解压,文件名编码按 cp437→GBK→UTF-8 顺序尝试修复(中文压缩包常见乱码问题)。 - AES 加密 ZIP(
file显示AES Encrypted、或unzip报unsupported compression method 99):系统自带 unzip/ditto 无法处理,必须用pyzipper。密码从reading_config.json的zip_password字段读取(不在技能内硬编码)。用法:
python import pyzipper with pyzipper.AESZipFile(zip_path) as z: z.extractall(out_dir, pwd=password.encode())
密码错误或未配置zip_password→ 标记 failed,注明"AES 加密,需在 reading_config.json 配置正确的 zip_password",并在汇报中提醒用户。 - TAR/GZ/TGZ/BZ2:
tar -xf <file> -C <目标目录>。 - RAR/7Z:检查
which unar或which 7zz/which 7z,有则使用(unar -o <目标目录> <file>);都没有则在台账标记 failed,错误注明"需要安装 unar(brew install unar)或 7zz",并在结果汇报中明确提醒用户。 - 解压后递归收集目录中所有支持的文档文件(忽略
__MACOSX/、.DS_Store等垃圾文件);若压缩包里还有嵌套压缩包,继续解压(最多嵌套 2 层)。 - 压缩包内每个文档独立走第 2–6 步,摘要命名为
<压缩包名>_<文档名>_摘要.md;若包内只有一个文档,则简化为<压缩包名>_摘要.md。 - 台账以压缩包文件名为 key,记录其包含的文档清单及各自摘要文件;全部文档处理完才置为 done。
- 处理完毕后删除解压临时目录;压缩包原文件保留不动。
第 2 步:抽取全文文本到缓存(本地脚本,秒级,不会超时)
对 PDF/EPUB/MOBI 等,把全文抽成单一 txt 缓存,避免在大模型对话里逐页搬运海量文本:
- PDF:用
pdfplumber逐页extract_text(),每页前写一行===== PAGE x/y =====,汇总写入/tmp/reading_digest/text/<文件名>.txt,并统计总字符数与页数。 - EPUB/MOBI/AZW3:优先
pandoc <file> -o <tmp>.md(检查which pandoc);无 pandoc 用ebooklib+beautifulsoup4抽 HTML 文本。 - DOCX:
pandoc或python-docx。 - TXT/MD:直接用作输入,无需抽取。
- 抽完若平均页文本 < 80 字符,判定疑似扫描版,转用 Read 工具逐页视觉阅读(见注意事项)。
第 3 步:串行派发子代理逐本精读(核心:一次只跑一本,严禁并发)
对每个文档(一本期刊/一本书)一次仅启动一个 general-purpose 子代理,且必须等它返回后再启动下一个。并发会触发 15–20 分钟流超时使 agent 被取消。子代理提示词须包含:
- 输入:第 2 步的 txt 路径;输出:本地 md 路径
{summary_subdir}/<原文件名>_摘要.md(压缩包内文档用<压缩包名>_<文档名>_摘要.md)。 - 分块增量读取:用 Read 工具按 offset/limit 每次读约 3000 行,严禁一次性载入全文。
- 流式追加写(防超时/防内存爆的关键):
- 先用 Write 写文件头:标题(《刊名》期号 全文摘要)、元信息(期号/总页数/生成说明"本摘要由 AI 通读全文自动生成"/原文件相对路径)、一句话总览。
- 之后每读完一个 chunk,立即cat >> "<输出md>"把该 chunk 内已完整结束的每篇文章/章节摘要追加进去:标题(英文原文+中文译名)|作者|主旨内容(150–300字)|核心观点/结论(列点)。跨 chunk 被截断的文章在下个 chunk 读完后补全,避免重复。
- 全部追加完后,再cat >>追加「## 本期最值得读 Top 3–5」与文末免责声明。 - 期刊杂志类必须逐篇介绍;书籍按章节脉络总结核心论点与结论;短文直接给主旨与结论。
- 忽略广告、版权页、目录页、无关读者来信。
此方式把单本文献工作量压进一次 agent 运行(通常 < 18 分钟)且内存恒定,规避超时。
第 4 步:校验与重试
子代理返回后检查输出 md 是否存在且 > 1KB;若失败或为空,单独重试该本一次(仍串行)。同一本两次失败则记台账 failed 并写明原因,继续下一本,不阻塞整体流程。
第 5 步:输出与收尾
每个文档摘要输出为本地 Markdown:
- 本地 Markdown:即第 3 步生成的
{summary_subdir}/<原文件名>_摘要.md,开头已含生成时间与原路径。 - 更新台账为 done,保存
summary_file。 - 清理
/tmp/reading_digest/下该文档的临时文件与解压目录;原文件只读不动。 - 全部完成后用 present_files 展示本地摘要。
注意事项
- 原文件永远只读,不移动、不重命名、不删除。
- 严禁并发启动多个文档子代理——这是整批超时失败的根因;务必一本一本串行处理。
- 逐字通读而非跳读,确保不遗漏观点;但最终摘要须凝练,不是全文复述。
- 扫描版 PDF 用 Read 工具逐页视觉阅读(读懂图表/照片语境),其余用抽取 txt。
- 台账 JSON 更新用读-改-写方式,保持其余字段不变。
- 配置中的
zip_password属敏感信息,仅存于本机reading_config.json,切勿提交到 Git 仓库或随技能打包分享。