"""主题检测与聚类。""" 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]