refactor: 拆 generate_report 为 _collect/_select/_render 三段

所有选择逻辑(9 处 board_select + featured_pick + _localize + pad)
全归 _select,_render 纯拼装写盘,薄壳 generate_report 仅编排。
结构化 bundle 传参;副作用(record_pushed_links/_save_snapshot/
save_json)保持原时序在 _render 末尾。行为不变,89 测试绿(T2)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-18 14:02:32 +08:00
parent 92e0ed9a27
commit cd92644be4

View File

@@ -489,7 +489,11 @@ def _format_skill_section(items: list[dict[str, Any]], *, hot: bool = False) ->
return lines
def generate_report() -> tuple[str, str, Path, Path]:
def _collect(date_str: str) -> dict[str, Any]:
"""抓取 skills/github/news 数据并归一化,计算 wecom 限额与周去重 recent keys。
无副作用(不写快照/不记已推)。返回供 _select/_render 消费的 bundle。
"""
# Hot/Trending 前排同 source 极密,需更深抓取才能凑够展示用的唯一 source
trending_n = env_int("DAILY_TRENDING_LIMIT", 400)
hot_n = max(env_int("DAILY_HOT_LIMIT", 400), compare_depth())
@@ -570,11 +574,79 @@ def generate_report() -> tuple[str, str, Path, Path]:
| recent_shown["github_emerging"]
| recent_shown["github_topic"]
)
return {
"trending_n": trending_n,
"hot_n": hot_n,
"github_limit": github_limit,
"emerging_limit": emerging_limit,
"topic_limit": topic_limit,
"wecom_trending": wecom_trending,
"wecom_hot": wecom_hot,
"wecom_github": wecom_github,
"wecom_emerging": wecom_emerging,
"wecom_topic": wecom_topic,
"wecom_limits": wecom_limits,
"pool": pool,
"pad_pool": pad_pool,
"feed": feed,
"prev_ids": prev_ids,
"now": now,
"date_str": date_str,
"time_str": time_str,
"updated": updated,
"trending": trending,
"hot": hot,
"github_trending": github_trending,
"github_emerging": github_emerging,
"github_topic": github_topic,
"topic_name": topic_name,
"news_merged": news_merged,
"ai_news": ai_news,
"cn_ai_news": cn_ai_news,
"ai_news_research": ai_news_research,
"wecom_news": wecom_news,
"wecom_tech_news": wecom_tech_news,
"recent_shown": recent_shown,
"skill_recent": skill_recent,
"github_recent": github_recent,
}
def _select(c: dict[str, Any]) -> dict[str, Any]:
"""全部「选择 + 数据突变」:9 处 board_select + featured_pick + LLM 步骤 + pad。
时序约束内聚本段:featured pick 依赖 deep-pool;_localize 在 featured 后、
pad 前执行;写回 shown keys/llm_input 也在此。_render 不再做任何选择。
副作用: apply_featured_pick 写回 shown keys(保持原时序)。
"""
date_str = c["date_str"]
feed = c["feed"]
prev_ids = c["prev_ids"]
updated = c["updated"]
time_str = c["time_str"]
trending = c["trending"]
hot = c["hot"]
github_trending = c["github_trending"]
github_emerging = c["github_emerging"]
github_topic = c["github_topic"]
topic_name = c["topic_name"]
news_merged = c["news_merged"]
ai_news = c["ai_news"]
cn_ai_news = c["cn_ai_news"]
wecom_news = c["wecom_news"]
wecom_tech_news = c["wecom_tech_news"]
wecom_limits = c["wecom_limits"]
pool = c["pool"]
pad_pool = c["pad_pool"]
recent_shown = c["recent_shown"]
skill_recent = c["skill_recent"]
github_recent = c["github_recent"]
selected_trending = board_select(
board="skills_trending",
items=trending,
recent_keys=skill_recent,
limit=wecom_trending,
limit=c["wecom_trending"],
pool_size=pool,
kind="skill",
)
@@ -582,7 +654,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
board="skills_hot",
items=hot,
recent_keys=skill_recent,
limit=wecom_hot,
limit=c["wecom_hot"],
pool_size=pool,
kind="skill",
)
@@ -590,7 +662,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
board="github_trending",
items=github_trending,
recent_keys=github_recent,
limit=wecom_github,
limit=c["wecom_github"],
pool_size=pool,
kind="github",
)
@@ -599,7 +671,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
board="github_emerging",
items=github_emerging,
recent_keys=github_recent,
limit=wecom_emerging,
limit=c["wecom_emerging"],
pool_size=pool,
kind="github",
)
@@ -608,7 +680,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
board="github_topic",
items=github_topic,
recent_keys=github_recent,
limit=wecom_topic,
limit=c["wecom_topic"],
pool_size=pool,
kind="github",
)
@@ -741,6 +813,178 @@ def generate_report() -> tuple[str, str, Path, Path]:
themes = theme_clusters(feed, theme_rules=THEME_RULES, skill_id_fn=_skill_id)
pick_src = trending[0].get("source", "") if trending else ""
pick_name = trending[0].get("title", "") if trending else ""
pick_command = pick_command_from_featured(featured) or (
f"npx skills add {pick_src}/{pick_name}"
if pick_src and pick_name
else "npx skills add vercel-labs/skills/find-skills"
)
pick_why = pick_why_from_featured(featured) or ""
pick_title = str((featured or {}).get("title") or pick_name or "").strip()
pick_url = str((featured or {}).get("url") or "").strip()
gt = selected_trending
gh = selected_hot
gt_pad = board_select(
board="skills_trending",
items=trending,
recent_keys=skill_recent,
limit=pad_pool,
pool_size=pool,
kind="skill",
)
gh_pad = board_select(
board="skills_hot",
items=hot,
recent_keys=skill_recent,
limit=pad_pool,
pool_size=pool,
kind="skill",
)
wecom_github_items = [_prepare_github_item(item) for item in selected_github]
wecom_emerging_items = [_prepare_github_item(item) for item in selected_emerging]
wecom_topic_items = [_prepare_github_item(item) for item in selected_topic]
github_pad_recent = (
recent_shown["github_trending"]
| recent_shown["github_emerging"]
| recent_shown["github_topic"]
)
wecom_github_pad = [
_prepare_github_item(item)
for item in board_select(
board="github_trending",
items=github_trending,
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
)
]
wecom_emerging_pad = [
_prepare_github_item(item)
for item in board_select(
board="github_emerging",
items=github_emerging,
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
)
]
wecom_topic_pad = [
_prepare_github_item(item)
for item in board_select(
board="github_topic",
items=github_topic,
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
)
]
delta_pad = eff_mode == "delta" and wecom_delta_pad()
board_kwargs = {
"mode": eff_mode,
"movement": movement,
"trending": gt,
"hot": gh,
"topic_name": topic_name,
"github_trending": wecom_github_items,
"github_emerging": wecom_emerging_items,
"github_topic": wecom_topic_items,
"wecom_trending": c["wecom_trending"],
"wecom_hot": c["wecom_hot"],
"wecom_github": c["wecom_github"],
"wecom_emerging": c["wecom_emerging"],
"wecom_topic": c["wecom_topic"],
"pad": delta_pad,
"date_str": date_str,
"trending_pad": gt_pad,
"hot_pad": gh_pad,
"github_trending_pad": wecom_github_pad,
"github_emerging_pad": wecom_emerging_pad,
"github_topic_pad": wecom_topic_pad,
}
return {
"selected_trending": selected_trending,
"selected_hot": selected_hot,
"boards_for_wecom": boards_for_wecom,
"llm_input": llm_input,
"featured": featured,
"movement": movement,
"eff_mode": eff_mode,
"push_gate": push_gate,
"wecom_ai": wecom_ai,
"wecom_cn": wecom_cn,
"agent_wecom": agent_wecom,
"editorial_theme": editorial_theme,
"editorial_highlights": editorial_highlights,
"themes": themes,
"pick_command": pick_command,
"pick_why": pick_why,
"pick_title": pick_title,
"pick_url": pick_url,
"board_kwargs": board_kwargs,
"prev_ids": prev_ids,
"gt": gt,
"gh": gh,
"wecom_github_items": wecom_github_items,
"wecom_emerging_items": wecom_emerging_items,
"wecom_topic_items": wecom_topic_items,
}
def _render(c: dict[str, Any], s: dict[str, Any]) -> tuple[str, str, Path, Path]:
"""纯拼装: 拼完整版 markdown + 企微 wecom_md + 写盘。
零选择逻辑。副作用: record_pushed_links + _save_snapshot + save_json + 写文件,
全部保持原时序(在拼装完成后执行)。
"""
feed = c["feed"]
now = c["now"]
date_str = c["date_str"]
time_str = c["time_str"]
updated = c["updated"]
trending = c["trending"]
hot = c["hot"]
github_trending = c["github_trending"]
github_emerging = c["github_emerging"]
github_topic = c["github_topic"]
topic_name = c["topic_name"]
news_merged = c["news_merged"]
ai_news = c["ai_news"]
cn_ai_news = c["cn_ai_news"]
ai_news_research = c["ai_news_research"]
wecom_news = c["wecom_news"]
wecom_tech_news = c["wecom_tech_news"]
trending_n = c["trending_n"]
hot_n = c["hot_n"]
github_limit = c["github_limit"]
emerging_limit = c["emerging_limit"]
topic_limit = c["topic_limit"]
prev_ids = s["prev_ids"]
llm_input = s["llm_input"]
featured = s["featured"]
eff_mode = s["eff_mode"]
push_gate = s["push_gate"]
wecom_ai = s["wecom_ai"]
wecom_cn = s["wecom_cn"]
agent_wecom = s["agent_wecom"]
editorial_theme = s["editorial_theme"]
editorial_highlights = s["editorial_highlights"]
themes = s["themes"]
pick_command = s["pick_command"]
pick_why = s["pick_why"]
pick_title = s["pick_title"]
pick_url = s["pick_url"]
board_kwargs = s["board_kwargs"]
gt = s["gt"]
gh = s["gh"]
wecom_github_items = s["wecom_github_items"]
wecom_emerging_items = s["wecom_emerging_items"]
wecom_topic_items = s["wecom_topic_items"]
lines = [
f"# 早报 · {date_str}",
"",
@@ -814,17 +1058,6 @@ def generate_report() -> tuple[str, str, Path, Path]:
lines.append(f"- {ex}")
lines.append("")
pick_src = trending[0].get("source", "") if trending else ""
pick_name = trending[0].get("title", "") if trending else ""
pick_command = pick_command_from_featured(featured) or (
f"npx skills add {pick_src}/{pick_name}"
if pick_src and pick_name
else "npx skills add vercel-labs/skills/find-skills"
)
pick_why = pick_why_from_featured(featured) or ""
pick_title = str((featured or {}).get("title") or pick_name or "").strip()
pick_url = str((featured or {}).get("url") or "").strip()
lines.extend(["---", "", "## 安装示例", "", "```bash"])
for item in trending[:4]:
src, name = item.get("source", ""), item.get("title", "")
@@ -833,88 +1066,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
lines.extend(["```", "", f"*企微短版见 `output/{date_str}.wecom.md`*"])
markdown = "\n".join(lines)
gt = selected_trending
gh = selected_hot
gt_pad = board_select(
board="skills_trending",
items=trending,
recent_keys=skill_recent,
limit=pad_pool,
pool_size=pool,
kind="skill",
)
gh_pad = board_select(
board="skills_hot",
items=hot,
recent_keys=skill_recent,
limit=pad_pool,
pool_size=pool,
kind="skill",
)
wecom_github_items = [_prepare_github_item(item) for item in selected_github]
wecom_emerging_items = [_prepare_github_item(item) for item in selected_emerging]
wecom_topic_items = [_prepare_github_item(item) for item in selected_topic]
github_pad_recent = (
recent_shown["github_trending"]
| recent_shown["github_emerging"]
| recent_shown["github_topic"]
)
wecom_github_pad = [
_prepare_github_item(item)
for item in board_select(
board="github_trending",
items=github_trending,
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
)
]
wecom_emerging_pad = [
_prepare_github_item(item)
for item in board_select(
board="github_emerging",
items=github_emerging,
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
)
]
wecom_topic_pad = [
_prepare_github_item(item)
for item in board_select(
board="github_topic",
items=github_topic,
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
)
]
delta_pad = eff_mode == "delta" and wecom_delta_pad()
board_kwargs = {
"mode": eff_mode,
"movement": movement,
"trending": gt,
"hot": gh,
"topic_name": topic_name,
"github_trending": wecom_github_items,
"github_emerging": wecom_emerging_items,
"github_topic": wecom_topic_items,
"wecom_trending": wecom_trending,
"wecom_hot": wecom_hot,
"wecom_github": wecom_github,
"wecom_emerging": wecom_emerging,
"wecom_topic": wecom_topic,
"pad": delta_pad,
"date_str": date_str,
"trending_pad": gt_pad,
"hot_pad": gh_pad,
"github_trending_pad": wecom_github_pad,
"github_emerging_pad": wecom_emerging_pad,
"github_topic_pad": wecom_topic_pad,
}
if agent_wecom:
wecom_md = replace_wecom_skill_sections(agent_wecom, **board_kwargs)
else:
@@ -1000,6 +1152,13 @@ def generate_report() -> tuple[str, str, Path, Path]:
return markdown, wecom_md, out_md, out_wecom
def generate_report() -> tuple[str, str, Path, Path]:
"""编排三段: 抓取(_collect) → 选择(_select) → 拼装(_render)。"""
collected = _collect(_now_cst().strftime("%Y-%m-%d"))
selected = _select(collected)
return _render(collected, selected)
def main() -> int:
LOG_DIR.mkdir(parents=True, exist_ok=True)
log_file = LOG_DIR / f"{_now_cst():%Y-%m-%d}.log"