diff --git a/app/templates/hotspots/report.html b/app/templates/hotspots/report.html index 7e806f7..f79965e 100644 --- a/app/templates/hotspots/report.html +++ b/app/templates/hotspots/report.html @@ -16,11 +16,11 @@ {% if report %} -
-

{{ report.summary }}

-
{{ report.markdown_content }}
-
+ {% include "partials/report_panel.html" %} {% else %} -
报告生成中,请稍候...
+
+
+

报告生成中,请稍候...

+
{% endif %} {% endblock %} diff --git a/app/templates/items/detail.html b/app/templates/items/detail.html index d42fbb1..f1ad40e 100644 --- a/app/templates/items/detail.html +++ b/app/templates/items/detail.html @@ -17,10 +17,12 @@ {% if report %} -
-

{{ report.summary }}

-
{{ report.markdown_content }}
-
+ {% include "partials/report_panel.html" %} +{% else %} +
+
+

报告生成中,请稍候...

+
{% endif %}
评论明细
diff --git a/app/templates/partials/report_panel.html b/app/templates/partials/report_panel.html new file mode 100644 index 0000000..e856d6c --- /dev/null +++ b/app/templates/partials/report_panel.html @@ -0,0 +1,91 @@ +{% set metrics = report.metrics_json | from_json_object %} +{% set typical = report.typical_comments_json | from_json_object %} +{% set sentiment = metrics.get("sentiment", {}) %} +{% set top_labels = metrics.get("top_labels", []) %} +{% set sample_count = metrics.get("sample_count", 0) %} +{% set item_count = metrics.get("item_count") %} + +
+
+ {% if task.analysis_status == "insufficient" %} +
当前有效评论样本不足,AI 总结暂不可用。建议增加评论抓取数量后重新分析。
+ {% endif %} + +
+
+
+
评论样本
+
{{ sample_count }}
+
+
+ {% if item_count is not none %} +
+
+
关联内容
+
{{ item_count }}
+
+
+ {% endif %} +
+
+
AI 成功率
+
{{ rate_percent(task.analysis_success_rate) }}%
+
+
+
+ +
+
AI 总结
+

{{ report.summary or "总结生成失败,请查看上方统计数据。" }}

+
+ +
+
+

情绪分布

+ {% for key, bar_class in [("positive", "bg-success"), ("neutral", "bg-secondary"), ("negative", "bg-danger"), ("unknown", "bg-warning")] %} + {% set item = sentiment.get(key, {"count": 0, "pct": 0}) %} +
+ {{ sentiment_label(key) }} + {{ item.get("count", 0) }} 条({{ item.get("pct", 0) }}%) +
+
+
+
+ {% endfor %} +
+
+

Top 标签

+ {% if top_labels %} +
+ {% for label in top_labels %} + {{ label.get("name") }} ({{ label.get("count", 0) }}) + {% endfor %} +
+ {% else %} +

暂无标签数据

+ {% endif %} +
+
+
+
+ +
+
典型评论
+
+
+ {% for key in ["positive", "neutral", "negative"] %} +
+

{{ sentiment_label(key) }}

+ {% for comment in typical.get(key, []) %} +
+

{{ comment.get("content") }}

+ 点赞 {{ comment.get("like_count", 0) }} +
+ {% else %} +

暂无{{ sentiment_label(key) }}代表评论

