Files

5.0 KiB
Raw Permalink Blame History

name, description, metadata
name description metadata
morning-digest 通用「数据采集 + 模板注入」引擎:用一份 YAML 配置声明多路数据源(http_json/command/static),采集后用 Jinja2 模板注入成 markdown 文档。适合日报/周报/聚合摘要,不绑定单台机器。
author version
xf 2.0.0

morning-digest — 通用采集 + 模板注入引擎

把「数据采集 → 模板注入 → 输出文档」抽象成一套配置驱动的通用 skill,不绑定任何具体机器/域名/IP。早报只是其一例用法,换一份配置即可复用到日报、周报、榜单、聚合摘要。

核心思路:采集用脚本,排版用模板注入,全程确定性,不依赖 LLM 排版。

流水线

build.py --config config/digest.yaml
   ┌─────────────────────────────────────────────┐
   │ 1. 读配置(YAML/JSON)                        │
   │ 2. ${ENV} 占位符替换(机器相关项从环境变量注入)│
   │ 3. 逐 source 采集(http_json / command / static_json)
   │ 4. Jinja2 模板注入 → 输出 markdown            │
   └─────────────────────────────────────────────┘

快速开始

# 1. 准备环境变量(不写死进仓库)
set -a; . ./.env; set +a

# 2. 一键采集 + 渲染
python3 scripts/build.py --config config/morning-digest.yaml
# 输出:/tmp/digest_today.md(配置里 render.output 决定)

# 只看数据不写文件
python3 scripts/build.py --config config/morning-digest.yaml --dry-run

# 临时覆盖环境变量
python3 scripts/build.py --config config/morning-digest.yaml --env HOT_API=http://localhost:6688

配置文件结构(YAML)

meta:
  name: morning-digest
  date_format: "%Y-%m-%d"

sources:
  <section名>:            # 会成为模板变量
    type: http_json | command | static_json
    # ...adapter 参数
    map:                  # 原始 item → 输出字段
      字段名: 表达式

render:
  template: templates/digest.md
  output: /tmp/xxx.md

Source 类型与适配器

http_json — 拉一个 JSON 接口取列表

news:
  type: http_json
  url: "https://host/api/{country}"        # {param} 由 param_loop 填充
  param_loop: { key: country, values: [china, us] }   # 可选:循环发多请求
  items_path: headlines                     # 响应里取列表的路径
  limit: 5
  map:
    title: "title|headline|name"           # | 表示依次回退取第一个非空
    url: "url|link"
    source: "sourceLabel|{loop.country}"   # {loop.key} = 当前循环值

command — 跑 shell 命令,读出 JSON

github:
  type: command
  cmd: "python3 ${GITHUB_TRENDING_SCRIPT} {out}"   # {out} = 临时 JSON 文件路径
  items_from_file: "{out}"                          # 从文件读(默认解析 stdout)
  map: { name: name, desc: desc, url: url, lang: lang, stars: stars, stars_today: stars_today }

static_json — 读本地文件(供 LLM/外部注入)

tech:
  type: static_json
  file: "${TECH_FILE}"    # 未设置则跳过(optional: true)
  map: { title: title, url: url, summary: summary }

map 取值表达式

  • a|b|c — 依次尝试,取第一个非空字段
  • {loop.key} — 当前 param_loop 循环值
  • @index — 1 起始序号
  • 空串/缺失 → 该字段为空

模板

templates/digest.md(Jinja2)。每个 source 的 section 名成为一个模板变量(列表)。改排版只改模板,不动脚本。

早报模板里 GitHub Trending 已渲染成 markdown 超链接:

**[org/name](https://github.com/org/name)**(lang):desc

环境变量(.env.example)

机器相关项一律从环境变量注入,仓库不写死。

变量 说明
HOT_API DailyHotApi 基址
GITHUB_TRENDING_SCRIPT GitHub Trending 采集脚本
RSS_SCRIPT RSS 采集脚本
TECH_FILE 科技动态注入 JSON(可选)
FEISHU_CREATE_SCRIPT 飞书知识库写入脚本(可选)

失败隔离

每个 source 独立 try/except:失败 → 该 section 为空数组,错误写进输出 JSON 顶部的 _errors(不影响其他 source,流程不中断)。

依赖

  • Python 3.10+(requests、jinja2、pyyaml 可选、bs4 视 source)
  • source 脚本(${GITHUB_TRENDING_SCRIPT}、${RSS_SCRIPT} 等)按各自配置

已知坑

  • github.com 直连间歇性超时:GitHub Trending source 依赖直连官方页面,外网抖动时会空(记入 _errors 不中断)。
  • 海外 RSS DNS 吊死:ak-rss-digest 用子进程隔离 + feedparser,个别源超时不影响整体。
  • 飞书写入幂等:create_digest.py 同标题自动复用节点,不重复建文档。

扩展

想加数据源?在 sources 里加一个 section(选一种 adapter,配好 map)→ 在模板里用它,即可。无需改引擎。