diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index 557cf756..76e3ad89 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 @@ -48,8 +51,8 @@ class GewechatMessageConverter(adapter.MessageConverter): return content_list - @staticmethod async def target2yiri( + self, message: dict, bot_account_id: str ) -> platform_message.MessageChain: @@ -74,10 +77,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 传递 @@ -106,19 +128,26 @@ class GewechatMessageConverter(adapter.MessageConverter): ) class GewechatEventConverter(adapter.EventConverter): - + + def __init__(self, config: dict): + self.config = config + self.message_converter = GewechatMessageConverter(config) + @staticmethod async def yiri2target( event: platform_events.MessageEvent ) -> dict: pass - @staticmethod async def target2yiri( + self, event: dict, bot_account_id: str ) -> platform_events.MessageEvent: - message_chain = await GewechatMessageConverter.target2yiri(copy.deepcopy(event), bot_account_id) + message_chain = await self.message_converter.target2yiri( + copy.deepcopy(event), + bot_account_id + ) if not message_chain: return None @@ -172,8 +201,8 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): ap: app.Application - message_converter: GewechatMessageConverter = GewechatMessageConverter() - event_converter: GewechatEventConverter = GewechatEventConverter() + message_converter: GewechatMessageConverter + event_converter: GewechatEventConverter listeners: typing.Dict[ typing.Type[platform_events.Event], @@ -186,6 +215,9 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): self.quart_app = quart.Quart(__name__) + self.message_converter = GewechatMessageConverter(config=config) + self.event_converter = GewechatEventConverter(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