From cae79aac4897fff4547457b52c4f8f1f4ecea623 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 18:09:02 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E7=B1=BB=E5=9E=8B=2049=EF=BC=88=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E8=AE=B0=E5=BD=95=EF=BC=89=E7=9A=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=A4=84=E7=90=86=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E7=B1=BB=E5=9E=8B=E7=9A=84=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 微信聊天记录是 xml 数据格式,本质上也是字符串,可以按照字符串Plain类型来处理。 --- pkg/platform/sources/gewechat.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index 9d3921fc..62f3de7d 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -79,6 +79,32 @@ class GewechatMessageConverter(adapter.MessageConverter): [platform_message.Image(base64=f"data:image/jpeg;base64,{image_base64}")] ) + elif message["Data"]["MsgType"] == 49: + # 支持微信聊天记录的消息类型,将 XML 内容转换为 MessageChain 传递 + try: + # 首先确保内容是字符串 + content = message["Data"]["Content"]["string"] + + # 如果内容已经是base64编码,尝试解码 + try: + # 先将字符串编码为UTF-8字节 + content_bytes = content.encode('utf-8') + # 然后进行base64解码 + decoded_content = base64.b64decode(content_bytes) + return platform_message.MessageChain( + [platform_message.Unknown(content=decoded_content)] + ) + except Exception as e: + # 如果解码失败,直接返回原始内容 + return platform_message.MessageChain( + [platform_message.Plain(text=content)] + ) + except Exception as e: + print(f"Error processing type 49 message: {str(e)}") + return platform_message.MessageChain( + [platform_message.Plain(text="[无法解析的消息]")] + ) + class GewechatEventConverter(adapter.EventConverter): @staticmethod From 6aeae7e9f5c6523abb9aece93d1115a472c980c8 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 18:53:29 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=8A=A5=E9=94=99(base=20LangBot=20v3.4.9.2):=20[02-24=2005:46?= =?UTF-8?q?:37.616]=20manager.py=20(169)=20-=20[ERROR]=20:=20=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E9=80=82=E9=85=8D=E5=99=A8=E8=BF=90=E8=A1=8C=E5=87=BA?= =?UTF-8?q?=E9=94=99:=20'GeWeChatAdapter'=20object=20has=20no=20attribute?= =?UTF-8?q?=20'name'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/platform/sources/gewechat.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index 62f3de7d..557cf756 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -160,7 +160,9 @@ class GewechatEventConverter(adapter.EventConverter): class GeWeChatAdapter(adapter.MessagePlatformAdapter): - + + name: str = "gewechat" # 定义适配器名称 + bot: gewechat_client.GewechatClient quart_app: quart.Quart From c442320c7f80cff9dc537e6671bc93c0b4344856 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 19:53:43 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=20ocr=20=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E8=81=8A=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 From a60c896e89f996895c3069966fabdb360bed35d2 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 19:53:43 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=20ocr=20=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E8=81=8A=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 | 54 +++++++++++++++++++++++++------- pkg/utils/image.py | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 11 deletions(-) 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 From 2742c249bfbca6d7a03692b5da5dd1149d65c1bf Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 20:09:11 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=20ocr=20=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E8=81=8A=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 | 50 +++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index 557cf756..a2eeada8 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,23 @@ 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 +198,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 +212,8 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): self.quart_app = quart.Quart(__name__) + + @self.quart_app.route('/gewechat/callback', methods=['POST']) async def gewechat_callback(): data = await quart.request.json From f75ac292db581c812b18598dba42c474459206f0 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 20:11:27 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=20ocr=20=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E8=81=8A=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 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index a2eeada8..ea8592ee 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -212,7 +212,8 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): self.quart_app = quart.Quart(__name__) - + self.message_converter = GewechatMessageConverter(config) + self.event_converter = GewechatEventConverter(config) @self.quart_app.route('/gewechat/callback', methods=['POST']) async def gewechat_callback(): From c86602ebafbf12f62ce38e03cbbe52ed9b92512a Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 20:17:15 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=20ocr=20=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E8=81=8A=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 | 4 +++- pkg/utils/image.py | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index ea8592ee..da5548cd 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -87,7 +87,9 @@ class GewechatMessageConverter(adapter.MessageConverter): 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 + xml_content=image_xml, + token=self.config["token"], + image_type=2 ) return platform_message.MessageChain([ diff --git a/pkg/utils/image.py b/pkg/utils/image.py index 712d55d7..ff266446 100644 --- a/pkg/utils/image.py +++ b/pkg/utils/image.py @@ -9,14 +9,20 @@ 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]: +async def get_gewechat_image_base64( + gewechat_url: str, + app_id: str, + xml_content: str, + token: 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内容 + token (str): Gewechat API Token image_type (int, optional): 图片类型. Defaults to 2. 1: 高清图片 2: 常规图片 @@ -24,16 +30,19 @@ typing.Tuple[str, str]: Returns: typing.Tuple[str, str]: (base64编码, 图片格式) - - Raises: - Exception: 当图片下载或处理失败时抛出异常 """ + headers = { + 'X-GEWE-TOKEN': token, + 'Content-Type': 'application/json' + } + async with aiohttp.ClientSession() as session: # 获取图片下载链接 async with session.post( f"{gewechat_url}/v2/api/message/downloadImage", + headers=headers, json={ - "app_id": app_id, + "appId": app_id, "type": image_type, "xml": xml_content } @@ -48,13 +57,13 @@ typing.Tuple[str, str]: image_url = f"{gewechat_url}{resp_data['data']['fileUrl']}" # 下载图片内容 - async with session.get(image_url) as img_response: + async with session.get(image_url, headers=headers) 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' + image_format = content_type.split('/')[-1] # 读取图片数据并转换为base64 image_data = await img_response.read() From 91ad7944deabc0aa48647b4651d897e1a1d6f608 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 20:18:35 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=20ocr=20=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E8=81=8A=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/utils/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/utils/image.py b/pkg/utils/image.py index ff266446..03325912 100644 --- a/pkg/utils/image.py +++ b/pkg/utils/image.py @@ -54,7 +54,7 @@ async def get_gewechat_image_base64( if resp_data.get("ret") != 200: raise Exception(f"获取gewechat图片下载链接失败: {resp_data}") - image_url = f"{gewechat_url}{resp_data['data']['fileUrl']}" + image_url = f"{gewechat_url}/{resp_data['data']['fileUrl']}" # 下载图片内容 async with session.get(image_url, headers=headers) as img_response: From e21a27ff23383b8e06036a4f19aa40560eb53793 Mon Sep 17 00:00:00 2001 From: Ethan Date: Mon, 24 Feb 2025 20:36:03 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=EF=BC=8C=E8=BE=83=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=9B=BE=E7=89=87=E4=BB=85=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E5=96=84=E4=B8=BA=E8=8E=B7=E5=8F=96=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E4=B8=AD=E5=AE=9E=E9=99=85=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=20ocr=20=E6=88=96=E8=80=85=20llm=20vision=20=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E8=81=8A=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 | 1 + pkg/platform/sources/gewechat.yaml | 7 +++++ pkg/utils/image.py | 46 +++++++++++++++++++----------- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index da5548cd..557a624c 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -89,6 +89,7 @@ class GewechatMessageConverter(adapter.MessageConverter): app_id=self.config["app_id"], xml_content=image_xml, token=self.config["token"], + data_dir=self.config.get("data_dir", "/root/docker/gewechat/data/download"), image_type=2 ) diff --git a/pkg/platform/sources/gewechat.yaml b/pkg/platform/sources/gewechat.yaml index 6a6aec28..42659411 100644 --- a/pkg/platform/sources/gewechat.yaml +++ b/pkg/platform/sources/gewechat.yaml @@ -45,6 +45,13 @@ spec: type: string required: true default: "" + - name: data_dir + label: + en_US: Data Directory + zh_CN: 数据目录 + type: string + required: true + default: "/root/docker/gewechat/data/download" execution: python: path: ./gewechat.py diff --git a/pkg/utils/image.py b/pkg/utils/image.py index 03325912..f5618d10 100644 --- a/pkg/utils/image.py +++ b/pkg/utils/image.py @@ -8,25 +8,29 @@ import aiohttp import PIL.Image import httpx +import os +import aiofiles +import pathlib +from urllib.parse import urlparse + async def get_gewechat_image_base64( gewechat_url: str, app_id: str, xml_content: str, token: str, + data_dir: str = "/root/docker/gewechat/data/download", # gewechat数据目录 image_type: int = 2 ) -> typing.Tuple[str, str]: - """从gewechat服务器获取图片并转换为base64格式 + """从gewechat本地文件系统获取图片并转换为base64格式 Args: - gewechat_url (str): gewechat服务器地址 + gewechat_url (str): gewechat服务器地址(用于获取图片URL) app_id (str): gewechat应用ID xml_content (str): 图片的XML内容 token (str): Gewechat API Token + data_dir (str): gewechat数据目录 image_type (int, optional): 图片类型. Defaults to 2. - 1: 高清图片 - 2: 常规图片 - 3: 缩略图 Returns: typing.Tuple[str, str]: (base64编码, 图片格式) @@ -54,22 +58,30 @@ async def get_gewechat_image_base64( if resp_data.get("ret") != 200: raise Exception(f"获取gewechat图片下载链接失败: {resp_data}") - image_url = f"{gewechat_url}/{resp_data['data']['fileUrl']}" + # 从URL中解析文件路径 + file_url = resp_data['data']['fileUrl'] + parsed_url = urlparse(file_url) + path_parts = parsed_url.path.strip('/').split('/') - # 下载图片内容 - async with session.get(image_url, headers=headers) as img_response: - if img_response.status != 200: - raise Exception(f"下载gewechat图片失败: {await img_response.text()}") + # 构建本地文件路径 + # URL格式: /20250224/wx_U48cqQsdtqedi4Cak7MnN/35f6240a-c778-4579-93ee-d8002f91a8ed.png + local_path = os.path.join(data_dir, *path_parts) - # 获取图片格式 - content_type = img_response.headers.get('Content-Type', '') - image_format = content_type.split('/')[-1] + # 确保文件存在 + if not os.path.exists(local_path): + raise Exception(f"图片文件不存在: {local_path}") - # 读取图片数据并转换为base64 - image_data = await img_response.read() - base64_str = base64.b64encode(image_data).decode('utf-8') + # 读取本地文件 + async with aiofiles.open(local_path, 'rb') as f: + image_data = await f.read() - return base64_str, image_format + # 获取图片格式 + image_format = pathlib.Path(local_path).suffix.lstrip('.') + + # 转换为base64 + 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]: """ From 2ffe2967d699616753644989aa59572a08be7640 Mon Sep 17 00:00:00 2001 From: Ethan Date: Tue, 25 Feb 2025 11:32:35 +0800 Subject: [PATCH 10/12] feat: add download image port configuration and improve image retrieval process --- pkg/core/migrations/m025_gewechat_config.py | 1 + pkg/platform/sources/gewechat.py | 15 +-- pkg/platform/sources/gewechat.yaml | 14 +-- pkg/utils/image.py | 102 ++++++++++++-------- templates/platform.json | 1 + templates/schema/platform.json | 5 + 6 files changed, 83 insertions(+), 55 deletions(-) diff --git a/pkg/core/migrations/m025_gewechat_config.py b/pkg/core/migrations/m025_gewechat_config.py index 3ed108c0..b5b01a43 100644 --- a/pkg/core/migrations/m025_gewechat_config.py +++ b/pkg/core/migrations/m025_gewechat_config.py @@ -23,6 +23,7 @@ class GewechatConfigMigration(migration.Migration): "adapter": "gewechat", "enable": False, "gewechat_url": "http://your-gewechat-server:2531", + "gewechat_downloadImage_port": 2532, "port": 2286, "callback_url": "http://your-callback-url:2286/gewechat/callback", "app_id": "", diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index 7bac28c8..23c6d41b 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -56,7 +56,7 @@ class GewechatMessageConverter(adapter.MessageConverter): message: dict, bot_account_id: str ) -> platform_message.MessageChain: - + if message["Data"]["MsgType"] == 1: # 检查消息开头,如果有 wxid_sbitaz0mt65n22:\n 则删掉 regex = re.compile(r"^wxid_.*:") @@ -89,8 +89,8 @@ class GewechatMessageConverter(adapter.MessageConverter): app_id=self.config["app_id"], xml_content=image_xml, token=self.config["token"], - data_dir=self.config.get("data_dir", "/root/docker/gewechat/data/download"), - image_type=2 + image_type=2, + download_image_port=self.config["gewechat_downloadImage_port"] ) return platform_message.MessageChain([ @@ -107,20 +107,15 @@ class GewechatMessageConverter(adapter.MessageConverter): elif message["Data"]["MsgType"] == 49: # 支持微信聊天记录的消息类型,将 XML 内容转换为 MessageChain 传递 try: - # 首先确保内容是字符串 content = message["Data"]["Content"]["string"] - # 如果内容已经是base64编码,尝试解码 try: - # 先将字符串编码为UTF-8字节 content_bytes = content.encode('utf-8') - # 然后进行base64解码 decoded_content = base64.b64decode(content_bytes) return platform_message.MessageChain( [platform_message.Unknown(content=decoded_content)] ) except Exception as e: - # 如果解码失败,直接返回原始内容 return platform_message.MessageChain( [platform_message.Plain(text=content)] ) @@ -175,7 +170,7 @@ class GewechatEventConverter(adapter.EventConverter): time=event["Data"]["CreateTime"], source_platform_object=event, ) - elif 'wxid_' in event["Data"]["FromUserName"]["string"]: + else: return platform_events.FriendMessage( sender=platform_entities.Friend( id=event["Data"]["FromUserName"]["string"], @@ -221,7 +216,7 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): @self.quart_app.route('/gewechat/callback', methods=['POST']) async def gewechat_callback(): data = await quart.request.json - # print(json.dumps(data, indent=4, ensure_ascii=False)) + print(json.dumps(data, indent=4, ensure_ascii=False)) if 'testMsg' in data: return 'ok' diff --git a/pkg/platform/sources/gewechat.yaml b/pkg/platform/sources/gewechat.yaml index 42659411..05b721a3 100644 --- a/pkg/platform/sources/gewechat.yaml +++ b/pkg/platform/sources/gewechat.yaml @@ -17,6 +17,13 @@ spec: type: string required: true default: "" + - name: gewechat_downloadImage_port + label: + en_US: GeWeChat download image port + zh_CN: GeWeChat 下载图片的端口 + type: int + required: true + default: 2532 - name: port label: en_US: Port @@ -45,13 +52,6 @@ spec: type: string required: true default: "" - - name: data_dir - label: - en_US: Data Directory - zh_CN: 数据目录 - type: string - required: true - default: "/root/docker/gewechat/data/download" execution: python: path: ./gewechat.py diff --git a/pkg/utils/image.py b/pkg/utils/image.py index f5618d10..5f185615 100644 --- a/pkg/utils/image.py +++ b/pkg/utils/image.py @@ -11,6 +11,7 @@ import httpx import os import aiofiles import pathlib +import asyncio from urllib.parse import urlparse @@ -19,69 +20,94 @@ async def get_gewechat_image_base64( app_id: str, xml_content: str, token: str, - data_dir: str = "/root/docker/gewechat/data/download", # gewechat数据目录 - image_type: int = 2 + image_type: int = 2, + download_image_port: int = 2532, ) -> typing.Tuple[str, str]: - """从gewechat本地文件系统获取图片并转换为base64格式 + """从gewechat服务器获取图片并转换为base64格式 Args: gewechat_url (str): gewechat服务器地址(用于获取图片URL) app_id (str): gewechat应用ID xml_content (str): 图片的XML内容 token (str): Gewechat API Token - data_dir (str): gewechat数据目录 image_type (int, optional): 图片类型. Defaults to 2. + download_image_port (int, optional): 图片下载服务端口. Defaults to 2532. Returns: typing.Tuple[str, str]: (base64编码, 图片格式) + + Raises: + aiohttp.ClientTimeout: 请求超时(15秒)或连接超时(2秒) + Exception: 其他错误 """ headers = { 'X-GEWE-TOKEN': token, 'Content-Type': 'application/json' } - async with aiohttp.ClientSession() as session: - # 获取图片下载链接 - async with session.post( - f"{gewechat_url}/v2/api/message/downloadImage", - headers=headers, - json={ - "appId": app_id, - "type": image_type, - "xml": xml_content - } - ) as response: - if response.status != 200: - raise Exception(f"获取gewechat图片下载失败: {await response.text()}") + # 设置超时 + timeout = aiohttp.ClientTimeout( + total=15.0, # 总超时时间15秒 + connect=2.0, # 连接超时2秒 + sock_connect=2.0, # socket连接超时2秒 + sock_read=15.0 # socket读取超时15秒 + ) - resp_data = await response.json() - if resp_data.get("ret") != 200: - raise Exception(f"获取gewechat图片下载链接失败: {resp_data}") + try: + async with aiohttp.ClientSession(timeout=timeout) as session: + # 获取图片下载链接 + try: + async with session.post( + f"{gewechat_url}/v2/api/message/downloadImage", + headers=headers, + json={ + "appId": app_id, + "type": image_type, + "xml": xml_content + } + ) as response: + if response.status != 200: + raise Exception(f"获取gewechat图片下载失败: {await response.text()}") - # 从URL中解析文件路径 - file_url = resp_data['data']['fileUrl'] - parsed_url = urlparse(file_url) - path_parts = parsed_url.path.strip('/').split('/') + resp_data = await response.json() + if resp_data.get("ret") != 200: + raise Exception(f"获取gewechat图片下载链接失败: {resp_data}") - # 构建本地文件路径 - # URL格式: /20250224/wx_U48cqQsdtqedi4Cak7MnN/35f6240a-c778-4579-93ee-d8002f91a8ed.png - local_path = os.path.join(data_dir, *path_parts) + file_url = resp_data['data']['fileUrl'] + except asyncio.TimeoutError: + raise Exception("获取图片下载链接超时") + except aiohttp.ClientError as e: + raise Exception(f"获取图片下载链接网络错误: {str(e)}") - # 确保文件存在 - if not os.path.exists(local_path): - raise Exception(f"图片文件不存在: {local_path}") + # 解析原始URL并替换端口 + parsed_url = urlparse(gewechat_url) + base_url = f"http://{parsed_url.hostname}:{download_image_port}" + download_url = f"{base_url}/download/{file_url}" - # 读取本地文件 - async with aiofiles.open(local_path, 'rb') as f: - image_data = await f.read() + # 下载图片 + try: + async with session.get(download_url) as img_response: + if img_response.status != 200: + raise Exception(f"下载图片失败: {await img_response.text()}, URL: {download_url}") - # 获取图片格式 - image_format = pathlib.Path(local_path).suffix.lstrip('.') + image_data = await img_response.read() - # 转换为base64 - base64_str = base64.b64encode(image_data).decode('utf-8') + content_type = img_response.headers.get('Content-Type', '') + if content_type: + image_format = content_type.split('/')[-1] + else: + image_format = file_url.split('.')[-1] + + base64_str = base64.b64encode(image_data).decode('utf-8') + + return base64_str, image_format + except asyncio.TimeoutError: + raise Exception(f"下载图片超时, URL: {download_url}") + except aiohttp.ClientError as e: + raise Exception(f"下载图片网络错误: {str(e)}, URL: {download_url}") + except Exception as e: + raise Exception(f"获取图片失败: {str(e)}") from e - return base64_str, image_format async def get_wecom_image_base64(pic_url: str) -> tuple[str, str]: """ diff --git a/templates/platform.json b/templates/platform.json index 8e8e73ef..2cccf058 100644 --- a/templates/platform.json +++ b/templates/platform.json @@ -64,6 +64,7 @@ "adapter": "gewechat", "enable": false, "gewechat_url": "http://your-gewechat-server:2531", + "gewechat_downloadImage_port": 2532, "port": 2286, "callback_url": "http://your-callback-url:2286/gewechat/callback", "app_id": "", diff --git a/templates/schema/platform.json b/templates/schema/platform.json index c33907c1..2f1114bd 100644 --- a/templates/schema/platform.json +++ b/templates/schema/platform.json @@ -325,6 +325,11 @@ "default": "", "description": "gewechat 的 url" }, + "gewechat_downloadImage_port": { + "type": "integer", + "default": 2532, + "description": "gewechat 下载图片的端口" + }, "port": { "type": "integer", "default": 2286, From 4db1d2b3a328211dfffa0bf4485a440cb96ad705 Mon Sep 17 00:00:00 2001 From: Ethan Date: Tue, 25 Feb 2025 11:53:23 +0800 Subject: [PATCH 11/12] fix: comment out debug print statement in gewechat callback --- pkg/platform/sources/gewechat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index 23c6d41b..e6e2d87e 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -216,7 +216,7 @@ class GeWeChatAdapter(adapter.MessagePlatformAdapter): @self.quart_app.route('/gewechat/callback', methods=['POST']) async def gewechat_callback(): data = await quart.request.json - print(json.dumps(data, indent=4, ensure_ascii=False)) + # print(json.dumps(data, indent=4, ensure_ascii=False)) if 'testMsg' in data: return 'ok' From 9401a79b2b3bd993e6fc76504d421973829067b7 Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Tue, 25 Feb 2025 16:12:45 +0800 Subject: [PATCH 12/12] feat: update file download url --- pkg/core/migrations/m025_gewechat_config.py | 2 +- .../m034_gewechat_file_url_config.py | 29 +++++++++++++++++++ pkg/core/stages/migrate.py | 2 +- pkg/platform/sources/gewechat.py | 2 +- pkg/platform/sources/gewechat.yaml | 10 +++---- pkg/utils/image.py | 7 ++--- templates/platform.json | 2 +- templates/schema/platform.json | 8 ++--- 8 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 pkg/core/migrations/m034_gewechat_file_url_config.py diff --git a/pkg/core/migrations/m025_gewechat_config.py b/pkg/core/migrations/m025_gewechat_config.py index b5b01a43..65b5c1d5 100644 --- a/pkg/core/migrations/m025_gewechat_config.py +++ b/pkg/core/migrations/m025_gewechat_config.py @@ -23,7 +23,7 @@ class GewechatConfigMigration(migration.Migration): "adapter": "gewechat", "enable": False, "gewechat_url": "http://your-gewechat-server:2531", - "gewechat_downloadImage_port": 2532, + "gewechat_file_url": "http://your-gewechat-server:2532", "port": 2286, "callback_url": "http://your-callback-url:2286/gewechat/callback", "app_id": "", diff --git a/pkg/core/migrations/m034_gewechat_file_url_config.py b/pkg/core/migrations/m034_gewechat_file_url_config.py new file mode 100644 index 00000000..44bbd65e --- /dev/null +++ b/pkg/core/migrations/m034_gewechat_file_url_config.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from urllib.parse import urlparse + +from .. import migration + + +@migration.migration_class("gewechat-file-url-config", 34) +class GewechatFileUrlConfigMigration(migration.Migration): + """迁移""" + + async def need_migrate(self) -> bool: + """判断当前环境是否需要运行此迁移""" + + for adapter in self.ap.platform_cfg.data['platform-adapters']: + if adapter['adapter'] == 'gewechat': + if 'gewechat_file_url' not in adapter: + return True + return False + + async def run(self): + """执行迁移""" + for adapter in self.ap.platform_cfg.data['platform-adapters']: + if adapter['adapter'] == 'gewechat': + if 'gewechat_file_url' not in adapter: + parsed_url = urlparse(adapter['gewechat_url']) + adapter['gewechat_file_url'] = f"{parsed_url.scheme}://{parsed_url.hostname}:2532" + + await self.ap.platform_cfg.dump_config() diff --git a/pkg/core/stages/migrate.py b/pkg/core/stages/migrate.py index d317596e..ce6e41a5 100644 --- a/pkg/core/stages/migrate.py +++ b/pkg/core/stages/migrate.py @@ -11,7 +11,7 @@ from ..migrations import m015_gitee_ai_config, m016_dify_service_api, m017_dify_ from ..migrations import m020_wecom_config, m021_lark_config, m022_lmstudio_config, m023_siliconflow_config, m024_discord_config, m025_gewechat_config from ..migrations import m026_qqofficial_config, m027_wx_official_account_config, m028_aliyun_requester_config from ..migrations import m029_dashscope_app_api_config, m030_lark_config_cmpl, m031_dingtalk_config, m032_volcark_config -from ..migrations import m033_dify_thinking_config +from ..migrations import m033_dify_thinking_config, m034_gewechat_file_url_config @stage.stage_class("MigrationStage") class MigrationStage(stage.BootingStage): diff --git a/pkg/platform/sources/gewechat.py b/pkg/platform/sources/gewechat.py index e6e2d87e..c7478635 100644 --- a/pkg/platform/sources/gewechat.py +++ b/pkg/platform/sources/gewechat.py @@ -86,11 +86,11 @@ class GewechatMessageConverter(adapter.MessageConverter): try: base64_str, image_format = await image.get_gewechat_image_base64( gewechat_url=self.config["gewechat_url"], + gewechat_file_url=self.config["gewechat_file_url"] app_id=self.config["app_id"], xml_content=image_xml, token=self.config["token"], image_type=2, - download_image_port=self.config["gewechat_downloadImage_port"] ) return platform_message.MessageChain([ diff --git a/pkg/platform/sources/gewechat.yaml b/pkg/platform/sources/gewechat.yaml index 05b721a3..01967ffc 100644 --- a/pkg/platform/sources/gewechat.yaml +++ b/pkg/platform/sources/gewechat.yaml @@ -17,13 +17,13 @@ spec: type: string required: true default: "" - - name: gewechat_downloadImage_port + - name: gewechat_file_url label: - en_US: GeWeChat download image port - zh_CN: GeWeChat 下载图片的端口 - type: int + en_US: GeWeChat file download URL + zh_CN: GeWeChat 文件下载URL + type: string required: true - default: 2532 + default: "" - name: port label: en_US: Port diff --git a/pkg/utils/image.py b/pkg/utils/image.py index 5f185615..16077ace 100644 --- a/pkg/utils/image.py +++ b/pkg/utils/image.py @@ -17,21 +17,21 @@ from urllib.parse import urlparse async def get_gewechat_image_base64( gewechat_url: str, + gewechat_file_url: str, app_id: str, xml_content: str, token: str, image_type: int = 2, - download_image_port: int = 2532, ) -> typing.Tuple[str, str]: """从gewechat服务器获取图片并转换为base64格式 Args: gewechat_url (str): gewechat服务器地址(用于获取图片URL) + gewechat_file_url (str): gewechat文件下载服务地址 app_id (str): gewechat应用ID xml_content (str): 图片的XML内容 token (str): Gewechat API Token image_type (int, optional): 图片类型. Defaults to 2. - download_image_port (int, optional): 图片下载服务端口. Defaults to 2532. Returns: typing.Tuple[str, str]: (base64编码, 图片格式) @@ -80,8 +80,7 @@ async def get_gewechat_image_base64( raise Exception(f"获取图片下载链接网络错误: {str(e)}") # 解析原始URL并替换端口 - parsed_url = urlparse(gewechat_url) - base_url = f"http://{parsed_url.hostname}:{download_image_port}" + base_url = gewechat_file_url download_url = f"{base_url}/download/{file_url}" # 下载图片 diff --git a/templates/platform.json b/templates/platform.json index 2cccf058..a0fb8ce2 100644 --- a/templates/platform.json +++ b/templates/platform.json @@ -64,7 +64,7 @@ "adapter": "gewechat", "enable": false, "gewechat_url": "http://your-gewechat-server:2531", - "gewechat_downloadImage_port": 2532, + "gewechat_file_url": "http://your-gewechat-server:2532", "port": 2286, "callback_url": "http://your-callback-url:2286/gewechat/callback", "app_id": "", diff --git a/templates/schema/platform.json b/templates/schema/platform.json index 2f1114bd..925330a7 100644 --- a/templates/schema/platform.json +++ b/templates/schema/platform.json @@ -325,10 +325,10 @@ "default": "", "description": "gewechat 的 url" }, - "gewechat_downloadImage_port": { - "type": "integer", - "default": 2532, - "description": "gewechat 下载图片的端口" + "gewechat_file_url": { + "type": "string", + "default": "", + "description": "gewechat 文件下载URL" }, "port": { "type": "integer",