mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 13:38:43 +00:00
fix: 报告生成器硬编码了 QQ 头像 API (qlogo.cn),导致 Discord 用户显示默认/错误的 QQ 头像。
修复: 修改 ReportGenerator,允许传入自定义的 avatar_getter 回调。
This commit is contained in:
@@ -316,12 +316,27 @@ class QQGroupDailyAnalysis(Star):
|
||||
# 8. 生成并发送报告
|
||||
output_format = self.config_manager.get_output_format()
|
||||
|
||||
# 定义头像获取回调
|
||||
async def avatar_getter(user_id: str) -> str | None:
|
||||
if not orchestrator:
|
||||
return None
|
||||
try:
|
||||
# orchestrator.get_member_avatars 接受列表返回字典
|
||||
avatars = await orchestrator.get_member_avatars([user_id])
|
||||
return avatars.get(user_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"获取头像失败 {user_id}: {e}")
|
||||
return None
|
||||
|
||||
if output_format == "image":
|
||||
(
|
||||
image_url,
|
||||
html_content,
|
||||
) = await self.report_generator.generate_image_report(
|
||||
analysis_result, group_id, self.html_render
|
||||
analysis_result,
|
||||
group_id,
|
||||
self.html_render,
|
||||
avatar_getter=avatar_getter,
|
||||
)
|
||||
|
||||
if image_url:
|
||||
@@ -358,7 +373,7 @@ class QQGroupDailyAnalysis(Star):
|
||||
return
|
||||
|
||||
pdf_path = await self.report_generator.generate_pdf_report(
|
||||
analysis_result, group_id
|
||||
analysis_result, group_id, avatar_getter=avatar_getter
|
||||
)
|
||||
|
||||
if pdf_path:
|
||||
|
||||
+62
-13
@@ -25,21 +25,31 @@ class ReportGenerator:
|
||||
self.html_templates = HTMLTemplates(config_manager) # 实例化HTML模板管理器
|
||||
|
||||
async def generate_image_report(
|
||||
self, analysis_result: dict, group_id: str, html_render_func
|
||||
self,
|
||||
analysis_result: dict,
|
||||
group_id: str,
|
||||
html_render_func,
|
||||
avatar_getter=None,
|
||||
) -> tuple[str | None, str | None]:
|
||||
"""
|
||||
生成图片格式的分析报告
|
||||
|
||||
Args:
|
||||
analysis_result: 分析结果字典
|
||||
group_id: 群组ID
|
||||
html_render_func: HTML渲染函数
|
||||
avatar_getter: 异步回调函数,接收 user_id 返回 avatar_url/data
|
||||
|
||||
Returns:
|
||||
tuple[str | None, str | None]: (image_url, html_content)
|
||||
- image_url: 生成的图片URL,如果生成失败则为None
|
||||
- html_content: 生成的HTML内容,如果渲染失败但HTML生成成功,则返回此内容供重试
|
||||
"""
|
||||
html_content = None
|
||||
try:
|
||||
# 准备渲染数据
|
||||
render_payload = await self._prepare_render_data(
|
||||
analysis_result, chart_template="activity_chart.html"
|
||||
analysis_result,
|
||||
chart_template="activity_chart.html",
|
||||
avatar_getter=avatar_getter,
|
||||
)
|
||||
|
||||
# 先渲染HTML模板(使用异步方法)
|
||||
@@ -125,7 +135,7 @@ class ReportGenerator:
|
||||
return None, html_content
|
||||
|
||||
async def generate_pdf_report(
|
||||
self, analysis_result: dict, group_id: str
|
||||
self, analysis_result: dict, group_id: str, avatar_getter=None
|
||||
) -> str | None:
|
||||
"""生成PDF格式的分析报告"""
|
||||
try:
|
||||
@@ -142,7 +152,9 @@ class ReportGenerator:
|
||||
|
||||
# 准备渲染数据
|
||||
render_data = await self._prepare_render_data(
|
||||
analysis_result, chart_template="activity_chart_pdf.html"
|
||||
analysis_result,
|
||||
chart_template="activity_chart_pdf.html",
|
||||
avatar_getter=avatar_getter,
|
||||
)
|
||||
logger.info(f"PDF 渲染数据准备完成,包含 {len(render_data)} 个字段")
|
||||
|
||||
@@ -211,7 +223,10 @@ class ReportGenerator:
|
||||
return report
|
||||
|
||||
async def _prepare_render_data(
|
||||
self, analysis_result: dict, chart_template: str = "activity_chart.html"
|
||||
self,
|
||||
analysis_result: dict,
|
||||
chart_template: str = "activity_chart.html",
|
||||
avatar_getter=None,
|
||||
) -> dict:
|
||||
"""准备渲染数据"""
|
||||
stats = analysis_result["statistics"]
|
||||
@@ -241,7 +256,7 @@ class ReportGenerator:
|
||||
titles_list = []
|
||||
for title in user_titles[:max_user_titles]:
|
||||
# 获取用户头像
|
||||
avatar_data = await self._get_user_avatar(str(title.qq))
|
||||
avatar_data = await self._get_user_avatar(str(title.qq), avatar_getter)
|
||||
title_data = {
|
||||
"name": title.name,
|
||||
"title": title.title,
|
||||
@@ -261,7 +276,9 @@ class ReportGenerator:
|
||||
quotes_list = []
|
||||
for quote in stats.golden_quotes[:max_golden_quotes]:
|
||||
avatar_url = (
|
||||
await self._get_user_avatar(str(quote.qq)) if quote.qq else None
|
||||
await self._get_user_avatar(str(quote.qq), avatar_getter)
|
||||
if quote.qq
|
||||
else None
|
||||
)
|
||||
quotes_list.append(
|
||||
{
|
||||
@@ -337,13 +354,45 @@ class ReportGenerator:
|
||||
|
||||
return result
|
||||
|
||||
async def _get_user_avatar(self, user_id: str) -> str | None:
|
||||
async def _get_user_avatar(self, user_id: str, avatar_getter=None) -> str | None:
|
||||
"""获取用户头像的base64编码"""
|
||||
try:
|
||||
avatar_url = f"https://q4.qlogo.cn/headimg_dl?dst_uin={user_id}&spec=100"
|
||||
# 1. 如果提供了 avatar_getter,优先使用它获取 avatar_url
|
||||
avatar_url = None
|
||||
if avatar_getter:
|
||||
try:
|
||||
# avatar_getter 可能返回 URL 或直接返回 base64
|
||||
# 假定它返回 img URL,后续我们自己下载转 base64
|
||||
# 或者如果它返回 data:image 格式(base64),则直接使用
|
||||
result = await avatar_getter(user_id)
|
||||
if result:
|
||||
if result.startswith("data:image"):
|
||||
return result
|
||||
avatar_url = result
|
||||
except Exception as e:
|
||||
logger.warning(f"使用 custom avatar_getter 获取头像失败: {e}")
|
||||
|
||||
# 2. 如果没有 avatar_getter 或获取失败,使用默认 QQ 头像逻辑(仅当 user_id 看起来像 QQ 号时?)
|
||||
# 为保持兼容性,如果 avatar_url 仍为 None,且不强制禁用 QQ 默认,则使用 QQ 逻辑
|
||||
if not avatar_url:
|
||||
if (
|
||||
user_id.isdigit() and 5 <= len(user_id) <= 12
|
||||
): # 简单判断是否可能是 QQ 号
|
||||
avatar_url = (
|
||||
f"https://q4.qlogo.cn/headimg_dl?dst_uin={user_id}&spec=100"
|
||||
)
|
||||
else:
|
||||
return None # 非 QQ 号且无 avatar_getter,返回 None 使用默认占位符
|
||||
|
||||
if not avatar_url:
|
||||
return None
|
||||
|
||||
async with aiohttp.ClientSession() as client:
|
||||
async with client.get(avatar_url) as response:
|
||||
response.raise_for_status()
|
||||
async with client.get(avatar_url, timeout=10) as response:
|
||||
if response.status != 200:
|
||||
logger.warning(f"下载头像失败 {avatar_url}: {response.status}")
|
||||
return None
|
||||
|
||||
avatar_data = await response.read()
|
||||
|
||||
if not isinstance(avatar_data, bytes):
|
||||
|
||||
Reference in New Issue
Block a user