- 新增模板统计视图模型,接入消息总数/活跃人数/文本量/媒体量等核心指标\n- 追加深度统计卡片(Links/Emoji/Video/Sections/Bullets/Quotes/Code)并展示活跃等级\n- 从结构化章节提取话题雷达标签与核心看点,提升信息可读性\n- 调整模板为高信息密度布局,参考 gemini-code 风格进行 KPI、标签与双栏信息区展示\n- 模板模式下停止在正文拼接群概览与 tokens 文本,改由可视化卡片与页脚指标展示\n- 完善渲染链路参数传递:message_stats 与 metadata 全量传入模板渲染
416 lines
14 KiB
HTML
416 lines
14 KiB
HTML
<!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-face(fonts 目录),避免外网字体依赖。 */
|
||
{{ 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;
|
||
}
|
||
.sections {
|
||
margin-top: 12px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
.section-card {
|
||
border: 1px solid #e5eaf1;
|
||
background: #ffffff;
|
||
border-radius: 8px;
|
||
padding: 10px 11px;
|
||
}
|
||
.section-title {
|
||
margin: 0 0 8px;
|
||
font-size: 14px;
|
||
font-weight: 800;
|
||
color: var(--title);
|
||
letter-spacing: -.01em;
|
||
}
|
||
.section-items {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
.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;
|
||
}
|
||
.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="sections">
|
||
{% for section in summary_sections %}
|
||
<article class="section-card">
|
||
<h3 class="section-title">{{ section["title"] }}</h3>
|
||
<div class="section-items">
|
||
{% for item in section["items"] %}
|
||
{% if item["kind"] == "bullet" %}
|
||
<p class="item-bullet">{{ item["text"] }}</p>
|
||
{% elif item["kind"] == "quote" %}
|
||
<blockquote class="item-quote">{{ item["text"] }}</blockquote>
|
||
{% elif item["kind"] == "code" %}
|
||
<pre class="item-code">{{ item["text"] }}</pre>
|
||
{% else %}
|
||
<p class="item-paragraph">{{ item["text"] }}</p>
|
||
{% endif %}
|
||
{% endfor %}
|
||
</div>
|
||
</article>
|
||
{% endfor %}
|
||
</div>
|
||
{% if not summary_sections %}
|
||
<div class="fallback-text">{{ summary_fallback_text }}</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>
|