Files
daily-robots/daily/skills_group.py
2026-07-02 11:31:16 +08:00

104 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Skills 榜单:同 source 合并为一条(企微 Top N"""
from __future__ import annotations
from typing import Any
def skill_id(item: dict[str, Any]) -> str:
return str(item.get("id") or f"{item.get('source')}/{item.get('title')}")
def format_installs(n: int | float) -> str:
if n >= 1_000_000:
return f"{n / 1_000_000:.1f}M"
if n >= 1_000:
return f"{n / 1_000:.1f}K"
return str(int(n))
def _installs_range(items: list[dict[str, Any]]) -> tuple[int, int, str]:
values = [int(item.get("installs") or 0) for item in items]
lo, hi = min(values), max(values)
if lo == hi:
return lo, hi, format_installs(hi)
return lo, hi, f"{format_installs(lo)}{format_installs(hi)}"
def _best_description(items: list[dict[str, Any]]) -> str:
for item in items:
desc = (item.get("description") or "").strip()
if desc:
return desc
return ""
def _cluster_skill(items: list[dict[str, Any]]) -> dict[str, Any]:
ranked = sorted(items, key=lambda x: int(x.get("installs") or 0), reverse=True)
top = ranked[0]
_lo, _hi, installs_fmt = _installs_range(ranked)
titles = [str(x.get("title") or "") for x in ranked if x.get("title")]
sample = ", ".join(titles[:4])
if len(titles) > 4:
sample = f"{sample}"
return {
"id": skill_id(top),
"title": top.get("title", ""),
"source": top.get("source", ""),
"installs": int(top.get("installs") or 0),
"installs_min": _lo,
"installs_max": _hi,
"installs_fmt": installs_fmt,
"link": top.get("link", ""),
"description": _best_description(ranked),
"cluster": True,
"cluster_count": len(ranked),
"cluster_skills": titles,
"cluster_titles": sample,
}
def _single_skill(item: dict[str, Any]) -> dict[str, Any]:
installs = int(item.get("installs") or 0)
return {
"id": skill_id(item),
"title": item.get("title", ""),
"source": item.get("source", ""),
"installs": installs,
"installs_fmt": format_installs(installs),
"link": item.get("link", ""),
"description": item.get("description", ""),
"cluster": False,
}
def group_skills_by_source(
items: list[dict[str, Any]],
*,
limit: int = 10,
pool_size: int = 50,
) -> list[dict[str, Any]]:
"""按 source 去重合并;保留各 source 在榜内的最佳名次顺序。"""
if not items or limit <= 0:
return []
pool = items[: max(pool_size, limit)]
by_source: dict[str, list[dict[str, Any]]] = {}
first_rank: dict[str, int] = {}
for rank, item in enumerate(pool, 1):
source = (item.get("source") or "?").strip() or "?"
by_source.setdefault(source, []).append(item)
first_rank.setdefault(source, rank)
ordered_sources = sorted(by_source.keys(), key=lambda s: first_rank[s])
result: list[dict[str, Any]] = []
for source in ordered_sources:
group = by_source[source]
if len(group) == 1:
result.append(_single_skill(group[0]))
else:
result.append(_cluster_skill(group))
if len(result) >= limit:
break
return result