+ {% endfor %} +
+ {% endfor %} +
+
+
diff --git a/app/templating.py b/app/templating.py index 3e3570a..017273b 100644 --- a/app/templating.py +++ b/app/templating.py @@ -28,6 +28,14 @@ def from_json_filter(value: str | None) -> list: return parsed if isinstance(parsed, list) else [] +def from_json_object_filter(value: str | None) -> dict: + try: + parsed = json.loads(value) if value else {} + except (TypeError, json.JSONDecodeError): + return {} + return parsed if isinstance(parsed, dict) else {} + + def progress_percent(processed_count: int, total_count: int) -> int: if total_count <= 0: return 0 @@ -40,8 +48,19 @@ def rate_percent(rate: float | None) -> int: return min(100, max(0, round(rate * 100))) +def sentiment_label(sentiment: str) -> str: + return { + "positive": "正向", + "neutral": "中性", + "negative": "负向", + "unknown": "未知", + }.get(sentiment, sentiment) + + templates.env.globals["status_badge_config"] = status_badge_config templates.env.globals["progress_percent"] = progress_percent templates.env.globals["rate_percent"] = rate_percent +templates.env.globals["sentiment_label"] = sentiment_label templates.env.filters["platform_label"] = platform_label templates.env.filters["from_json"] = from_json_filter +templates.env.filters["from_json_object"] = from_json_object_filter diff --git a/tests/integration/test_routes.py b/tests/integration/test_routes.py index 01f63ee..a2a8b0b 100644 --- a/tests/integration/test_routes.py +++ b/tests/integration/test_routes.py @@ -179,7 +179,14 @@ def seed_result_data(engine): from sqlalchemy.orm import Session with Session(engine) as session: - task = Task(id="task-result", platform="douyin", status="success", total_items_count=1, successful_items_count=1) + task = Task( + id="task-result", + platform="douyin", + status="success", + total_items_count=1, + successful_items_count=1, + analysis_success_rate=1.0, + ) session.add(task) hotspot = Hotspot(id="hot-result", task_id=task.id, platform="douyin", title="热点标题", rank=1, raw_data="{}") session.add(hotspot) @@ -216,8 +223,8 @@ def seed_result_data(engine): hotspot_id=hotspot.id, report_type="hotspot", title="热点标题", - metrics_json='{"sample_count":1,"sentiment":{"positive":{"count":1,"pct":100}},"top_labels":[{"name":"认可","count":1}]}', - typical_comments_json='{"positive":[{"content":"评论内容","like_count":3}]}', + metrics_json='{"sample_count":1,"item_count":1,"sentiment":{"positive":{"count":1,"pct":100},"neutral":{"count":0,"pct":0},"negative":{"count":0,"pct":0},"unknown":{"count":0,"pct":0}},"top_labels":[{"name":"认可","count":1}]}', + typical_comments_json='{"positive":[{"content":"评论内容","like_count":3}],"neutral":[],"negative":[]}', summary="热点总结", markdown_content="# 热点标题\n\n热点总结", data="{}", @@ -231,8 +238,8 @@ def seed_result_data(engine): content_item_id=item.id, report_type="item", title="视频标题", - metrics_json='{"sample_count":1,"sentiment":{"positive":{"count":1,"pct":100}},"top_labels":[{"name":"认可","count":1}]}', - typical_comments_json='{"positive":[{"content":"评论内容","like_count":3}]}', + metrics_json='{"sample_count":1,"sentiment":{"positive":{"count":1,"pct":100},"neutral":{"count":0,"pct":0},"negative":{"count":0,"pct":0},"unknown":{"count":0,"pct":0}},"top_labels":[{"name":"认可","count":1}]}', + typical_comments_json='{"positive":[{"content":"评论内容","like_count":3}],"neutral":[],"negative":[]}', summary="内容总结", markdown_content="# 视频标题\n\n内容总结", data="{}", @@ -255,10 +262,74 @@ def test_result_pages_render_seeded_data(): assert 'onclick="window.location.reload()"' in task_response.text assert hotspot_response.status_code == 200 assert "热点总结" in hotspot_response.text + assert "评论样本" in hotspot_response.text + assert "关联内容" in hotspot_response.text + assert "正向" in hotspot_response.text + assert "1 条(100%)" in hotspot_response.text + assert "认可 (1)" in hotspot_response.text + assert "典型评论" in hotspot_response.text + assert "评论内容" in hotspot_response.text + assert "
评论内容情绪标签点赞