feat(message_summary): beautify overview stats pills
This commit is contained in:
@@ -528,11 +528,19 @@ class MessageSummaryPlugin(MessagePluginInterface):
|
||||
if not summary or not summary.strip():
|
||||
return summary
|
||||
|
||||
pairs = [
|
||||
("总", int(stats.get("total_count") or 0)),
|
||||
("人数", int(stats.get("participant_count") or 0)),
|
||||
("文本", int(stats.get("text_count") or 0)),
|
||||
("图片", int(stats.get("image_count") or 0)),
|
||||
("视频", int(stats.get("video_count") or 0)),
|
||||
("链接", int(stats.get("link_count") or 0)),
|
||||
("表情", int(stats.get("emoji_count") or 0)),
|
||||
]
|
||||
stats_line = " · ".join([f"**{label}** {value}" for label, value in pairs])
|
||||
section_lines = [
|
||||
"## 群概览",
|
||||
f"- 📊 总:{int(stats.get('total_count') or 0)} 👥 人:{int(stats.get('participant_count') or 0)}\n"
|
||||
f"- 💬 文:{int(stats.get('text_count') or 0)} 🖼 图:{int(stats.get('image_count') or 0)} 🎬 视:{int(stats.get('video_count') or 0)}\n"
|
||||
f"- 🔗 链:{int(stats.get('link_count') or 0)} 😄 表:{int(stats.get('emoji_count') or 0)}"
|
||||
stats_line,
|
||||
]
|
||||
section = "\n".join(section_lines)
|
||||
return f"{section}\n\n{summary.strip()}"
|
||||
|
||||
@@ -15,6 +15,43 @@ except ImportError:
|
||||
markdown = None
|
||||
|
||||
META_KEYWORDS = ["群", "群名", "时间", "日期", "成员", "消息", "统计", "总结", "来源", "生成", "记录"]
|
||||
STAT_PILL_CLASSES = {
|
||||
"总": "total",
|
||||
"人数": "people",
|
||||
"文本": "text",
|
||||
"图片": "image",
|
||||
"视频": "video",
|
||||
"链接": "link",
|
||||
"表情": "emoji",
|
||||
}
|
||||
|
||||
|
||||
def _extract_stats_pills_from_markdown(md_content: str) -> str:
|
||||
text = str(md_content or "")
|
||||
pattern = re.compile(
|
||||
r"(^##\s+群概览\s*\n)([^\n]+)(?=\n(?:\n|##\s|###\s|$))",
|
||||
re.M,
|
||||
)
|
||||
|
||||
def replace(match):
|
||||
stats_line = match.group(2).strip()
|
||||
parts = [part.strip() for part in stats_line.split("·") if part.strip()]
|
||||
pills = []
|
||||
for part in parts:
|
||||
item_match = re.match(r"(?:\*\*)?([^*\s]+)(?:\*\*)?\s+(\d+)", part)
|
||||
if not item_match:
|
||||
continue
|
||||
label = item_match.group(1).strip()
|
||||
value = item_match.group(2).strip()
|
||||
kind = STAT_PILL_CLASSES.get(label, "default")
|
||||
pills.append(
|
||||
f'<span class="stats-pill stats-pill-{kind}"><span class="stats-pill-label">{label}</span><span class="stats-pill-value">{value}</span></span>'
|
||||
)
|
||||
if not pills:
|
||||
return match.group(0)
|
||||
return match.group(1) + f'<div class="stats-pills">{"".join(pills)}</div>'
|
||||
|
||||
return pattern.sub(replace, text, count=1)
|
||||
|
||||
def _simple_markdown_to_html(md_content: str) -> str:
|
||||
lines = str(md_content or "").splitlines()
|
||||
@@ -58,6 +95,11 @@ def _simple_markdown_to_html(md_content: str) -> str:
|
||||
close_ul()
|
||||
html_parts.append(f"<h3>{stripped[4:].strip()}</h3>")
|
||||
continue
|
||||
if stripped.startswith("<div ") and stripped.endswith("</div>"):
|
||||
flush_paragraph()
|
||||
close_ul()
|
||||
html_parts.append(stripped)
|
||||
continue
|
||||
if stripped.startswith("- "):
|
||||
flush_paragraph()
|
||||
if not in_ul:
|
||||
@@ -165,6 +207,7 @@ def _split_hero(html_body: str):
|
||||
|
||||
|
||||
async def md_str_to_html_content(md_content):
|
||||
md_content = _extract_stats_pills_from_markdown(md_content)
|
||||
if markdown is not None:
|
||||
html_body = markdown.markdown(md_content, extensions=['extra', 'codehilite'])
|
||||
else:
|
||||
@@ -354,6 +397,48 @@ async def md_str_to_html_content(md_content):
|
||||
border-radius: 14px;
|
||||
color: #355468;
|
||||
}
|
||||
.stats-pills {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin: 12px 0 8px;
|
||||
}
|
||||
.stats-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 7px 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.92em;
|
||||
line-height: 1;
|
||||
border: 1px solid rgba(148,163,184,0.16);
|
||||
background: linear-gradient(180deg, rgba(255,255,255,0.96), rgba(248,250,252,0.92));
|
||||
color: #334155;
|
||||
box-shadow: 0 8px 18px rgba(15,23,42,0.05);
|
||||
}
|
||||
.stats-pill-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.82em;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
background: linear-gradient(135deg, #64748b, #475569);
|
||||
}
|
||||
.stats-pill-value {
|
||||
font-weight: 800;
|
||||
color: #1e293b;
|
||||
min-width: 20px;
|
||||
}
|
||||
.stats-pill-total .stats-pill-label { background: linear-gradient(135deg, #3b82f6, #1d4ed8); }
|
||||
.stats-pill-people .stats-pill-label { background: linear-gradient(135deg, #0f766e, #14b8a6); }
|
||||
.stats-pill-text .stats-pill-label { background: linear-gradient(135deg, #8b5cf6, #7c3aed); }
|
||||
.stats-pill-image .stats-pill-label { background: linear-gradient(135deg, #ec4899, #db2777); }
|
||||
.stats-pill-video .stats-pill-label { background: linear-gradient(135deg, #f97316, #ea580c); }
|
||||
.stats-pill-link .stats-pill-label { background: linear-gradient(135deg, #22c55e, #16a34a); }
|
||||
.stats-pill-emoji .stats-pill-label { background: linear-gradient(135deg, #eab308, #ca8a04); }
|
||||
hr { border: none; height: 1px; background: linear-gradient(90deg, transparent, rgba(148,163,184,0.35), transparent); margin: 26px 0; }
|
||||
a { color: var(--primary); text-decoration: none; border-bottom: 1px dashed rgba(109,94,252,0.35); }
|
||||
.signature { margin-top: 34px; text-align: right; color: #73849c; font-size: 0.95em; font-style: italic; }
|
||||
|
||||
Reference in New Issue
Block a user