From 2a651a5c8562ea5397005403057678572c3e992f Mon Sep 17 00:00:00 2001 From: liuwei Date: Wed, 29 Apr 2026 15:28:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=B2=89=E4=B8=9D=E6=97=A5?= =?UTF-8?q?=E6=8A=A5=E4=BF=A1=E6=81=AF=E5=8C=BA=E9=87=8D=E5=A4=8D=E4=B8=8E?= =?UTF-8?q?=E7=83=AD=E7=82=B9=E5=8C=BA=E7=A9=BA=E7=99=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 移除今日重点信息中的重复摘要列表,只保留卡片展示\n2. 为粉丝日报模板补充新旧载荷结构兼容逻辑,支持从llm_compact、peak_buckets、repeated_messages等字段自动兜底\n3. 热点窗口与共识梗区域增加空数据说明块,避免页面出现整块空白 --- plugins/douyu/report_template.py | 134 +++++++++++++++--- .../douyu/templates/daily_fans_report.html | 1 - 2 files changed, 114 insertions(+), 21 deletions(-) diff --git a/plugins/douyu/report_template.py b/plugins/douyu/report_template.py index 14a5154..15c794b 100644 --- a/plugins/douyu/report_template.py +++ b/plugins/douyu/report_template.py @@ -474,6 +474,95 @@ def _render_fans_metric_cards(metrics: List[Dict[str, str]]) -> str: return "".join(blocks) +def _get_compact_scene_material(payload: Dict[str, Any]) -> Dict[str, Any]: + """ + 兼容两种来源的粉丝日报载荷: + 1. 新版 prompt 材料已经预先组装好的 compact_scene_material; + 2. 正式渲染链路里仍然保留在 llm_compact 下的压缩材料。 + 这样模板层可以向后兼容,不会因为字段尚未完全迁移就出现空版块。 + """ + compact = payload.get("compact_scene_material", {}) or {} + if compact: + return compact + return payload.get("llm_compact", {}) or {} + + +def _get_topic_evidence_clusters(payload: Dict[str, Any]) -> List[Dict[str, Any]]: + """ + 兼容“已展开主题簇”和“仍放在 llm_compact.semantic_fact_hints.topic_clusters”两种结构。 + """ + clusters = payload.get("topic_evidence_clusters", []) or [] + if clusters: + return clusters + compact = _get_compact_scene_material(payload) + fact_hints = compact.get("semantic_fact_hints", {}) or {} + normalized = [] + for item in (fact_hints.get("topic_clusters", []) or [])[:6]: + normalized.append({ + "label": str(item.get("label") or "").strip(), + "count": int(item.get("match_count", item.get("count", 0)) or 0), + "user_count": int(item.get("user_count", 0) or 0), + "time_range": ( + f"{str(item.get('first_hm') or '').strip()}-{str(item.get('last_hm') or '').strip()}" + ).strip("-"), + "keywords": item.get("keywords", []) or [], + "samples": item.get("samples", []) or [], + }) + return normalized + + +def _get_hero_mentions(payload: Dict[str, Any]) -> List[Dict[str, Any]]: + compact = _get_compact_scene_material(payload) + return ( + compact.get("semantic_fact_hints", {}) + .get("hero_mentions", []) + or [] + ) + + +def _build_local_stats(payload: Dict[str, Any]) -> Dict[str, Any]: + """ + 兼容新旧载荷的本地统计字段。 + 如果没有 top-level local_stats,就从 peak_buckets / repeated_messages / burst_terms / content_cues 临时拼一份, + 保证“热点窗口与共识梗”始终有内容可用。 + """ + local_stats = payload.get("local_stats", {}) or {} + if local_stats: + return local_stats + + compact = _get_compact_scene_material(payload) + content_cues = compact.get("content_cues", []) or [] + return { + "message_count": int((payload.get("report_meta", {}) or {}).get("message_count", 0) or 0), + "unique_user_count": int((payload.get("report_meta", {}) or {}).get("unique_user_count", 0) or 0), + "top_emotion_bursts": [ + { + "text": str(item.get("text") or "").strip(), + "count": int(item.get("count", 0) or 0), + } + for item in content_cues + if str(item.get("kind") or "").strip() == "emotion" and str(item.get("text") or "").strip() + ][:8], + "top_repeated_messages": [ + { + "text": str(item.get("text") or "").strip(), + "count": int(item.get("count", 0) or 0), + "user_count": int(item.get("user_count", 0) or 0), + } + for item in (payload.get("repeated_messages", []) or [])[:8] + if str(item.get("text") or "").strip() + ], + "peak_windows": [ + { + "start_time": str(item.get("start_time") or "").strip(), + "message_count": int(item.get("message_count", 0) or 0), + "user_count": int(item.get("user_count", 0) or 0), + } + for item in (payload.get("peak_buckets", []) or [])[:6] + ], + } + + def _build_fans_effective_info_lines(payload: Dict[str, Any], limit: int = 6) -> List[str]: """ 为粉丝日报补一层“有效信息速览”。 @@ -490,7 +579,7 @@ def _build_fans_effective_info_lines(payload: Dict[str, Any], limit: int = 6) -> seen.add(value) lines.append(value) - for item in (payload.get("topic_evidence_clusters", []) or [])[:6]: + for item in _get_topic_evidence_clusters(payload)[:6]: label = str(item.get("label") or "").strip() count = int(item.get("count", 0) or 0) time_range = str(item.get("time_range") or "").strip() @@ -506,13 +595,13 @@ def _build_fans_effective_info_lines(payload: Dict[str, Any], limit: int = 6) -> if len(lines) >= limit: return lines[:limit] - hero_mentions = payload.get("compact_scene_material", {}).get("semantic_fact_hints", {}).get("hero_mentions", []) or [] + hero_mentions = _get_hero_mentions(payload) if hero_mentions: hero_names = [str(item.get("hero") or "").strip() for item in hero_mentions[:4] if str(item.get("hero") or "").strip()] if hero_names: push(f"英雄讨论主要集中在 {'、'.join(hero_names)}。") - hot_windows = payload.get("local_stats", {}).get("peak_windows", []) or [] + hot_windows = _build_local_stats(payload).get("peak_windows", []) or [] if hot_windows: top_window = hot_windows[0] push( @@ -537,7 +626,7 @@ def _build_local_topic_focus_lines(payload: Dict[str, Any], limit: int = 4) -> L seen.add(value) lines.append(value) - for item in (payload.get("topic_evidence_clusters", []) or [])[:4]: + for item in _get_topic_evidence_clusters(payload)[:4]: label = str(item.get("label") or "").strip() keywords = [str(keyword).strip() for keyword in (item.get("keywords", []) or [])[:5] if str(keyword).strip()] count = int(item.get("count", 0) or 0) @@ -555,12 +644,7 @@ def _build_local_hero_focus_lines(payload: Dict[str, Any], limit: int = 4) -> Li 为“英雄与对局焦点”准备本地兜底。 这部分直接复用英雄提及聚类,优先强调出现频次和代表发言,方便粉丝快速看懂今天在聊什么英雄。 """ - hero_mentions = ( - payload.get("compact_scene_material", {}) - .get("semantic_fact_hints", {}) - .get("hero_mentions", []) - or [] - ) + hero_mentions = _get_hero_mentions(payload) lines: List[str] = [] seen = set() @@ -687,11 +771,20 @@ def _render_hot_window_cards(hot_windows: List[Dict[str, Any]]) -> str: f'
{message_count} 条弹幕 / {user_count} 人参与
' '' ) + # 页面层兜底: + # 如果热窗没有任何卡片,也返回一个说明块,避免整个区域看起来像渲染坏了。 + if not blocks: + blocks.append( + '
' + '
--:--
' + '
当前载荷里没有可展示的热点窗口数据
' + '
' + ) return "".join(blocks) def _render_repeat_digest(payload: Dict[str, Any]) -> str: - local_stats = payload.get("local_stats", {}) or {} + local_stats = _build_local_stats(payload) repeated_messages = local_stats.get("top_repeated_messages", []) or [] emotion_bursts = local_stats.get("top_emotion_bursts", []) or [] blocks = [] @@ -715,6 +808,13 @@ def _render_repeat_digest(payload: Dict[str, Any]) -> str: f'{count} 次' '' ) + if not blocks: + blocks.append( + '
' + '暂无共识梗数据' + '0 次' + '
' + ) return "".join(blocks) @@ -1054,14 +1154,9 @@ def render_fans_daily_report_html( lead_text = str(sections.get("lead") or "").strip() if not lead_text: lead_text = "今天这场直播的弹幕主打一个集体上头,观众一边盯着画面,一边忙着把梗越刷越离谱。" - topic_clusters = payload.get("topic_evidence_clusters", []) or [] - hero_mentions = ( - payload.get("compact_scene_material", {}) - .get("semantic_fact_hints", {}) - .get("hero_mentions", []) - or [] - ) - local_stats = payload.get("local_stats", {}) or {} + topic_clusters = _get_topic_evidence_clusters(payload) + hero_mentions = _get_hero_mentions(payload) + local_stats = _build_local_stats(payload) renderer = HtmlTemplateRenderer() return renderer.render( @@ -1072,7 +1167,6 @@ def render_fans_daily_report_html( "lead_text": lead_text, # 粉丝版不再只做“乐子文案展示”,而是补进本地提纯后的有效信息区。 "fans_metrics_html": Markup(_render_fans_metric_cards(_build_fans_fun_metrics(payload))), - "effective_summary_html": Markup(_render_list(effective_info_lines, item_class="section-summary-list")), "effective_info_html": Markup(_render_fans_info_cards(effective_info_lines)), "topic_focus_html": Markup(_render_list(topic_focus_lines, item_class="section-summary-list")), "topic_clusters_html": Markup(_render_topic_clusters(topic_clusters)), diff --git a/plugins/douyu/templates/daily_fans_report.html b/plugins/douyu/templates/daily_fans_report.html index 9b25ae5..2ad7183 100644 --- a/plugins/douyu/templates/daily_fans_report.html +++ b/plugins/douyu/templates/daily_fans_report.html @@ -398,7 +398,6 @@
今日重点信息
- {{ effective_summary_html }}
{{ effective_info_html }}