From 451dbaa4702e308e4effad322c2d4c8a58a4be92 Mon Sep 17 00:00:00 2001 From: SXP-Simon Date: Mon, 16 Mar 2026 00:43:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(telegram):=20Photo=5Finvalid=5Fdimensions:?= =?UTF-8?q?=20Telegram=20=E6=8A=A5=E9=94=99=E6=8F=90=E7=A4=BA=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=95=BF=E5=AE=BD=E6=AF=94=E4=BE=8B=E6=88=96=E6=80=BB?= =?UTF-8?q?=E5=B0=BA=E5=AF=B8=E4=B8=8D=E5=90=88=E8=A7=84=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BB=A5=E6=96=87=E4=BB=B6=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/adapters/telegram_adapter.py | 110 +++++++++++++----- 1 file changed, 81 insertions(+), 29 deletions(-) diff --git a/src/infrastructure/platform/adapters/telegram_adapter.py b/src/infrastructure/platform/adapters/telegram_adapter.py index cfe8907..f1a288f 100644 --- a/src/infrastructure/platform/adapters/telegram_adapter.py +++ b/src/infrastructure/platform/adapters/telegram_adapter.py @@ -521,7 +521,8 @@ class TelegramAdapter(PlatformAdapter): try: chat_id, message_thread_id = self._parse_group_id(group_id) - photo_obj: Any = None + file_obj: Any = None + is_temp_obj = False kwargs: dict[str, Any] = {"chat_id": chat_id} if message_thread_id: @@ -529,41 +530,62 @@ class TelegramAdapter(PlatformAdapter): if caption: kwargs["caption"] = caption - # 处理本地文件或 URL - if image_path.startswith(("http://", "https://")): - # 远程 URL - 需要下载后发送 + # 1. 统一处理输入源 (Base64 / URL / Local File) + import base64 + import os + from datetime import datetime + if image_path.startswith("base64://"): + data = base64.b64decode(image_path[len("base64://") :]) + file_obj = BytesIO(data) + is_temp_obj = True + elif image_path.startswith("data:"): + parts = image_path.split(",", 1) + if len(parts) == 2: + data = base64.b64decode(parts[1]) + file_obj = BytesIO(data) + is_temp_obj = True + elif image_path.startswith(("http://", "https://")): try: import aiohttp - async with aiohttp.ClientSession() as session: - async with session.get( - image_path, timeout=aiohttp.ClientTimeout(total=30) - ) as resp: + async with session.get(image_path, timeout=aiohttp.ClientTimeout(total=30)) as resp: if resp.status == 200: data = await resp.read() - kwargs["photo"] = BytesIO(data) + file_obj = BytesIO(data) + is_temp_obj = True else: - # 尝试直接发送 URL - kwargs["photo"] = image_path + file_obj = image_path # 尝试直接发 URL except Exception as e: logger.warning(f"[Telegram] 下载图片失败,尝试直接发送: {e}") - kwargs["photo"] = image_path - - photo_obj = kwargs["photo"] - await client.send_photo(**kwargs) + file_obj = image_path else: # 本地文件 - with open(image_path, "rb") as f: - kwargs["photo"] = f - await client.send_photo(**kwargs) + if os.path.exists(image_path): + file_obj = open(image_path, "rb") + is_temp_obj = True + else: + file_obj = image_path - if isinstance(photo_obj, BytesIO): - photo_obj.close() + # 2. 发送图片 + kwargs["photo"] = file_obj + try: + await client.send_photo(**kwargs) + finally: + if is_temp_obj and hasattr(file_obj, "close"): + file_obj.close() return True + except Exception as e: - if "photo_obj" in locals() and isinstance(photo_obj, BytesIO): - photo_obj.close() + err_msg = str(e) + # Photo_invalid_dimensions: Telegram 报错提示图片长宽比例或总尺寸不合规 + if "Photo_invalid_dimensions" in err_msg or "Photo invalid dimensions" in err_msg: + logger.warning("[Telegram] 图片尺寸超限,正在尝试以文件形式发送...") + # 构造一个更有意义的文件名 + ts = datetime.now().strftime("%Y%m%d_%H%M%S") + fn = f"analysis_report_{group_id}_{ts}.png" + return await self.send_file(group_id, image_path, filename=fn) + logger.error(f"[Telegram] 发送图片失败: {e}") return False @@ -581,21 +603,51 @@ class TelegramAdapter(PlatformAdapter): try: import os + import base64 + from io import BytesIO chat_id, message_thread_id = self._parse_group_id(group_id) + file_obj: Any = None + is_temp_obj = False kwargs: dict[str, Any] = {"chat_id": chat_id} if message_thread_id: kwargs["message_thread_id"] = int(message_thread_id) - if filename: - kwargs["filename"] = filename - else: - kwargs["filename"] = os.path.basename(file_path) - # 打开文件 - with open(file_path, "rb") as f: - kwargs["document"] = f + # 1. 统一处理输入源 (Base64 / Local File) + if file_path.startswith("base64://"): + data = base64.b64decode(file_path[len("base64://") :]) + file_obj = BytesIO(data) + is_temp_obj = True + if not filename: + filename = "file.png" + elif file_path.startswith("data:"): + parts = file_path.split(",", 1) + if len(parts) == 2: + data = base64.b64decode(parts[1]) + file_obj = BytesIO(data) + is_temp_obj = True + if not filename: + filename = "file.png" + elif os.path.isfile(file_path): + file_obj = open(file_path, "rb") + is_temp_obj = True + if not filename: + filename = os.path.basename(file_path) + else: + # 可能是 URL 或缓存 ID + file_obj = file_path + if not filename: + filename = "file" + + kwargs["document"] = file_obj + kwargs["filename"] = filename + + try: await client.send_document(**kwargs) + finally: + if is_temp_obj and hasattr(file_obj, "close"): + file_obj.close() return True except Exception as e: