feat: 实现 board_select 周去重与深池补满
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
46
daily/board_select.py
Normal file
46
daily/board_select.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"""五榜唯一列表主人:周去重 + 深池补满。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Any, Literal
|
||||||
|
|
||||||
|
from daily.delta import skill_id
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def board_select(
|
||||||
|
*,
|
||||||
|
board: str,
|
||||||
|
items: list[dict[str, Any]],
|
||||||
|
recent_keys: set[str],
|
||||||
|
limit: int,
|
||||||
|
pool_size: int,
|
||||||
|
kind: Literal["skill", "github"],
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
"""从深池过滤近 N 日已展示 key,按原顺序取满 limit;不足则短榜。"""
|
||||||
|
if kind == "skill":
|
||||||
|
from daily.skills_group import group_skills_by_source
|
||||||
|
|
||||||
|
pool = group_skills_by_source(items, limit=pool_size, pool_size=pool_size)
|
||||||
|
|
||||||
|
def key_fn(x: dict[str, Any]) -> str:
|
||||||
|
return skill_id(x)
|
||||||
|
else:
|
||||||
|
pool = items[: max(pool_size, limit)]
|
||||||
|
|
||||||
|
def key_fn(x: dict[str, Any]) -> str:
|
||||||
|
return str(x.get("repo") or "")
|
||||||
|
|
||||||
|
out: list[dict[str, Any]] = []
|
||||||
|
for item in pool:
|
||||||
|
k = key_fn(item)
|
||||||
|
if not k or k in recent_keys:
|
||||||
|
continue
|
||||||
|
out.append(item)
|
||||||
|
if len(out) >= limit:
|
||||||
|
break
|
||||||
|
if len(out) < limit:
|
||||||
|
logger.info("board_short:%s:%s", board, len(out))
|
||||||
|
return out
|
||||||
58
tests/test_board_select.py
Normal file
58
tests/test_board_select.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# tests/test_board_select.py
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from daily.board_select import board_select
|
||||||
|
|
||||||
|
|
||||||
|
def _gh(repo: str) -> dict:
|
||||||
|
return {"repo": repo, "description": repo}
|
||||||
|
|
||||||
|
|
||||||
|
class BoardSelectTests(unittest.TestCase):
|
||||||
|
def test_filters_recent_and_keeps_order(self):
|
||||||
|
pool = [_gh(f"o/r{i}") for i in range(20)]
|
||||||
|
recent = {"o/r0", "o/r1", "o/r2"}
|
||||||
|
out = board_select(
|
||||||
|
board="github_trending",
|
||||||
|
items=pool,
|
||||||
|
recent_keys=recent,
|
||||||
|
limit=5,
|
||||||
|
pool_size=20,
|
||||||
|
kind="github",
|
||||||
|
)
|
||||||
|
keys = [x["repo"] for x in out]
|
||||||
|
self.assertEqual(keys, ["o/r3", "o/r4", "o/r5", "o/r6", "o/r7"])
|
||||||
|
|
||||||
|
def test_deep_pool_fills_after_filter(self):
|
||||||
|
pool = [_gh(f"o/r{i}") for i in range(8)]
|
||||||
|
recent = {f"o/r{i}" for i in range(6)} # 前 6 全封
|
||||||
|
out = board_select(
|
||||||
|
board="github_emerging",
|
||||||
|
items=pool,
|
||||||
|
recent_keys=recent,
|
||||||
|
limit=5,
|
||||||
|
pool_size=8,
|
||||||
|
kind="github",
|
||||||
|
)
|
||||||
|
self.assertEqual([x["repo"] for x in out], ["o/r6", "o/r7"]) # 短榜
|
||||||
|
|
||||||
|
def test_skill_uses_skill_id(self):
|
||||||
|
items = [
|
||||||
|
{"id": "a/b/s1", "source": "a/b", "title": "s1", "installs": 10},
|
||||||
|
{"id": "c/d/s2", "source": "c/d", "title": "s2", "installs": 9},
|
||||||
|
]
|
||||||
|
out = board_select(
|
||||||
|
board="skills_trending",
|
||||||
|
items=items,
|
||||||
|
recent_keys={"a/b/s1"},
|
||||||
|
limit=10,
|
||||||
|
pool_size=50,
|
||||||
|
kind="skill",
|
||||||
|
)
|
||||||
|
self.assertEqual([x["id"] for x in out], ["c/d/s2"])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user