From 6cf63bc494712220920453f25206734aefa7716a Mon Sep 17 00:00:00 2001 From: liuwei Date: Thu, 23 Apr 2026 09:57:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E4=B8=BA=E6=9C=AC=E5=9C=B0=20fonts=20?= =?UTF-8?q?=E5=AD=97=E4=BD=93=E6=B8=B2=E6=9F=93=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 message_summary 插件中新增本地字体 CSS 构建逻辑,动态注入模板\n- 使用 fonts/simhei.ttf 与 fonts/simsun.ttf 生成 @font-face,避免外网字体依赖\n- Gemini 总结模板移除 Google Fonts,改用本地字体变量与系统回退栈\n- 补充详细中文注释,说明离线字体加载与容错策略 --- plugins/message_summary/main.py | 56 +++++++++++++++++++ .../templates/gemini_summary_card.html | 10 ++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/plugins/message_summary/main.py b/plugins/message_summary/main.py index f1e07e7..74a21ee 100644 --- a/plugins/message_summary/main.py +++ b/plugins/message_summary/main.py @@ -521,15 +521,71 @@ class MessageSummaryPlugin(MessagePluginInterface): # 约束:模板只负责展示,正文仍然由模型生成并在此做安全转义后注入。 renderer = HtmlTemplateRenderer() summary_html = self._summary_markdown_to_html(summary_text) + # 说明: + # 1. 这里注入“本地字体 CSS”到模板,避免依赖 Google Fonts 等外网资源; + # 2. 字体文件统一从仓库根目录 fonts/ 下读取,便于部署时统一管理; + # 3. 若字体文件缺失,自动回退系统字体,不影响功能可用性。 + local_font_css = self._build_local_font_css() return renderer.render( self._summary_image_template_path, { "title": f"{group_name} 群聊总结", "generated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "summary_html": Markup(summary_html), + "local_font_css": Markup(local_font_css), }, ) + def _build_local_font_css(self) -> str: + """构建模板可注入的本地字体 CSS。""" + # 说明: + # 1. 使用绝对 file:/// URI,确保 Playwright set_content 场景下也能正确定位字体文件; + # 2. 按存在性逐个注册字体,避免硬编码导致不存在文件时报错; + # 3. 仅返回 CSS 字符串,不在此处抛异常,保证模板渲染链路稳定。 + try: + project_root = Path(__file__).resolve().parents[2] + font_dir = project_root / "fonts" + + simhei_path = font_dir / "simhei.ttf" + simsun_path = font_dir / "simsun.ttf" + + css_parts: List[str] = [] + if simhei_path.exists(): + css_parts.append( + "@font-face {" + "font-family: 'ABotSimHei'; " + f"src: url('{simhei_path.resolve().as_uri()}') format('truetype'); " + "font-weight: 400 900; " + "font-style: normal; " + "font-display: swap; " + "}" + ) + if simsun_path.exists(): + css_parts.append( + "@font-face {" + "font-family: 'ABotSimSun'; " + f"src: url('{simsun_path.resolve().as_uri()}') format('truetype'); " + "font-weight: 400 700; " + "font-style: normal; " + "font-display: swap; " + "}" + ) + + # 说明: + # 1. 通过 CSS 变量统一字体栈,模板端只需引用变量即可; + # 2. 先使用本地字体,再回退系统字体,兼顾一致性和容错性。 + css_parts.append( + ":root { " + "--abot-font-sans: 'ABotSimHei', 'ABotSimSun', 'PingFang SC', " + "'Microsoft YaHei', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; " + "--abot-font-code: 'Cascadia Mono', 'JetBrains Mono', 'Consolas', 'SFMono-Regular', Menlo, monospace; " + "}" + ) + return "\n".join(css_parts) + except Exception as e: + self.LOG.warning(f"构建本地字体 CSS 失败,回退系统字体: {e}") + return "" + async def _render_summary_image( self, answer: str, diff --git a/plugins/message_summary/templates/gemini_summary_card.html b/plugins/message_summary/templates/gemini_summary_card.html index 7ec3c83..617401d 100644 --- a/plugins/message_summary/templates/gemini_summary_card.html +++ b/plugins/message_summary/templates/gemini_summary_card.html @@ -5,8 +5,8 @@ {{ title }}