diff --git a/plugins/message_summary/main.py b/plugins/message_summary/main.py index 1c7cad1..df7b485 100644 --- a/plugins/message_summary/main.py +++ b/plugins/message_summary/main.py @@ -110,6 +110,13 @@ class MessageSummaryPlugin(MessagePluginInterface): self._summary_image_template_path = str( output_config.get("summary_image_template_path", "plugins/message_summary/templates/summary_card.html") ).strip() + # 模板截图视口参数: + # 1. 支持在插件配置中单独传入宽度/高度/缩放; + # 2. 默认保持历史值(780/960/1.2),避免影响未配置场景; + # 3. 仅在 template 模式生图时使用,markdown 模式不受影响。 + self._template_viewport_width = int(output_config.get("template_viewport_width", 780)) + self._template_viewport_height = int(output_config.get("template_viewport_height", 960)) + self._template_device_scale_factor = float(output_config.get("template_device_scale_factor", 1.2)) self.llm_client = UnifiedLLMClient(api_config) self._api_mode = self.llm_client.mode or self._api_mode self._response_mode = self.llm_client.response_mode or self._response_mode @@ -1489,7 +1496,16 @@ class MessageSummaryPlugin(MessagePluginInterface): message_stats=message_stats, metadata=metadata, ) - await asyncio.wait_for(html_to_image(html_content, str(output_path)), timeout=total_timeout) + await asyncio.wait_for( + html_to_image( + html_content, + str(output_path), + viewport_width=self._template_viewport_width, + viewport_height=self._template_viewport_height, + device_scale_factor=self._template_device_scale_factor, + ), + timeout=total_timeout, + ) if not output_path.exists() or output_path.stat().st_size < 1024: raise RuntimeError("模板截图输出文件异常") return str(output_path.resolve()) diff --git a/utils/markdown_to_image.py b/utils/markdown_to_image.py index 8fd377a..9185109 100644 --- a/utils/markdown_to_image.py +++ b/utils/markdown_to_image.py @@ -633,14 +633,35 @@ class _PersistentBrowser: return self._heartbeat_task = asyncio.create_task(self._heartbeat_loop(), name="md2img:heartbeat") - async def screenshot(self, html_content: str, output_image: str): + async def screenshot( + self, + html_content: str, + output_image: str, + viewport_width: int = 780, + viewport_height: int = 960, + device_scale_factor: float = 1.2, + ): browser = await self.ensure_browser() async def _capture_with_browser(active_browser): self._capture_in_progress = True context = None try: - context = await active_browser.new_context(viewport={"width": 780, "height": 960}, device_scale_factor=1.2) + # 说明: + # 1. 允许调用方按业务场景传入截图宽度(例如卡片模板可用更窄视口); + # 2. 默认值保持历史行为,确保未改造调用方不受影响; + # 3. 这里做最小边界保护,避免传入异常值导致 Playwright 抛错。 + safe_width = max(320, int(viewport_width or 780)) + safe_height = max(320, int(viewport_height or 960)) + safe_scale = float(device_scale_factor or 1.2) + if safe_scale < 1.0: + safe_scale = 1.0 + if safe_scale > 3.0: + safe_scale = 3.0 + context = await active_browser.new_context( + viewport={"width": safe_width, "height": safe_height}, + device_scale_factor=safe_scale, + ) page = await context.new_page() logger.debug("Set page content") await page.set_content(html_content, wait_until='domcontentloaded', timeout=15000) @@ -893,7 +914,13 @@ def warmup_md2img_browser_sync(timeout_seconds: int = 45) -> bool: return False -async def html_to_image(html_content, output_image): +async def html_to_image( + html_content, + output_image, + viewport_width: int = 780, + viewport_height: int = 960, + device_scale_factor: float = 1.2, +): """将 HTML 渲染为图片。 说明: @@ -903,7 +930,13 @@ async def html_to_image(html_content, output_image): async def _html_to_image_impl(): manager = _get_browser_manager() - await manager.screenshot(html_content, output_image) + await manager.screenshot( + html_content, + output_image, + viewport_width=viewport_width, + viewport_height=viewport_height, + device_scale_factor=device_scale_factor, + ) await _run_in_md2img_runtime(_html_to_image_impl())