feat(briefing): cluster-level preference filtering — rank themes by user interest, suppress disliked topics

This commit is contained in:
2026-04-08 22:51:13 -04:00
parent 8762552234
commit d56b57ee40
@@ -652,8 +652,9 @@ def _unified_user_prompt(internal_data: dict, external_data: dict, slot: str, te
lines.extend(f" - {p}" for p in internal_data["stale_projects"])
lines.append("")
# News — clustered by topic for thematic synthesis
# News — clustered by topic, ranked by preference score
rss = external_data.get("rss_items") or []
topic_scores = external_data.get("topic_scores") or {}
if rss:
# Group articles by their primary topic
clusters: dict[str, list[dict]] = {}
@@ -666,19 +667,34 @@ def _unified_user_prompt(internal_data: dict, external_data: dict, slot: str, te
else:
uncategorized.append(item)
# Sort clusters by size (most articles = most active theme)
sorted_clusters = sorted(clusters.items(), key=lambda x: len(x[1]), reverse=True)
# Score each cluster by aggregate preference (positive = user likes this topic)
def cluster_score(topic: str, items: list[dict]) -> float:
pref = topic_scores.get(topic, 0.0)
return pref * 2.0 + len(items) # preference-weighted, size as tiebreak
# Filter out clusters where the user has a strongly negative preference
filtered_clusters = [
(topic, items) for topic, items in clusters.items()
if topic_scores.get(topic, 0.0) >= -2.0
]
# Sort by preference-weighted score
sorted_clusters = sorted(filtered_clusters, key=lambda x: cluster_score(x[0], x[1]), reverse=True)
lines.append("NEWS THEMES (synthesize 1-2 themes into your briefing; mention article count per theme):")
for topic, items in sorted_clusters[:4]:
for i, (topic, items) in enumerate(sorted_clusters[:4]):
count = len(items)
titles = [i.get("title", "") for i in items[:3]]
sources = list({i.get("feed_title") or i.get("source") or "News" for i in items})
lines.append(f" [{topic.title()}] ({count} article{'s' if count != 1 else ''} from {', '.join(sources[:2])})")
titles = [it.get("title", "") for it in items[:3]]
sources = list({it.get("feed_title") or it.get("source") or "News" for it in items})
pref_indicator = ""
pref = topic_scores.get(topic, 0.0)
if pref >= 2.0:
pref_indicator = "" # user's preferred topic
lines.append(f" [{topic.title()}]{pref_indicator} ({count} article{'s' if count != 1 else ''} from {', '.join(sources[:2])})")
for t in titles:
lines.append(f"{t}")
# Include one excerpt for the top cluster
if items == sorted_clusters[0][1]:
# Include excerpt for preferred clusters or the top cluster
if pref >= 1.0 or i == 0:
excerpt = (items[0].get("content") or items[0].get("snippet") or "")[:400].strip()
if excerpt:
lines.append(f" > {excerpt}")
@@ -793,6 +809,7 @@ async def run_compilation(
external_data_filtered = {
"rss_items": filtered_rss,
"weather": [],
"topic_scores": topic_scores,
}
briefing_text = await _llm_synthesise(