From c442320c7f80cff9dc537e6671bc93c0b4344856 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 19:53:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96=E8=83=BD?= =?UTF-8?q?=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B=E7=BC=A9?= =?UTF-8?q?=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C=E6=94=B9?= =?UTF-8?q?=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD=20ocr=20?= =?UTF-8?q?=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E5=9B=BE=E7=89=87=E5=86=85=E5=AE=B9=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/platform/sources/gewechat.py | 37 ++++++++++++++++++---- pkg/utils/image.py | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index 557cf756..c1b6980b 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -28,7 +28,10 @@ from ...utils import image class GewechatMessageConverter(adapter.MessageConverter): - + + def __init__(self, config: dict): + self.config = config + @staticmethod async def yiri2target( message_chain: platform_message.MessageChain @@ -50,6 +53,7 @@ class GewechatMessageConverter(adapter.MessageConverter): @staticmethod async def target2yiri( + self, message: dict, bot_account_id: str ) -> platform_message.MessageChain: @@ -74,10 +78,29 @@ class GewechatMessageConverter(adapter.MessageConverter): return platform_message.MessageChain(content_list) elif message["Data"]["MsgType"] == 3: - image_base64 = message["Data"]["ImgBuf"]["buffer"] - return platform_message.MessageChain( - [platform_message.Image(base64=f"data:image/jpeg;base64,{image_base64}")] - ) + image_xml = message["Data"]["Content"]["string"] + if not image_xml: + return platform_message.MessageChain([ + platform_message.Plain(text="[图片内容为空]") + ]) + + try: + base64_str, image_format = await image.get_gewechat_image_base64( + gewechat_url=self.config["gewechat_url"], + app_id=self.config["app_id"], + xml_content=image_xml + ) + + return platform_message.MessageChain([ + platform_message.Image( + base64=f"data:image/{image_format};base64,{base64_str}" + ) + ]) + except Exception as e: + print(f"处理图片消息失败: {str(e)}") + return platform_message.MessageChain([ + platform_message.Plain(text="[图片处理失败]") + ]) elif message["Data"]["MsgType"] == 49: # 支持微信聊天记录的消息类型,将 XML 内容转换为 MessageChain 传递 @@ -172,7 +195,7 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): ap: app.Application - message_converter: GewechatMessageConverter = GewechatMessageConverter() + message_converter: GewechatMessageConverter event_converter: GewechatEventConverter = GewechatEventConverter() listeners: typing.Dict[ @@ -186,6 +209,8 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): self.quart_app = quart.Quart(__name__) + self.message_converter = GewechatMessageConverter(config=config) + @self.quart_app.route('/gewechat/callback', methods=['POST']) async def gewechat_callback(): data = await quart.request.json diff --git a/pkg/utils/image.py b/pkg/utils/image.py index 7a60df2a..712d55d7 100644 --- a/pkg/utils/image.py +++ b/pkg/utils/image.py @@ -8,6 +8,60 @@ import aiohttp import PIL.Image import httpx + +async def get_gewechat_image_base64(gewechat_url: str, app_id: str, xml_content: str, image_type: int = 2) -> \ +typing.Tuple[str, str]: + """从gewechat服务器获取图片并转换为base64格式 + + Args: + gewechat_url (str): gewechat服务器地址 + app_id (str): gewechat应用ID + xml_content (str): 图片的XML内容 + image_type (int, optional): 图片类型. Defaults to 2. + 1: 高清图片 + 2: 常规图片 + 3: 缩略图 + + Returns: + typing.Tuple[str, str]: (base64编码, 图片格式) + + Raises: + Exception: 当图片下载或处理失败时抛出异常 + """ + async with aiohttp.ClientSession() as session: + # 获取图片下载链接 + async with session.post( + f"{gewechat_url}/v2/api/message/downloadImage", + json={ + "app_id": app_id, + "type": image_type, + "xml": xml_content + } + ) as response: + if response.status != 200: + raise Exception(f"获取gewechat图片下载失败: {await response.text()}") + + resp_data = await response.json() + if resp_data.get("ret") != 200: + raise Exception(f"获取gewechat图片下载链接失败: {resp_data}") + + image_url = f"{gewechat_url}{resp_data['data']['fileUrl']}" + + # 下载图片内容 + async with session.get(image_url) as img_response: + if img_response.status != 200: + raise Exception(f"下载gewechat图片失败: {await img_response.text()}") + + # 获取图片格式 + content_type = img_response.headers.get('Content-Type', '') + image_format = content_type.split('/')[-1] # 例如 'image/jpeg' -> 'jpeg' + + # 读取图片数据并转换为base64 + image_data = await img_response.read() + base64_str = base64.b64encode(image_data).decode('utf-8') + + return base64_str, image_format + async def get_wecom_image_base64(pic_url: str) -> tuple[str, str]: """ 下载企业微信图片并转换为 base64