refactor: 全局变量重构,受保护成员访问修复,同步 I/O 操作异步化

This commit is contained in:
SXP-Simon
2026-01-07 00:28:35 +08:00
committed by Helian Nuits
parent 64ae5e1a6d
commit 4297bf4f99
4 changed files with 177 additions and 167 deletions
+8 -10
View File
@@ -32,10 +32,9 @@ class ReportGenerator:
# 准备渲染数据
render_payload = await self._prepare_render_data(analysis_result)
# 先渲染HTML模板
html_content = self._render_html_template(
self.html_templates.get_image_template(), render_payload
)
# 先渲染HTML模板(使用异步方法)
image_template = await self.html_templates.get_image_template_async()
html_content = self._render_html_template(image_template, render_payload)
# 检查HTML内容是否有效
if not html_content:
@@ -88,9 +87,9 @@ class ReportGenerator:
) -> str | None:
"""生成PDF格式的分析报告"""
try:
# 确保输出目录存在
# 确保输出目录存在(使用 asyncio.to_thread 避免阻塞)
output_dir = Path(self.config_manager.get_pdf_output_dir())
output_dir.mkdir(parents=True, exist_ok=True)
await asyncio.to_thread(output_dir.mkdir, parents=True, exist_ok=True)
# 生成文件名
current_date = datetime.now().strftime("%Y%m%d")
@@ -103,10 +102,9 @@ class ReportGenerator:
render_data = await self._prepare_render_data(analysis_result)
logger.info(f"PDF 渲染数据准备完成,包含 {len(render_data)} 个字段")
# 生成 HTML 内容(PDF模板使用{{}}占位符
html_content = self._render_html_template(
self.html_templates.get_pdf_template(), render_data
)
# 生成 HTML 内容(使用异步方法
pdf_template = await self.html_templates.get_pdf_template_async()
html_content = self._render_html_template(pdf_template, render_data)
# 检查HTML内容是否有效
if not html_content:
+48 -18
View File
@@ -3,6 +3,7 @@ HTML模板模块
使用Jinja2加载外部HTML模板文件
"""
import asyncio
import os
from jinja2 import Environment, FileSystemLoader, select_autoescape
@@ -21,12 +22,11 @@ class HTMLTemplates:
# 缓存不同模板的Jinja2环境
self._envs = {}
def _get_env(self) -> Environment:
"""获取当前配置的模板环境"""
def _get_env_sync(self) -> Environment:
"""获取当前配置的模板环境(同步版本,供 asyncio.to_thread 调用)"""
template_name = self.config_manager.get_report_template()
# 如果环境已缓存且配置未变(这里简单假设配置变了会重新获取,或者我们可以每次都检查)
# 为了响应配置热更,我们每次都检查一下或者简单地按需创建
# 如果环境已缓存且配置未变
if template_name in self._envs:
return self._envs[template_name]
@@ -34,7 +34,6 @@ class HTMLTemplates:
if not os.path.exists(template_dir):
logger.warning(f"模板目录不存在: {template_dir},回退到 scrapbook")
template_dir = os.path.join(self.base_dir, "scrapbook")
# 如果 scrapbook 也不存在,那就有大问题了,不过这里假设 scrapbook 一定存在
env = Environment(
loader=FileSystemLoader(template_dir),
@@ -45,31 +44,62 @@ class HTMLTemplates:
self._envs[template_name] = env
return env
def get_image_template(self) -> str:
"""获取图片报告的HTML模板(返回原始模板字符串"""
async def _get_env_async(self) -> Environment:
"""获取当前配置的模板环境(异步版本"""
return await asyncio.to_thread(self._get_env_sync)
def _get_env(self) -> Environment:
"""获取当前配置的模板环境(同步版本,向后兼容)"""
return self._get_env_sync()
def _read_template_file_sync(self, filename: str) -> str:
"""同步读取模板文件内容"""
with open(filename, encoding="utf-8") as f:
return f.read()
async def get_image_template_async(self) -> str:
"""获取图片报告的HTML模板(异步版本,返回原始模板字符串)"""
try:
env = self._get_env()
# 获取模板对象
env = await self._get_env_async()
template = env.get_template("image_template.html")
# 读取原始模板文件内容,而不是渲染它
with open(template.filename, encoding="utf-8") as f:
return f.read()
return await asyncio.to_thread(
self._read_template_file_sync, template.filename
)
except Exception as e:
# 如果加载失败,返回空字符串让调用者处理
logger.error(f"加载图片模板失败: {e}")
return ""
def get_pdf_template(self) -> str:
"""获取PDF报告的HTML模板(返回原始模板字符串"""
def get_image_template(self) -> str:
"""获取图片报告的HTML模板(同步版本,向后兼容"""
try:
env = self._get_env()
# 获取模板对象
template = env.get_template("image_template.html")
with open(template.filename, encoding="utf-8") as f:
return f.read()
except Exception as e:
logger.error(f"加载图片模板失败: {e}")
return ""
async def get_pdf_template_async(self) -> str:
"""获取PDF报告的HTML模板(异步版本,返回原始模板字符串)"""
try:
env = await self._get_env_async()
template = env.get_template("pdf_template.html")
# 读取原始模板文件内容,而不是渲染它
return await asyncio.to_thread(
self._read_template_file_sync, template.filename
)
except Exception as e:
logger.error(f"加载PDF模板失败: {e}")
return ""
def get_pdf_template(self) -> str:
"""获取PDF报告的HTML模板(同步版本,向后兼容)"""
try:
env = self._get_env()
template = env.get_template("pdf_template.html")
with open(template.filename, encoding="utf-8") as f:
return f.read()
except Exception as e:
# 如果加载失败,返回空字符串让调用者处理
logger.error(f"加载PDF模板失败: {e}")
return ""
+5 -5
View File
@@ -46,7 +46,7 @@ class AutoScheduler:
elif bot_qq_ids:
self.bot_manager.set_bot_qq_ids([bot_qq_ids])
async def _get_platform_id_for_group(self, group_id):
async def get_platform_id_for_group(self, group_id):
"""根据群ID获取对应的平台ID"""
try:
# 首先检查已注册的bot实例
@@ -355,7 +355,7 @@ class AutoScheduler:
else:
# 回退到原来的逻辑(单个平台)
logger.warning(f"{group_id} 没有多个平台可用,使用回退逻辑")
platform_id = await self._get_platform_id_for_group(group_id)
platform_id = await self.get_platform_id_for_group(group_id)
if not platform_id:
logger.error(f"❌ 群 {group_id} 无法获取平台ID,跳过分析")
@@ -621,7 +621,7 @@ class AutoScheduler:
)
else:
logger.warning(f"{group_id} 没有多个平台可用,使用回退逻辑")
platform_id = await self._get_platform_id_for_group(group_id)
platform_id = await self.get_platform_id_for_group(group_id)
if not platform_id:
logger.error(f"❌ 群 {group_id} 无法获取平台ID,无法发送图片")
return False
@@ -794,7 +794,7 @@ class AutoScheduler:
else:
# 回退到原来的逻辑(单个平台)
logger.warning(f"{group_id} 没有多个平台可用,使用回退逻辑")
platform_id = await self._get_platform_id_for_group(group_id)
platform_id = await self.get_platform_id_for_group(group_id)
if not platform_id:
logger.error(f"❌ 群 {group_id} 无法获取平台ID,无法发送文本")
@@ -874,7 +874,7 @@ class AutoScheduler:
else:
# 回退到原来的逻辑(单个平台)
logger.warning(f"{group_id} 没有多个平台可用,使用回退逻辑")
platform_id = await self._get_platform_id_for_group(group_id)
platform_id = await self.get_platform_id_for_group(group_id)
if not platform_id:
logger.error(f"❌ 群 {group_id} 无法获取平台ID,无法发送PDF")