feat: 拆分 wecom_shown_keys 与 movement_baseline 历史层
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
83
daily/board_history.py
Normal file
83
daily/board_history.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""企微展示历史:读写 data.wecom_shown_keys,与 movement_baseline 严格分离。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from daily.config import OUTPUT_DIR, board_dedup_days
|
||||
from daily.delta import RECENT_BOARD_KEYS, skill_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
BOARD_KEYS = RECENT_BOARD_KEYS
|
||||
|
||||
|
||||
def extract_shown_keys(board: str, items: list[dict[str, Any]]) -> list[str]:
|
||||
"""从最终展示 items 抽取稳定 identity key。"""
|
||||
keys: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for item in items:
|
||||
if board.startswith("skills_"):
|
||||
key = skill_id(item)
|
||||
else:
|
||||
key = str(item.get("repo") or "")
|
||||
if not key or key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
keys.append(key)
|
||||
return keys
|
||||
|
||||
|
||||
def load_recent_shown_keys(
|
||||
date_str: str,
|
||||
*,
|
||||
lookback_days: int | None = None,
|
||||
) -> dict[str, set[str]]:
|
||||
"""近 N 日 data.wecom_shown_keys 并集(不含当日)。缺省或读失败视为空集。"""
|
||||
empty = {board: set() for board in BOARD_KEYS}
|
||||
try:
|
||||
dt = datetime.strptime(date_str, "%Y-%m-%d")
|
||||
except ValueError:
|
||||
return empty
|
||||
|
||||
days = lookback_days if lookback_days is not None else board_dedup_days()
|
||||
out: dict[str, set[str]] = {board: set() for board in BOARD_KEYS}
|
||||
|
||||
for day_offset in range(1, days + 1):
|
||||
prev_date = (dt - timedelta(days=day_offset)).strftime("%Y-%m-%d")
|
||||
path = OUTPUT_DIR / f"{prev_date}.data.json"
|
||||
if not path.exists():
|
||||
continue
|
||||
try:
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, ValueError) as exc:
|
||||
logger.warning("读取 wecom_shown_keys %s 失败:%s", path, exc)
|
||||
continue
|
||||
data = payload.get("data")
|
||||
if not isinstance(data, dict):
|
||||
continue
|
||||
shown = data.get("wecom_shown_keys")
|
||||
if not isinstance(shown, dict):
|
||||
continue
|
||||
for board in BOARD_KEYS:
|
||||
keys = shown.get(board) or []
|
||||
if not isinstance(keys, list):
|
||||
continue
|
||||
out[board].update(str(k) for k in keys if k)
|
||||
return out
|
||||
|
||||
|
||||
def merge_wecom_shown_into_data(
|
||||
data: dict[str, Any],
|
||||
shown: dict[str, list[str]],
|
||||
) -> dict[str, Any]:
|
||||
"""写入 wecom_shown_keys,不修改 movement_baseline。"""
|
||||
merged = dict(data)
|
||||
merged["wecom_shown_keys"] = {
|
||||
board: list(keys) for board, keys in shown.items()
|
||||
}
|
||||
return merged
|
||||
Reference in New Issue
Block a user