Files
abot/plugins/message_summary/templates/gemini_summary_card.html
liuwei 6fec1025de 按5话题结构重排总结渲染并优化模板适配
- 新增话题卡片聚合逻辑:从结构化分节中提取并合并为最多5个话题\n- 在渲染阶段识别并归并时段/参与人数/核心观点/客观分析/亮点瞬间,避免详情平铺\n- 新增辅助区块抽取(交易/资源/荣誉榜等),以独立模块展示减少正文拥挤\n- 调整Gemini模板为固定5话题卡片布局,控制单话题条目上限,降低超长截图风险\n- 修正统计展示口径兜底:限制Text和Active不超过Msgs,避免出现反直觉指标\n- 保留旧字段兼容,确保非Gemini模板仍可回退渲染
2026-04-23 10:21:00 +08:00

483 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<style>
/* 说明:由后端动态注入本地字体 @font-facefonts 目录),避免外网字体依赖。 */
{{ local_font_css }}
:root {
--bg: #f8fafc;
--surface: #ffffff;
--line: #eef2f7;
--text: #334155;
--text-soft: #64748b;
--text-faint: #94a3b8;
--title: #0f172a;
--brand: #2563eb;
--brand-soft: #dbeafe;
--ok-soft: #f0fdf4;
--ok-line: #22c55e;
--quote-bg: #f8fafc;
--quote-line: #cbd5e1;
--code-bg: #0f172a;
--code-text: #e2e8f0;
--shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.08);
}
* { box-sizing: border-box; }
body {
margin: 0;
/* 说明:减少上下留白,避免截图后出现“背景很大、内容很小”的视觉问题。 */
padding: 10px 0 12px;
background: var(--bg);
color: var(--text);
/* 说明:优先使用本地字体变量,未命中时回退系统字体。 */
font-family: var(--abot-font-sans, "PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
-webkit-font-smoothing: antialiased;
}
.report-container {
/* 说明:使用与截图视口更匹配的宽度,显著提升内容占比。 */
width: min(720px, calc(100vw - 20px));
margin: 0 auto;
background: var(--surface);
box-shadow: var(--shadow);
border: 1px solid #e2e8f0;
}
.label-tiny {
font-size: 9px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: .08em;
color: var(--text-faint);
margin-bottom: 2px;
display: block;
}
.header {
/* 说明:同步放大内边距与字号节奏,避免在更宽卡片里内容显得过小。 */
padding: 20px 20px 16px;
border-bottom: 1px solid var(--line);
}
.header-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
gap: 10px;
}
.header-title {
font-size: 16px;
font-weight: 900;
color: var(--title);
letter-spacing: -.02em;
line-height: 1.35;
}
.header-title .accent {
color: var(--brand);
font-weight: 600;
}
.header-id {
margin-top: 4px;
font-size: 11px;
color: var(--text-faint);
font-weight: 600;
letter-spacing: .03em;
}
.header-tag {
padding: 5px 9px;
background: #f1f5f9;
border-radius: 4px;
font-size: 10px;
font-weight: 800;
color: #64748b;
text-transform: uppercase;
white-space: nowrap;
border: 1px solid #e2e8f0;
}
.meta-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
text-align: center;
}
.meta-item {
background: #f8fafc;
border: 1px solid #f1f5f9;
border-radius: 4px;
padding: 9px 5px 7px;
}
.meta-value {
font-size: 12px;
font-weight: 800;
color: #475569;
}
.meta-value.brand {
color: var(--brand);
}
.topic-radar {
margin-top: 12px;
}
.topic-tags {
margin-top: 6px;
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.topic-tag {
padding: 3px 8px;
border-radius: 999px;
font-size: 10px;
font-weight: 700;
color: #334155;
background: #f8fafc;
border: 1px solid #e2e8f0;
}
.summary-body {
padding: 18px 20px 20px;
}
.lead-callout {
margin-top: 10px;
padding: 10px 12px;
background: var(--ok-soft);
border-left: 2px solid var(--ok-line);
border-radius: 0 6px 6px 0;
font-size: 13px;
line-height: 1.78;
color: #166534;
}
.topics {
margin-top: 12px;
display: flex;
flex-direction: column;
gap: 10px;
}
.topic-card {
border: 1px solid #e5eaf1;
background: #ffffff;
border-radius: 8px;
padding: 10px 11px;
}
.topic-title {
margin: 0 0 8px;
font-size: 14px;
font-weight: 800;
color: var(--title);
letter-spacing: -.01em;
}
.topic-meta {
margin: 0 0 8px;
padding: 8px 9px;
border-radius: 6px;
background: #f8fafc;
border: 1px dashed #dbe4f2;
font-size: 11px;
line-height: 1.65;
color: #5b6b84;
}
.topic-block {
display: flex;
flex-direction: column;
gap: 6px;
}
.topic-subtitle {
margin: 0;
font-size: 10px;
text-transform: uppercase;
letter-spacing: .08em;
color: #94a3b8;
font-weight: 800;
}
.item-paragraph {
margin: 0;
font-size: 13px;
line-height: 1.82;
color: var(--text);
}
.item-bullet {
margin: 0;
padding-left: 14px;
position: relative;
font-size: 13px;
line-height: 1.78;
color: var(--text);
}
.item-bullet::before {
content: "•";
position: absolute;
left: 0;
top: 0;
color: var(--brand);
font-weight: 900;
}
.item-quote {
margin: 0;
padding: 8px 10px;
border-left: 3px solid var(--quote-line);
background: var(--quote-bg);
color: #475569;
border-radius: 0 4px 4px 0;
font-size: 12px;
line-height: 1.75;
}
.item-code {
margin: 0;
padding: 10px 11px;
border-radius: 6px;
background: var(--code-bg);
color: var(--code-text);
border: 1px solid #1e293b;
/* 说明:代码字体优先使用本地/系统等宽字体栈,保证服务端离线场景可读。 */
font-family: var(--abot-font-code, "Cascadia Mono", "Consolas", "SFMono-Regular", Menlo, monospace);
font-size: 12px;
line-height: 1.7;
white-space: pre-wrap;
word-break: break-word;
}
.summary-footer {
margin-top: 14px;
padding-top: 10px;
border-top: 1px dashed #e2e8f0;
font-size: 10px;
color: var(--text-faint);
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
}
.summary-footer .right {
font-size: 9px;
color: #94a3b8;
letter-spacing: .04em;
text-transform: uppercase;
white-space: nowrap;
}
.safe-callout {
margin-top: 10px;
padding: 8px 10px;
background: var(--ok-soft);
border-left: 2px solid var(--ok-line);
border-radius: 0 4px 4px 0;
font-size: 12px;
color: #166534;
}
.fallback-text {
margin-top: 10px;
font-size: 12px;
line-height: 1.76;
color: #475569;
white-space: pre-wrap;
}
.summary-grid {
display: grid;
grid-template-columns: 1.45fr 1fr;
gap: 10px;
margin-top: 12px;
}
.aux-sections {
margin-top: 12px;
display: flex;
flex-direction: column;
gap: 8px;
}
.aux-card {
border: 1px solid #e8edf5;
border-radius: 7px;
padding: 9px 10px;
background: #fff;
}
.aux-title {
margin: 0 0 6px;
font-size: 12px;
font-weight: 800;
color: #334155;
}
.aux-item {
margin: 0;
font-size: 12px;
line-height: 1.68;
color: #475569;
}
.mini-card {
border: 1px solid #e5eaf1;
border-radius: 8px;
padding: 10px 11px;
background: #fff;
}
.mini-title {
margin: 0 0 8px;
font-size: 10px;
text-transform: uppercase;
letter-spacing: .08em;
color: #94a3b8;
font-weight: 800;
}
.mini-list {
display: flex;
flex-direction: column;
gap: 5px;
}
.mini-row {
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
font-size: 12px;
color: #475569;
}
.mini-row .value {
font-weight: 800;
color: #1e293b;
font-family: var(--abot-font-code, "Cascadia Mono", "Consolas", monospace);
}
.highlight-list {
display: flex;
flex-direction: column;
gap: 6px;
}
.highlight-item {
margin: 0;
font-size: 12px;
line-height: 1.72;
color: #334155;
padding-left: 12px;
position: relative;
}
.highlight-item::before {
content: "";
position: absolute;
left: 0;
top: 7px;
width: 5px;
height: 5px;
border-radius: 50%;
background: #2563eb;
}
@media (max-width: 640px) {
.summary-grid {
grid-template-columns: 1fr;
}
.meta-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
</style>
</head>
<body>
<div class="report-container">
<header class="header">
<div class="header-row">
<div>
<div class="header-title">CHAT INSIGHTS <span class="accent">SUMMARY</span></div>
<div class="header-id">{{ generated_at }}</div>
</div>
<div class="header-tag">{{ summary_metrics.activity_badge or "Daily Archive" }}</div>
</div>
<div class="meta-grid">
{% for card in summary_metrics.kpi_cards %}
<div class="meta-item">
<span class="label-tiny">{{ card.label }}</span>
<div class="meta-value {% if card.tone == 'blue' %}brand{% endif %}">{{ card.value }}</div>
</div>
{% endfor %}
</div>
<div class="topic-radar">
<span class="label-tiny"># Personal Interest Radar</span>
<div class="topic-tags">
{% for tag in summary_metrics.topic_tags %}
<span class="topic-tag">{{ tag }}</span>
{% endfor %}
{% if not summary_metrics.topic_tags %}
<span class="topic-tag">暂无热点标签</span>
{% endif %}
</div>
</div>
</header>
<section class="summary-body">
<span class="label-tiny"># {{ summary_doc_title or title }}</span>
<div class="lead-callout">
{{ summary_lead or "暂无总结内容。" }}
</div>
<div class="topics">
{% for topic in summary_topics %}
<article class="topic-card">
<h3 class="topic-title">{{ loop.index }}. {{ topic["title"] }}</h3>
<div class="topic-meta">
{% if topic["time_range"] %}<div>🕒 {{ topic["time_range"] }}</div>{% endif %}
{% if topic["participants"] %}<div>👥 {{ topic["participants"] }}</div>{% endif %}
</div>
{% if topic["overview_points"] %}
<div class="topic-block">
<p class="topic-subtitle">核心观点</p>
{% for line in topic["overview_points"] %}
<p class="item-bullet">{{ line }}</p>
{% endfor %}
</div>
{% endif %}
{% if topic["analysis_points"] %}
<div class="topic-block">
<p class="topic-subtitle">客观分析</p>
{% for line in topic["analysis_points"] %}
<p class="item-paragraph">{{ line }}</p>
{% endfor %}
</div>
{% endif %}
{% if topic["quote_text"] %}
<div class="topic-block">
<p class="topic-subtitle">亮点瞬间</p>
<blockquote class="item-quote">{{ topic["quote_text"] }}</blockquote>
</div>
{% endif %}
</article>
{% endfor %}
</div>
{% if not summary_topics %}
<div class="fallback-text">{{ summary_fallback_text }}</div>
{% endif %}
{% if summary_aux_sections %}
<div class="aux-sections">
{% for block in summary_aux_sections %}
<article class="aux-card">
<h4 class="aux-title">{{ block["title"] }}</h4>
{% for line in block["items"] %}
<p class="aux-item">• {{ line }}</p>
{% endfor %}
</article>
{% endfor %}
</div>
{% endif %}
<div class="summary-grid">
<div class="mini-card">
<h4 class="mini-title"># Deep Stats</h4>
<div class="mini-list">
{% for item in summary_metrics.mini_stats %}
<div class="mini-row">
<span>{{ item.label }}</span>
<span class="value">{{ item.value }}</span>
</div>
{% endfor %}
</div>
</div>
<div class="mini-card">
<h4 class="mini-title"># Core Highlights</h4>
<div class="highlight-list">
{% for text in summary_metrics.highlights %}
<p class="highlight-item">{{ text }}</p>
{% endfor %}
{% if not summary_metrics.highlights %}
<p class="highlight-item">暂无可提取的核心看点</p>
{% endif %}
</div>
</div>
</div>
<div class="safe-callout">内容已按结构化规则重排渲染,不再直接内嵌原始 HTML。</div>
<div class="summary-footer">
<span>ABOT · Message Summary Gemini Style</span>
<span class="right">Tokens: {{ summary_metrics.token_total }} · Latency: {{ summary_metrics.latency_text }}</span>
</div>
</section>
</div>
</body>
</html>