From 2412e080b46366dbfc92cfc70357cca3377e4726 Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Fri, 21 Nov 2025 23:39:19 +0800 Subject: [PATCH] fix: import errors --- src/langbot/libs/wecom_ai_bot_api/api.py | 47 ++++++++------- src/langbot/pkg/api/http/service/bot.py | 6 +- .../pkg/platform/sources/officialaccount.py | 32 +++++----- .../pkg/platform/sources/qqofficial.py | 26 ++++---- src/langbot/pkg/platform/sources/wecom.py | 27 ++++----- src/langbot/pkg/platform/sources/wecombot.py | 59 ++++++++++--------- 6 files changed, 96 insertions(+), 101 deletions(-) diff --git a/src/langbot/libs/wecom_ai_bot_api/api.py b/src/langbot/libs/wecom_ai_bot_api/api.py index 2ac01b89..bed94d02 100644 --- a/src/langbot/libs/wecom_ai_bot_api/api.py +++ b/src/langbot/libs/wecom_ai_bot_api/api.py @@ -13,9 +13,9 @@ import httpx from Crypto.Cipher import AES from quart import Quart, request, Response, jsonify -from libs.wecom_ai_bot_api import wecombotevent -from libs.wecom_ai_bot_api.WXBizMsgCrypt3 import WXBizMsgCrypt -from pkg.platform.logger import EventLogger +from langbot.libs.wecom_ai_bot_api import wecombotevent +from langbot.libs.wecom_ai_bot_api.WXBizMsgCrypt3 import WXBizMsgCrypt +from langbot.pkg.platform.logger import EventLogger @dataclass @@ -224,10 +224,7 @@ class WecomBotClient: # 只有在非统一模式下才注册独立路由 if not self.unified_mode: self.app.add_url_rule( - '/callback/command', - 'handle_callback', - self.handle_callback_request, - methods=['POST', 'GET'] + '/callback/command', 'handle_callback', self.handle_callback_request, methods=['POST', 'GET'] ) self._message_handlers = { @@ -445,7 +442,7 @@ class WecomBotClient: await self.logger.error("请求体中缺少 'encrypt' 字段") return Response('Bad Request', status=400) - xml_post_data = f"" + xml_post_data = f'' ret, decrypted_xml = self.wxcpt.DecryptMsg(xml_post_data, msg_signature, timestamp, nonce) if ret != 0: await self.logger.error('解密失败') @@ -483,7 +480,7 @@ class WecomBotClient: picurl = item.get('image', {}).get('url') if texts: - message_data['content'] = "".join(texts) # 拼接所有 text + message_data['content'] = ''.join(texts) # 拼接所有 text if picurl: base64 = await self.download_url_to_base64(picurl, self.EnCodingAESKey) message_data['picurl'] = base64 # 只保留第一个 image @@ -491,7 +488,9 @@ class WecomBotClient: # Extract user information from_info = msg_json.get('from', {}) message_data['userid'] = from_info.get('userid', '') - message_data['username'] = from_info.get('alias', '') or from_info.get('name', '') or from_info.get('userid', '') + message_data['username'] = ( + from_info.get('alias', '') or from_info.get('name', '') or from_info.get('userid', '') + ) # Extract chat/group information if msg_json.get('chattype', '') == 'group': @@ -580,7 +579,7 @@ class WecomBotClient: encrypted_bytes = response.content - aes_key = base64.b64decode(encoding_aes_key + "=") # base64 补齐 + aes_key = base64.b64decode(encoding_aes_key + '=') # base64 补齐 iv = aes_key[:16] cipher = AES.new(aes_key, AES.MODE_CBC, iv) @@ -589,22 +588,22 @@ class WecomBotClient: pad_len = decrypted[-1] decrypted = decrypted[:-pad_len] - if decrypted.startswith(b"\xff\xd8"): # JPEG - mime_type = "image/jpeg" - elif decrypted.startswith(b"\x89PNG"): # PNG - mime_type = "image/png" - elif decrypted.startswith((b"GIF87a", b"GIF89a")): # GIF - mime_type = "image/gif" - elif decrypted.startswith(b"BM"): # BMP - mime_type = "image/bmp" - elif decrypted.startswith(b"II*\x00") or decrypted.startswith(b"MM\x00*"): # TIFF - mime_type = "image/tiff" + if decrypted.startswith(b'\xff\xd8'): # JPEG + mime_type = 'image/jpeg' + elif decrypted.startswith(b'\x89PNG'): # PNG + mime_type = 'image/png' + elif decrypted.startswith((b'GIF87a', b'GIF89a')): # GIF + mime_type = 'image/gif' + elif decrypted.startswith(b'BM'): # BMP + mime_type = 'image/bmp' + elif decrypted.startswith(b'II*\x00') or decrypted.startswith(b'MM\x00*'): # TIFF + mime_type = 'image/tiff' else: - mime_type = "application/octet-stream" + mime_type = 'application/octet-stream' # 转 base64 - base64_str = base64.b64encode(decrypted).decode("utf-8") - return f"data:{mime_type};base64,{base64_str}" + base64_str = base64.b64encode(decrypted).decode('utf-8') + return f'data:{mime_type};base64,{base64_str}' async def run_task(self, host: str, port: int, *args, **kwargs): """ diff --git a/src/langbot/pkg/api/http/service/bot.py b/src/langbot/pkg/api/http/service/bot.py index f171e35d..2942521c 100644 --- a/src/langbot/pkg/api/http/service/bot.py +++ b/src/langbot/pkg/api/http/service/bot.py @@ -58,11 +58,11 @@ class BotService: if runtime_bot is not None: adapter_runtime_values['bot_account_id'] = runtime_bot.adapter.bot_account_id - if persistence_bot['adapter'] in ['wecom', 'wecombot', 'officialaccount', 'qqofficial', 'slack','wecomcs']: + if persistence_bot['adapter'] in ['wecom', 'wecombot', 'officialaccount', 'qqofficial', 'slack', 'wecomcs']: api_port = self.ap.instance_config.data['api']['port'] - webhook_url = f"/bots/{bot_uuid}" + webhook_url = f'/bots/{bot_uuid}' adapter_runtime_values['webhook_url'] = webhook_url - adapter_runtime_values['webhook_full_url'] = f"http://:{api_port}{webhook_url}" + adapter_runtime_values['webhook_full_url'] = f'http://:{api_port}{webhook_url}' else: adapter_runtime_values['webhook_url'] = None adapter_runtime_values['webhook_full_url'] = None diff --git a/src/langbot/pkg/platform/sources/officialaccount.py b/src/langbot/pkg/platform/sources/officialaccount.py index 3d339fa0..5f6f0e41 100644 --- a/src/langbot/pkg/platform/sources/officialaccount.py +++ b/src/langbot/pkg/platform/sources/officialaccount.py @@ -5,13 +5,12 @@ import traceback import pydantic import datetime import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter -from libs.official_account_api.oaevent import OAEvent -from libs.official_account_api.api import OAClient -from libs.official_account_api.api import OAClientForLongerResponse +from langbot.libs.official_account_api.oaevent import OAEvent +from langbot.libs.official_account_api.api import OAClient +from langbot.libs.official_account_api.api import OAClientForLongerResponse import langbot_plugin.api.entities.builtin.platform.entities as platform_entities import langbot_plugin.api.entities.builtin.platform.message as platform_message import langbot_plugin.api.entities.builtin.platform.events as platform_events -from langbot_plugin.api.entities.builtin.command import errors as command_errors from ..logger import EventLogger @@ -93,7 +92,6 @@ class OfficialAccountAdapter(abstract_platform_adapter.AbstractMessagePlatformAd bot_account_id = config.get('AppID', '') - super().__init__( bot=bot, bot_account_id=bot_account_id, @@ -101,10 +99,6 @@ class OfficialAccountAdapter(abstract_platform_adapter.AbstractMessagePlatformAd logger=logger, ) - - - - async def reply_message( self, message_source: platform_events.FriendMessage, @@ -165,19 +159,20 @@ class OfficialAccountAdapter(abstract_platform_adapter.AbstractMessagePlatformAd if self.bot_uuid and hasattr(self.logger, 'ap'): try: api_port = self.logger.ap.instance_config.data['api']['port'] - webhook_url = f"http://127.0.0.1:{api_port}/bots/{self.bot_uuid}" - webhook_url_public = f"http://:{api_port}/bots/{self.bot_uuid}" + webhook_url = f'http://127.0.0.1:{api_port}/bots/{self.bot_uuid}' + webhook_url_public = f'http://:{api_port}/bots/{self.bot_uuid}' - await self.logger.info(f"微信公众号 Webhook 回调地址:") - await self.logger.info(f" 本地地址: {webhook_url}") - await self.logger.info(f" 公网地址: {webhook_url_public}") - await self.logger.info(f"请在微信公众号后台配置此回调地址") + await self.logger.info('微信公众号 Webhook 回调地址:') + await self.logger.info(f' 本地地址: {webhook_url}') + await self.logger.info(f' 公网地址: {webhook_url_public}') + await self.logger.info('请在微信公众号后台配置此回调地址') except Exception as e: - await self.logger.warning(f"无法生成 webhook URL: {e}") + await self.logger.warning(f'无法生成 webhook URL: {e}') async def keep_alive(): while True: await asyncio.sleep(1) + await keep_alive() async def kill(self) -> bool: @@ -192,5 +187,8 @@ class OfficialAccountAdapter(abstract_platform_adapter.AbstractMessagePlatformAd ): return super().unregister_listener(event_type, callback) - async def is_muted(self, group_id: str, ) -> bool: + async def is_muted( + self, + group_id: str, + ) -> bool: pass diff --git a/src/langbot/pkg/platform/sources/qqofficial.py b/src/langbot/pkg/platform/sources/qqofficial.py index 91989126..a3288793 100644 --- a/src/langbot/pkg/platform/sources/qqofficial.py +++ b/src/langbot/pkg/platform/sources/qqofficial.py @@ -9,9 +9,8 @@ import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platf import langbot_plugin.api.entities.builtin.platform.message as platform_message import langbot_plugin.api.entities.builtin.platform.events as platform_events import langbot_plugin.api.entities.builtin.platform.entities as platform_entities -from langbot_plugin.api.entities.builtin.command import errors as command_errors -from libs.qq_official_api.api import QQOfficialClient -from libs.qq_official_api.qqofficialevent import QQOfficialEvent +from langbot.libs.qq_official_api.api import QQOfficialClient +from langbot.libs.qq_official_api.qqofficialevent import QQOfficialEvent from ...utils import image from ..logger import EventLogger @@ -141,11 +140,7 @@ class QQOfficialAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter def __init__(self, config: dict, logger: EventLogger): bot = QQOfficialClient( - app_id=config['appid'], - secret=config['secret'], - token=config['token'], - logger=logger, - unified_mode=True + app_id=config['appid'], secret=config['secret'], token=config['token'], logger=logger, unified_mode=True ) super().__init__( @@ -256,19 +251,20 @@ class QQOfficialAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter if self.bot_uuid and hasattr(self.logger, 'ap'): try: api_port = self.logger.ap.instance_config.data['api']['port'] - webhook_url = f"http://127.0.0.1:{api_port}/bots/{self.bot_uuid}" - webhook_url_public = f"http://:{api_port}/bots/{self.bot_uuid}" + webhook_url = f'http://127.0.0.1:{api_port}/bots/{self.bot_uuid}' + webhook_url_public = f'http://:{api_port}/bots/{self.bot_uuid}' - await self.logger.info(f"QQ 官方机器人 Webhook 回调地址:") - await self.logger.info(f" 本地地址: {webhook_url}") - await self.logger.info(f" 公网地址: {webhook_url_public}") - await self.logger.info(f"请在 QQ 官方机器人后台配置此回调地址") + await self.logger.info('QQ 官方机器人 Webhook 回调地址:') + await self.logger.info(f' 本地地址: {webhook_url}') + await self.logger.info(f' 公网地址: {webhook_url_public}') + await self.logger.info('请在 QQ 官方机器人后台配置此回调地址') except Exception as e: - await self.logger.warning(f"无法生成 webhook URL: {e}") + await self.logger.warning(f'无法生成 webhook URL: {e}') async def keep_alive(): while True: await asyncio.sleep(1) + await keep_alive() async def kill(self) -> bool: diff --git a/src/langbot/pkg/platform/sources/wecom.py b/src/langbot/pkg/platform/sources/wecom.py index 1bf2108d..21daad67 100644 --- a/src/langbot/pkg/platform/sources/wecom.py +++ b/src/langbot/pkg/platform/sources/wecom.py @@ -5,10 +5,9 @@ import traceback import datetime -from libs.wecom_api.api import WecomClient +from langbot.libs.wecom_api.api import WecomClient import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter -from libs.wecom_api.wecomevent import WecomEvent -from langbot_plugin.api.entities.builtin.command import errors as command_errors +from langbot.libs.wecom_api.wecomevent import WecomEvent from ...utils import image from ..logger import EventLogger import langbot_plugin.api.entities.builtin.platform.message as platform_message @@ -159,12 +158,11 @@ class WecomAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): unified_mode=True, ) - super().__init__( config=config, logger=logger, bot=bot, - bot_account_id="", + bot_account_id='', ) def set_bot_uuid(self, bot_uuid: str): @@ -189,7 +187,6 @@ class WecomAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): await self.bot.send_image(fixed_user_id, Wecom_event.agent_id, content['media_id']) async def send_message(self, target_type: str, target_id: str, message: platform_message.MessageChain): - content_list = await WecomMessageConverter.yiri2target(message, self.bot) parts = target_id.split('|') user_id = parts[0] @@ -235,23 +232,23 @@ class WecomAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): return await self.bot.handle_unified_webhook(request) async def run_async(self): - if self.bot_uuid and hasattr(self.logger, 'ap'): try: api_port = self.logger.ap.instance_config.data['api']['port'] - webhook_url = f"http://127.0.0.1:{api_port}/bots/{self.bot_uuid}" - webhook_url_public = f"http://:{api_port}/bots/{self.bot_uuid}" + webhook_url = f'http://127.0.0.1:{api_port}/bots/{self.bot_uuid}' + webhook_url_public = f'http://:{api_port}/bots/{self.bot_uuid}' - await self.logger.info(f"企业微信 Webhook 回调地址:") - await self.logger.info(f" 本地地址: {webhook_url}") - await self.logger.info(f" 公网地址: {webhook_url_public}") - await self.logger.info(f"请在企业微信后台配置此回调地址") + await self.logger.info('企业微信 Webhook 回调地址:') + await self.logger.info(f' 本地地址: {webhook_url}') + await self.logger.info(f' 公网地址: {webhook_url_public}') + await self.logger.info('请在企业微信后台配置此回调地址') except Exception as e: - await self.logger.warning(f"无法生成 webhook URL: {e}") + await self.logger.warning(f'无法生成 webhook URL: {e}') async def keep_alive(): while True: await asyncio.sleep(1) + await keep_alive() async def kill(self) -> bool: @@ -265,6 +262,6 @@ class WecomAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): ], ): return super().unregister_listener(event_type, callback) - + async def is_muted(self, group_id: int) -> bool: pass diff --git a/src/langbot/pkg/platform/sources/wecombot.py b/src/langbot/pkg/platform/sources/wecombot.py index d2d363f9..5fd66aca 100644 --- a/src/langbot/pkg/platform/sources/wecombot.py +++ b/src/langbot/pkg/platform/sources/wecombot.py @@ -8,11 +8,10 @@ import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platf import langbot_plugin.api.entities.builtin.platform.message as platform_message import langbot_plugin.api.entities.builtin.platform.events as platform_events import langbot_plugin.api.entities.builtin.platform.entities as platform_entities -import pydantic -from ..logger import EventLogger -from libs.wecom_ai_bot_api.wecombotevent import WecomBotEvent -from libs.wecom_ai_bot_api.api import WecomBotClient -from ...core import app +from ..logger import EventLogger +from langbot.libs.wecom_ai_bot_api.wecombotevent import WecomBotEvent +from langbot.libs.wecom_ai_bot_api.api import WecomBotClient + class WecomBotMessageConverter(abstract_platform_adapter.AbstractMessageConverter): @staticmethod @@ -36,14 +35,14 @@ class WecomBotMessageConverter(abstract_platform_adapter.AbstractMessageConverte return chain + class WecomBotEventConverter(abstract_platform_adapter.AbstractEventConverter): + @staticmethod + async def yiri2target(event: platform_events.MessageEvent): + return event.source_platform_object @staticmethod - async def yiri2target(event:platform_events.MessageEvent): - return event.source_platform_object - - @staticmethod - async def target2yiri(event:WecomBotEvent): + async def target2yiri(event: WecomBotEvent): message_chain = await WecomBotMessageConverter.target2yiri(event) if event.type == 'single': return platform_events.FriendMessage( @@ -82,6 +81,7 @@ class WecomBotEventConverter(abstract_platform_adapter.AbstractEventConverter): except Exception: print(traceback.format_exc()) + class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): bot: WecomBotClient bot_account_id: str @@ -91,13 +91,11 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): bot_uuid: str = None def __init__(self, config: dict, logger: EventLogger): - required_keys = ['Token', 'EncodingAESKey', 'Corpid', 'BotId'] missing_keys = [key for key in required_keys if key not in config] if missing_keys: raise Exception(f'WecomBot 缺少配置项: {missing_keys}') - bot = WecomBotClient( Token=config['Token'], EnCodingAESKey=config['EncodingAESKey'], @@ -114,9 +112,12 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): bot_account_id=bot_account_id, ) - - async def reply_message(self, message_source:platform_events.MessageEvent, message:platform_message.MessageChain,quote_origin: bool = False): - + async def reply_message( + self, + message_source: platform_events.MessageEvent, + message: platform_message.MessageChain, + quote_origin: bool = False, + ): content = await self.message_converter.yiri2target(message) await self.bot.set_message(message_source.source_platform_object.message_id, content) @@ -170,7 +171,9 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): def register_listener( self, event_type: typing.Type[platform_events.Event], - callback: typing.Callable[[platform_events.Event, abstract_platform_adapter.AbstractMessagePlatformAdapter], None], + callback: typing.Callable[ + [platform_events.Event, abstract_platform_adapter.AbstractMessagePlatformAdapter], None + ], ): async def on_message(event: WecomBotEvent): try: @@ -178,6 +181,7 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): except Exception: await self.logger.error(f'Error in wecombot callback: {traceback.format_exc()}') print(traceback.format_exc()) + try: if event_type == platform_events.FriendMessage: self.bot.on_message('single')(on_message) @@ -211,19 +215,20 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): if self.bot_uuid and hasattr(self.logger, 'ap'): try: api_port = self.logger.ap.instance_config.data['api']['port'] - webhook_url = f"http://127.0.0.1:{api_port}/bots/{self.bot_uuid}" - webhook_url_public = f"http://:{api_port}/bots/{self.bot_uuid}" + webhook_url = f'http://127.0.0.1:{api_port}/bots/{self.bot_uuid}' + webhook_url_public = f'http://:{api_port}/bots/{self.bot_uuid}' - await self.logger.info(f"企业微信机器人 Webhook 回调地址:") - await self.logger.info(f" 本地地址: {webhook_url}") - await self.logger.info(f" 公网地址: {webhook_url_public}") - await self.logger.info(f"请在企业微信后台配置此回调地址") + await self.logger.info('企业微信机器人 Webhook 回调地址:') + await self.logger.info(f' 本地地址: {webhook_url}') + await self.logger.info(f' 公网地址: {webhook_url_public}') + await self.logger.info('请在企业微信后台配置此回调地址') except Exception as e: - await self.logger.warning(f"无法生成 webhook URL: {e}") + await self.logger.warning(f'无法生成 webhook URL: {e}') async def keep_alive(): while True: await asyncio.sleep(1) + await keep_alive() async def kill(self) -> bool: @@ -232,11 +237,11 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter): async def unregister_listener( self, event_type: type, - callback: typing.Callable[[platform_events.Event, abstract_platform_adapter.AbstractMessagePlatformAdapter], None], + callback: typing.Callable[ + [platform_events.Event, abstract_platform_adapter.AbstractMessagePlatformAdapter], None + ], ): return super().unregister_listener(event_type, callback) - + async def is_muted(self, group_id: int) -> bool: pass - -