提取 collect/formatters/themes 等 pipeline 模块,新增 wecom 分条、RSS、delta、Agent 工作流测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
54 lines
2.3 KiB
Python
54 lines
2.3 KiB
Python
"""主题检测与聚类。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from collections import defaultdict
|
||
from typing import Any
|
||
|
||
THEME_RULES: list[tuple[str, str, list[str]]] = [
|
||
("🎬", "AI 多媒体 / 视频", ["runcomfy", "remotion", "video", "seedance", "inpaint", "lipsync"]),
|
||
("🔧", "工程协作 / Skill 元能力", ["grill", "tdd", "architecture", "find-skills", "to-issues"]),
|
||
("📱", "飞书 / Lark", ["lark", "feishu"]),
|
||
("📣", "内容营销", ["viral", "tiktok", "instagram", "reels"]),
|
||
("🎨", "设计 / 前端", ["frontend", "design", "ui-ux", "tailwind"]),
|
||
]
|
||
|
||
|
||
def detect_theme_line(feed: dict[str, Any]) -> str:
|
||
scores: dict[str, int] = defaultdict(int)
|
||
for board in ("topTrending", "topHot"):
|
||
for rank, item in enumerate(feed.get(board, [])[:10], 1):
|
||
haystack = " ".join(
|
||
[item.get("title", ""), item.get("source", ""), item.get("description", "")]
|
||
).lower()
|
||
for _icon, label, keywords in THEME_RULES:
|
||
if any(k in haystack for k in keywords):
|
||
scores[label] += max(1, 11 - rank)
|
||
break
|
||
if not scores:
|
||
return "**今日主题**:Agent Skills 生态持续活跃"
|
||
return f"**今日主题**:{max(scores.items(), key=lambda x: x[1])[0]}"
|
||
|
||
|
||
def theme_clusters(feed: dict[str, Any], limit: int = 5) -> list[tuple[str, list[str]]]:
|
||
from daily.pipeline.snapshot import skill_id
|
||
|
||
buckets: dict[str, list[str]] = defaultdict(list)
|
||
seen: set[str] = set()
|
||
for board in ("topTrending", "topHot"):
|
||
for item in feed.get(board, [])[:20]:
|
||
item_id = skill_id(item)
|
||
if item_id in seen:
|
||
continue
|
||
seen.add(item_id)
|
||
haystack = " ".join(
|
||
[item.get("title", ""), item.get("source", ""), item.get("description", "")]
|
||
).lower()
|
||
for _icon, theme, keywords in THEME_RULES:
|
||
if any(k in haystack for k in keywords):
|
||
label = f"**{item.get('title')}** (`{item.get('source')}`)"
|
||
if label not in buckets[theme]:
|
||
buckets[theme].append(label)
|
||
break
|
||
return [(theme, examples[:limit]) for theme, examples in buckets.items() if examples]
|