From 32162afa6529bae1399a89f4e9332f3e97fcfb11 Mon Sep 17 00:00:00 2001 From: RockChinQ <1010553892@qq.com> Date: Wed, 31 Jan 2024 00:02:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=81=A2=E5=A4=8D=E6=89=80?= =?UTF-8?q?=E6=9C=89=E5=AE=A1=E8=AE=A1API=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/audit/center/apigroup.py | 3 +- pkg/audit/center/groups/main.py | 2 +- pkg/audit/center/groups/plugin.py | 2 +- pkg/command/operators/plugin.py | 8 ++-- pkg/core/boot.py | 66 ++++++++++----------------- pkg/pipeline/process/handlers/chat.py | 18 ++++++++ pkg/plugin/manager.py | 52 +++++++++++++++++++++ pkg/plugin/setting.py | 19 ++++++++ pkg/provider/tools/toolmgr.py | 21 +++++++++ pkg/utils/announce.py | 17 +++++++ pkg/utils/version.py | 12 ++++- 11 files changed, 172 insertions(+), 48 deletions(-) diff --git a/pkg/audit/center/apigroup.py b/pkg/audit/center/apigroup.py index ce9ed76f..439ec6e6 100644 --- a/pkg/audit/center/apigroup.py +++ b/pkg/audit/center/apigroup.py @@ -38,6 +38,7 @@ class APIGroup(metaclass=abc.ABCMeta): url = self.prefix + path data = json.dumps(data) headers['Content-Type'] = 'application/json' + try: async with aiohttp.ClientSession() as session: async with session.request( @@ -49,7 +50,7 @@ class APIGroup(metaclass=abc.ABCMeta): **kwargs ) as resp: self.ap.logger.debug("data: %s", data) - self.ap.logger.debug("ret: %s", await resp.json()) + self.ap.logger.debug("ret: %s", await resp.text()) except Exception as e: self.ap.logger.debug(f'上报失败: {e}') diff --git a/pkg/audit/center/groups/main.py b/pkg/audit/center/groups/main.py index de7dcaec..24e5287b 100644 --- a/pkg/audit/center/groups/main.py +++ b/pkg/audit/center/groups/main.py @@ -9,7 +9,7 @@ class V2MainDataAPI(apigroup.APIGroup): def __init__(self, prefix: str, ap: app.Application): self.ap = ap - super().__init__(prefix+"/usage", ap) + super().__init__(prefix+"/main", ap) async def do(self, *args, **kwargs): config = self.ap.cfg_mgr.data diff --git a/pkg/audit/center/groups/plugin.py b/pkg/audit/center/groups/plugin.py index 89fa5fc6..312d5e86 100644 --- a/pkg/audit/center/groups/plugin.py +++ b/pkg/audit/center/groups/plugin.py @@ -9,7 +9,7 @@ class V2PluginDataAPI(apigroup.APIGroup): def __init__(self, prefix: str, ap: app.Application): self.ap = ap - super().__init__(prefix+"/usage", ap) + super().__init__(prefix+"/plugin", ap) async def do(self, *args, **kwargs): config = self.ap.cfg_mgr.data diff --git a/pkg/command/operators/plugin.py b/pkg/command/operators/plugin.py index 27973913..c9c91002 100644 --- a/pkg/command/operators/plugin.py +++ b/pkg/command/operators/plugin.py @@ -167,7 +167,7 @@ class PluginDelOperator(operator.CommandOperator): yield entities.CommandReturn(error=errors.CommandError("插件删除失败: "+str(e))) -def update_plugin_status(plugin_name: str, new_status: bool, ap: app.Application): +async def update_plugin_status(plugin_name: str, new_status: bool, ap: app.Application): if ap.plugin_mgr.get_plugin_by_name(plugin_name) is not None: for plugin in ap.plugin_mgr.plugins: if plugin.plugin_name == plugin_name: @@ -176,6 +176,8 @@ def update_plugin_status(plugin_name: str, new_status: bool, ap: app.Application for func in plugin.content_functions: func.enable = new_status + await ap.plugin_mgr.setting.dump_container_setting(ap.plugin_mgr.plugins) + break return True @@ -202,7 +204,7 @@ class PluginEnableOperator(operator.CommandOperator): plugin_name = context.crt_params[0] try: - if update_plugin_status(plugin_name, True, self.ap): + if await update_plugin_status(plugin_name, True, self.ap): yield entities.CommandReturn(text="已启用插件: {}".format(plugin_name)) else: yield entities.CommandReturn(error=errors.CommandError("插件状态修改失败: 未找到插件 {}".format(plugin_name))) @@ -230,7 +232,7 @@ class PluginDisableOperator(operator.CommandOperator): plugin_name = context.crt_params[0] try: - if update_plugin_status(plugin_name, False, self.ap): + if await update_plugin_status(plugin_name, False, self.ap): yield entities.CommandReturn(text="已禁用插件: {}".format(plugin_name)) else: yield entities.CommandReturn(error=errors.CommandError("插件状态修改失败: 未找到插件 {}".format(plugin_name))) diff --git a/pkg/core/boot.py b/pkg/core/boot.py index 8faf743f..c251624d 100644 --- a/pkg/core/boot.py +++ b/pkg/core/boot.py @@ -35,7 +35,7 @@ async def make_app() -> app.Application: print("以下文件不存在,已自动生成,请修改配置文件后重启:") for file in generated_files: print("-", file) - + sys.exit(0) missing_deps = await deps.check_deps() @@ -52,28 +52,24 @@ async def make_app() -> app.Application: # 生成标识符 identifier.init() - cfg_mgr = await config.load_python_module_config( - "config.py", - "config-template.py" - ) + cfg_mgr = await config.load_python_module_config("config.py", "config-template.py") cfg = cfg_mgr.data # 检查是否携带了 --override 或 -r 参数 - if '--override' in sys.argv or '-r' in sys.argv: + if "--override" in sys.argv or "-r" in sys.argv: use_override = True if use_override: overrided = await config.override_config_manager(cfg_mgr) if overrided: qcg_logger.info("以下配置项已使用 override.json 覆盖:" + ",".join(overrided)) - + tips_mgr = await config.load_python_module_config( - "tips.py", - "tips-custom-template.py" + "tips.py", "tips-custom-template.py" ) # 检查管理员QQ号 - if cfg_mgr.data['admin_qq'] == 0: + if cfg_mgr.data["admin_qq"] == 0: qcg_logger.warning("未设置管理员QQ号,将无法使用管理员命令,请在 config.py 中修改 admin_qq") # 构建组建实例 @@ -85,50 +81,38 @@ async def make_app() -> app.Application: proxy_mgr = proxy.ProxyManager(ap) await proxy_mgr.initialize() ap.proxy_mgr = proxy_mgr - - # 发送公告 - ann_mgr = announce.AnnouncementManager(ap) - try: - announcements = await ann_mgr.fetch_new() - - for ann in announcements: - ap.logger.info(f'[公告] {ann.time}: {ann.content}') - except Exception as e: - ap.logger.warning(f'获取公告时出错: {e}') - - ap.query_pool = pool.QueryPool() - + ver_mgr = version.VersionManager(ap) await ver_mgr.initialize() ap.ver_mgr = ver_mgr - try: - - if await ap.ver_mgr.is_new_version_available(): - ap.logger.info("有新版本可用,请使用 !update 命令更新") - - except Exception as e: - ap.logger.warning(f"检查版本更新时出错: {e}") - - plugin_mgr_inst = plugin_mgr.PluginManager(ap) - await plugin_mgr_inst.initialize() - ap.plugin_mgr = plugin_mgr_inst - center_v2_api = center_v2.V2CenterAPI( ap, basic_info={ - "host_id": identifier.identifier['host_id'], - "instance_id": identifier.identifier['instance_id'], + "host_id": identifier.identifier["host_id"], + "instance_id": identifier.identifier["instance_id"], "semantic_version": ver_mgr.get_current_version(), "platform": sys.platform, }, runtime_info={ - "admin_id": "{}".format(cfg['admin_qq']), - "msg_source": cfg['msg_source_adapter'], - } + "admin_id": "{}".format(cfg["admin_qq"]), + "msg_source": cfg["msg_source_adapter"], + }, ) ap.ctr_mgr = center_v2_api + # 发送公告 + ann_mgr = announce.AnnouncementManager(ap) + await ann_mgr.show_announcements() + + ap.query_pool = pool.QueryPool() + + await ap.ver_mgr.show_version_update() + + plugin_mgr_inst = plugin_mgr.PluginManager(ap) + await plugin_mgr_inst.initialize() + ap.plugin_mgr = plugin_mgr_inst + cmd_mgr_inst = cmdmgr.CommandManager(ap) await cmd_mgr_inst.initialize() ap.cmd_mgr = cmd_mgr_inst @@ -159,7 +143,7 @@ async def make_app() -> app.Application: ctrl = controller.Controller(ap) ap.ctrl = ctrl - + await ap.initialize() return ap diff --git a/pkg/pipeline/process/handlers/chat.py b/pkg/pipeline/process/handlers/chat.py index f726b572..13b33a6f 100644 --- a/pkg/pipeline/process/handlers/chat.py +++ b/pkg/pipeline/process/handlers/chat.py @@ -1,6 +1,7 @@ from __future__ import annotations import typing +import time import mirai @@ -84,9 +85,16 @@ class ChatMessageHandler(handler.MessageHandler): called_functions = [] + text_length = 0 + + start_time = time.time() + async for result in conversation.use_model.requester.request(query, conversation): conversation.messages.append(result) + if result.content is not None: + text_length += len(result.content) + # 转换成可读消息 if result.role == 'assistant': @@ -172,3 +180,13 @@ class ChatMessageHandler(handler.MessageHandler): result_type=entities.ResultType.CONTINUE, new_query=query ) + + await self.ap.ctr_mgr.usage.post_query_record( + session_type=session.launcher_type.value, + session_id=str(session.launcher_id), + query_ability_provider="QChatGPT.Chat", + usage=text_length, + model_name=conversation.use_model.name, + response_seconds=int(time.time() - start_time), + retry_times=-1, + ) \ No newline at end of file diff --git a/pkg/plugin/manager.py b/pkg/plugin/manager.py index 8387937c..243d442e 100644 --- a/pkg/plugin/manager.py +++ b/pkg/plugin/manager.py @@ -64,6 +64,15 @@ class PluginManager: """ await self.installer.install_plugin(plugin_source) + await self.ap.ctr_mgr.plugin.post_install_record( + { + "name": "unknown", + "remote": plugin_source, + "author": "unknown", + "version": "HEAD" + } + ) + async def uninstall_plugin( self, plugin_name: str, @@ -72,6 +81,17 @@ class PluginManager: """ await self.installer.uninstall_plugin(plugin_name) + plugin_container = self.get_plugin_by_name(plugin_name) + + await self.ap.ctr_mgr.plugin.post_remove_record( + { + "name": plugin_name, + "remote": plugin_container.plugin_source, + "author": plugin_container.plugin_author, + "version": plugin_container.plugin_version + } + ) + async def update_plugin( self, plugin_name: str, @@ -80,6 +100,19 @@ class PluginManager: """更新插件 """ await self.installer.update_plugin(plugin_name, plugin_source) + + plugin_container = self.get_plugin_by_name(plugin_name) + + await self.ap.ctr_mgr.plugin.post_update_record( + plugin={ + "name": plugin_name, + "remote": plugin_container.plugin_source, + "author": plugin_container.plugin_author, + "version": plugin_container.plugin_version + }, + old_version=plugin_container.plugin_version, + new_version="HEAD" + ) def get_plugin_by_name(self, plugin_name: str) -> context.RuntimeContainer: """通过插件名获取插件 @@ -98,10 +131,14 @@ class PluginManager: event=event ) + emitted_plugins: list[context.RuntimeContainer] = [] + for plugin in self.plugins: if plugin.enabled: if event.__class__ in plugin.event_handlers: + emitted_plugins.append(plugin) + is_prevented_default_before_call = ctx.is_prevented_default() try: @@ -126,4 +163,19 @@ class PluginManager: self.ap.logger.debug(f'事件 {event.__class__.__name__}({ctx.eid}) 处理完成,返回值 {ctx.__return_value__}') + if emitted_plugins: + plugins_info: list[dict] = [ + { + 'name': plugin.plugin_name, + 'remote': plugin.plugin_source, + 'version': plugin.plugin_version, + 'author': plugin.plugin_author + } for plugin in emitted_plugins + ] + + await self.ap.ctr_mgr.usage.post_event_record( + plugins=plugins_info, + event_name=event.__class__.__name__ + ) + return ctx diff --git a/pkg/plugin/setting.py b/pkg/plugin/setting.py index baa1c4d0..156a99e6 100644 --- a/pkg/plugin/setting.py +++ b/pkg/plugin/setting.py @@ -59,6 +59,25 @@ class SettingManager: await self.settings.dump_config() + async def dump_container_setting( + self, + plugin_containers: list[context.RuntimeContainer] + ): + """保存插件容器设置 + """ + + for plugin in plugin_containers: + for ps in self.settings.data['plugins']: + if ps['name'] == plugin.plugin_name: + plugin_dict = plugin.to_setting_dict() + + for key in plugin_dict: + ps[key] = plugin_dict[key] + + break + + await self.settings.dump_config() + async def record_installed_plugin_source( self, pkg_path: str, diff --git a/pkg/provider/tools/toolmgr.py b/pkg/provider/tools/toolmgr.py index bbd210cc..e0a1ec26 100644 --- a/pkg/provider/tools/toolmgr.py +++ b/pkg/provider/tools/toolmgr.py @@ -84,3 +84,24 @@ class ToolManager: self.ap.logger.error(f'执行函数 {name} 时发生错误: {e}') traceback.print_exc() return f'error occurred when executing function {name}: {e}' + finally: + + plugin = None + + for p in self.ap.plugin_mgr.plugins: + if function in p.content_functions: + plugin = p + break + + if plugin is not None: + + await self.ap.ctr_mgr.usage.post_function_record( + plugin={ + 'name': plugin.plugin_name, + 'remote': plugin.plugin_source, + 'version': plugin.plugin_version, + 'author': plugin.plugin_author + }, + function_name=function.name, + function_description=function.description, + ) \ No newline at end of file diff --git a/pkg/utils/announce.py b/pkg/utils/announce.py index c304caad..d17ac62a 100644 --- a/pkg/utils/announce.py +++ b/pkg/utils/announce.py @@ -104,3 +104,20 @@ class AnnouncementManager: await self.write_saved(all) return to_show + + async def show_announcements( + self + ): + """显示公告""" + try: + announcements = await self.fetch_new() + for ann in announcements: + self.ap.logger.info(f'[公告] {ann.time}: {ann.content}') + + if announcements: + + await self.ap.ctr_mgr.main.post_announcement_showed( + ids=[item.id for item in announcements] + ) + except Exception as e: + self.ap.logger.warning(f'获取公告时出错: {e}') diff --git a/pkg/utils/version.py b/pkg/utils/version.py index 99d77fcd..dc0ae722 100644 --- a/pkg/utils/version.py +++ b/pkg/utils/version.py @@ -148,7 +148,7 @@ class VersionManager: with open("current_tag", "w") as f: f.write(current_tag) - self.ap.ctr_mgr.main.post_update_record( + await self.ap.ctr_mgr.main.post_update_record( spent_seconds=int(time.time()-start_time), infer_reason="update", old_version=old_tag, @@ -224,3 +224,13 @@ class VersionManager: return 0 + async def show_version_update( + self + ): + try: + + if await self.ap.ver_mgr.is_new_version_available(): + self.ap.logger.info("有新版本可用,请使用 !update 命令更新") + + except Exception as e: + self.ap.logger.warning(f"检查版本更新时出错: {e}")