# NEO Bot Framework ## 📖 概述 NEO 是一个基于 Python 的现代化 OneBot 11 协议机器人框架,专为需要高性能、可扩展性和开发效率的团队设计。该框架通过 WebSocket 与各种 OneBot 实现端(如 NapCatQQ、LLOneBot 等)通信,提供了一套完整的机器人开发解决方案。 ### 设计理念 NEO 框架的设计遵循以下核心理念: 1. **开发者友好**:简洁的 API 设计、完整的类型提示和详细的文档,让开发者能够快速上手和高效开发 2. **架构清晰**:采用模块化设计,分离关注点,使代码易于维护和扩展 3. **高性能异步**:基于 `asyncio` 和 `websockets` 构建,支持高并发消息处理 4. **类型安全**:全面使用 Python 类型系统,提供编译时类型检查,减少运行时错误 5. **热重载支持**:支持插件热重载,开发过程中修改代码无需重启机器人 ### 核心价值 - **快速原型开发**:通过简洁的装饰器语法快速定义指令和事件处理器 - **生产环境就绪**:内置断线重连、错误处理和性能监控机制 - **可扩展架构**:支持自定义插件、中间件和权限系统 - **现代化开发体验**:支持热重载、类型提示和完整的 API 文档 ### 适用场景 - QQ 群机器人管理 - 自动化客服与问答系统 - 游戏社区管理 - 团队内部工具集成 - 教育与培训辅助 ## ✨ 特性 * **OneBot 11 标准支持**:完整支持 OneBot 11 的消息、通知、请求和元事件。 * **类型安全**:基于 `dataclasses` 的强类型事件模型,开发体验更佳。 * **插件系统**:轻量级的装饰器风格插件系统,支持指令 (`@matcher.command`) 和事件监听 (`@matcher.on_notice`, `@matcher.on_request`)。 * **插件元数据与内置帮助**:插件可通过 `__plugin_meta__` 变量进行自我描述。框架核心内置了 `/help` 指令,可自动收集并展示所有插件的帮助信息,无需手动维护。 * **🔥 热重载支持**:内置文件监控,修改 `base_plugins` 下的代码自动重载,无需重启,极大提升调试效率。 * **异步核心**:基于 `asyncio` 和 `websockets` 的高性能异步核心。 * **自动重连**:内置 WebSocket 断线重连机制。 ## ⚡️ 性能优化 ### Redis 缓存机制 为了提升响应速度并减少对 OneBot API 的重复调用,框架核心集成了一套基于 Redis 的缓存系统。对于一些不频繁变更的数据(如群信息、好友列表等),首次查询后会将其缓存至 Redis,在缓存有效期内(默认为 1 小时),后续请求将直接从 Redis 读取,极大提升了性能。 #### 工作原理 - **自动缓存**:框架会自动缓存特定 API 的调用结果。 - **缓存键**:缓存键根据 API 名称和关键参数(如 `group_id`, `user_id`)生成,确保唯一性。 - **过期时间**:默认缓存 1 小时,之后会自动失效,下次调用时将重新从 OneBot 实现端获取最新数据。 #### 受影响的 API 以下核心 API 已默认启用缓存: - `get_group_info` - `get_group_member_info` - `get_friend_list` - `get_stranger_info` - `get_login_info` #### 如何绕过缓存 在某些场景下,你可能需要获取实时数据而非缓存数据。为此,所有受缓存影响的 API 方法都增加了一个 `no_cache: bool = False` 的可选参数。 当你需要强制从服务器获取最新信息时,只需在调用时传入 `no_cache=True` 即可。 **示例:** ```python # 正常调用,会使用缓存 group_info = await bot.get_group_info(group_id=12345) # 强制获取最新信息,不使用缓存 latest_group_info = await bot.get_group_info(group_id=12345, no_cache=True) ``` ### `__slots__` 内存优化 框架内的所有数据模型(包括事件、消息段、API 返回对象等)均已启用 `__slots__ = True` 优化。这可以显著减少每个对象实例的内存占用,特别是在处理大量事件和数据时,能够有效降低机器人的整体内存消耗。 ## 📝 待办事项 (TODO) ### API 封装 - [x] **消息相关** - `delete_msg`: 撤回消息 - `get_msg`: 获取消息 - `get_forward_msg`: 获取合并转发消息 - `send_like`: 发送点赞 - [x] **群组管理** - `set_group_kick`: 群组踢人 - `set_group_ban`: 群组单人禁言 - `set_group_anonymous_ban`: 群组匿名禁言 - `set_group_whole_ban`: 群组全员禁言 - `set_group_admin`: 群组设置管理员 - `set_group_anonymous`: 群组匿名 - `set_group_card`: 设置群名片(群备注) - `set_group_name`: 设置群名 - `set_group_leave`: 退出群组 - `set_group_special_title`: 设置群组专属头衔 - [x] **群组信息** - `get_group_info`: 获取群信息 - `get_group_list`: 获取群列表 - `get_group_member_info`: 获取群成员信息 - `get_group_member_list`: 获取群成员列表 - `get_group_honor_info`: 获取群荣誉信息 - [x] **用户相关** - `get_login_info`: 获取登录号信息 - `get_stranger_info`: 获取陌生人信息 - `get_friend_list`: 获取好友列表 - [x] **请求处理** - `set_friend_add_request`: 处理加好友请求 - `set_group_add_request`: 处理加群请求/邀请 - [x] **系统/其他** - `get_version_info`: 获取版本信息 - `get_status`: 获取状态 - `can_send_image`: 检查是否可以发送图片 - `can_send_record`: 检查是否可以发送语音 - `clean_cache`: 清理缓存 ### 待实现 API - [ ] **Web 凭证类** - `get_cookies` - `get_csrf_token` - `get_credentials` - [ ] **文件/资源信息** - `get_image` - `get_record` - `get_file` - [ ] **系统控制** - `set_restart` - [ ] **扩展功能** - [x] `send_forward_msg`: 发送合并转发消息 ### 其他改进 - [x] **API 强类型封装**: 将 API 返回值从 `dict` 转换为数据模型对象。 - [x] **Redis 支持**: 集成 Redis 连接池,便于插件复用连接。 - [ ] **日志系统优化**: 引入更完善的日志记录机制,支持文件输出和日志级别控制。 - [ ] **异常处理增强**: 增强插件执行过程中的异常捕获,防止单个插件崩溃影响整个 Bot。 - [ ] **中间件支持**: 添加消息处理中间件,支持在指令执行前/后进行拦截和处理。 - [ ] **权限系统**: 实现基础的权限管理(如超级管理员、群管理员等)。 ## 📂 项目结构 ``` NEO/ ├── plugins/ # 插件目录,新建插件文件即可自动加载(支持热重载) │ ├── echo.py # 示例插件:实现 /echo 和 /赞我 指令 │ ├── forward_test.py # 示例插件:演示合并转发消息的构建和发送 │ ├── jrcd.py # 娱乐插件:提供 /jrcd 和 /bbcd 指令 │ └── thpic.py # 图片插件:提供 /thpic 指令,发送随机东方图片 ├── core/ # 核心框架代码 │ ├── api/ # API 模块抽象层 (MessageAPI, GroupAPI, FriendAPI, AccountAPI) │ │ ├── __init__.py │ │ ├── account.py │ │ ├── base.py │ │ ├── friend.py │ │ ├── group.py │ │ └── message.py │ ├── bot.py # Bot API 封装,提供 send_group_msg 等方法 │ ├── command_manager.py # 命令与事件分发器 │ ├── config_loader.py # 配置加载器 │ ├── plugin_manager.py # 插件加载与管理 │ ├── redis_manager.py # Redis 连接管理器 │ └── ws.py # WebSocket 客户端核心 ├── models/ # 数据模型 │ ├── events/ # OneBot 事件定义 (Message, Notice, Request, Meta) │ ├── message.py # 消息段定义 (MessageSegment) │ └── sender.py # 发送者定义 (Sender) ├── config.toml # 配置文件 ├── main.py # 启动入口(包含热重载监控) └── requirements.txt # 项目依赖 ``` ## 🚀 快速开始 ### 1. 环境准备 * Python 3.8+ * OneBot 11 实现端(推荐 [NapCatQQ](https://github.com/NapNeko/NapCatQQ) 或 LLOneBot) ### 2. 安装依赖 ```bash pip install -r requirements.txt ``` ### 3. 配置文件 修改根目录下的 `config.toml`,配置 WebSocket 连接信息: ```toml [napcat_ws] uri = "ws://127.0.0.1:30004" # OneBot 实现端的 WebSocket 地址 token = "your_token" # Access Token (如果有) reconnect_interval = 5 # 断线重连间隔(秒) [bot] command = ["/"] # 指令前缀,支持多个,如 ["/", "#"] ``` ### 4. 运行 ```bash python main.py ``` ## 🛠️ 开发指南 ### 🔥 热重载调试 项目集成了 `watchdog` 文件监控。在开发过程中,你只需要: 1. 保持 `main.py` 运行。 2. 修改或新建 `base_plugins` 目录下的 `.py` 插件文件。 3. 保存文件。 4. 控制台会自动提示 `[HotReload] 插件重载完成`,新的逻辑立即生效。 ### 创建新插件 在 `base_plugins` 目录下创建一个新的 `.py` 文件(例如 `my_plugin.py`),框架会自动加载它。 ### 示例代码 #### 1. 注册消息指令 使用 `@matcher.command("指令名")` 注册指令。 ```python from core.command_manager import matcher from core.bot import Bot from models import MessageEvent # 注册 /hello 指令 @matcher.command("hello") async def handle_hello(bot: Bot, event: MessageEvent, args: list[str]): # args 是去除指令后的参数列表 await event.reply("你好!这里是 NEO Bot。") ``` #### 2. 监听通知事件 使用 `@matcher.on_notice("通知类型")` 监听通知。 ```python from core.command_manager import matcher from core.bot import Bot from models import GroupIncreaseNoticeEvent # 监听群成员增加事件 @matcher.on_notice("group_increase") async def welcome_new_member(bot: Bot, event: GroupIncreaseNoticeEvent): await bot.send_group_msg(event.group_id, f"欢迎新成员 {event.user_id} 加入!") ``` #### 3. 监听请求事件 使用 `@matcher.on_request("请求类型")` 监听请求。 ```python from core.command_manager import matcher from core.bot import Bot from models import FriendRequestEvent # 自动同意好友请求 @matcher.on_request("friend") async def auto_approve_friend(bot: Bot, event: FriendRequestEvent): await bot.call_api("set_friend_add_request", { "flag": event.flag, "approve": True }) ``` #### 4. API 调用方式对比 框架提供两种 API 调用方式:**类型化 API**(推荐)和 **通用 API**(备用)。 ##### 方式一:类型化 API(推荐) 对于已封装的 API,框架提供了类型化的方法,返回数据模型对象而非原始字典: ```python from core.command_manager import matcher from core.bot import Bot from models import MessageEvent from models.objects import Group @matcher.command("info") async def get_group_info_typed(bot: Bot, event: MessageEvent, args: list[str]): # 使用类型化 API,返回 Group 对象 group: Group = await bot.get_group_info(event.group_id) await event.reply(f"群名:{group.group_name}\n成员数:{group.member_count}\n创建时间:{group.create_time}") ``` ##### 方式二:通用 API(备用) 如果框架尚未封装某个 OneBot API,你可以使用 `bot.call_api` 直接调用。这是通用的备用调用方法。 ```python from core.command_manager import matcher from core.bot import Bot from models import MessageEvent @matcher.command("info_legacy") async def get_group_info_legacy(bot: Bot, event: MessageEvent, args: list[str]): # 直接调用 get_group_info API # action: API 名称 # params: API 参数字典 resp = await bot.call_api("get_group_info", { "group_id": event.group_id, "no_cache": False }) if resp.get("status") == "ok": group_name = resp["data"]["group_name"] await event.reply(f"当前群名:{group_name}") ``` **建议**:优先使用类型化 API,获得更好的类型安全和代码提示。仅在框架未封装特定 API 时使用通用 API。 ## 📖 插件开发指南 ### 插件基本结构 一个标准的插件文件应该包含以下部分: 1. **模块文档字符串**:描述插件功能 2. **导入必要的模块**:从 `core` 和 `models` 导入所需类 3. **使用装饰器注册事件处理器**:`@matcher.command()`, `@matcher.on_notice()`, `@matcher.on_request()` 4. **异步函数实现业务逻辑**:使用 `async def` 定义处理函数 ### 插件元数据 (`__plugin_meta__`) 为了实现插件的自动发现和帮助信息的自动生成,框架引入了插件元数据机制。你需要在你的插件模块中定义一个名为 `__plugin_meta__` 的字典。 `load_all_plugins` 函数在加载插件时会自动读取这个变量,并将其注册到 `CommandManager` 中。`/help` 指令会遍历所有已注册的元数据,生成格式化的帮助信息。 一个标准的 `__plugin_meta__` 包含以下字段: - `name` (str): 插件的友好名称,例如 "回声"。 - `description` (str): 对插件功能的简短描述。 - `usage` (str): 插件的使用方法,可以包含多个指令和它们的说明。 **示例:** ```python # base_plugins/echo.py __plugin_meta__ = { "name": "回声与交互", "description": "提供 echo 和 赞我 功能", "usage": "/echo [内容] - 复读内容\n/赞我 - 让机器人给你点赞", } ``` ### 使用类型化 API 框架现已提供完整的类型化 API 封装,建议优先使用这些封装方法而非原始的 `call_api`: | API 方法 | 返回类型 | 说明 | |---------|---------|------| | `bot.send_group_msg()` | `Message` | 发送群消息 | | `bot.get_group_info()` | `Group` | 获取群信息 | | `bot.get_group_member_info()` | `GroupMember` | 获取群成员信息 | | `bot.get_friend_list()` | `List[Friend]` | 获取好友列表 | | `bot.get_login_info()` | `LoginInfo` | 获取登录信息 | | `bot.get_version_info()` | `VersionInfo` | 获取版本信息 | #### 示例:使用类型化 API 重构群信息查询 ```python from core.command_manager import matcher from core.bot import Bot from models import MessageEvent from models.objects import Group @matcher.command("group_info") async def get_group_info_typed(bot: Bot, event: MessageEvent, args: list[str]): # 使用类型化 API,返回 Group 对象而非字典 group: Group = await bot.get_group_info(event.group_id) await event.reply(f"群名:{group.group_name}\n成员数:{group.member_count}\n创建时间:{group.create_time}") ``` ### 事件处理模式 除了基本的消息指令,还可以处理多种事件类型: #### 1. 通知事件处理 ```python from models import GroupCardChangeEvent @matcher.on_notice("group_card") async def handle_group_card_change(bot: Bot, event: GroupCardChangeEvent): # event.card_new 是新名片,event.card_old 是旧名片 await bot.send_group_msg(event.group_id, f"成员 {event.user_id} 的名片从 '{event.card_old}' 改为 '{event.card_new}'") ``` #### 2. 请求事件处理 ```python from models import GroupRequestEvent @matcher.on_request("group") async def handle_group_request(bot: Bot, event: GroupRequestEvent): # 根据请求类型处理 if event.sub_type == "add": # 自动同意加群请求 await bot.set_group_add_request(event.flag, event.sub_type, approve=True) await bot.send_group_msg(event.group_id, f"已同意用户 {event.user_id} 的加群请求") ``` ### 错误处理 建议在插件中添加适当的错误处理,避免单个插件崩溃影响整个机器人: ```python @matcher.command("dangerous") async def dangerous_command(bot: Bot, event: MessageEvent, args: list[str]): try: # 可能失败的操作 result = await bot.call_api("some_api", {"param": "value"}) await event.reply(f"成功:{result}") except Exception as e: await event.reply(f"执行失败:{str(e)}") # 记录日志 import logging logging.error(f"插件执行错误:{e}", exc_info=True) ``` ### 插件开发最佳实践 1. **单一职责**:每个插件专注于一个功能领域 2. **错误处理**:妥善处理可能发生的异常 3. **类型提示**:为函数参数和返回值添加类型提示 4. **文档完整**:为每个函数添加文档字符串 5. **性能考虑**:避免在插件中执行耗时同步操作 6. **资源清理**:必要时使用 `try...finally` 确保资源释放 ### 🚀 高性能插件开发规范 (避坑指南) 为了保证整个机器人框架的响应速度和稳定性,所有插件都必须遵循异步、非阻塞的开发原则。任何一个插件中的阻塞操作都可能导致整个机器人卡顿或无响应。 以下是必须遵守的核心规范: #### 1. 禁止任何形式的同步网络请求 - **错误示范**: 使用 `requests` 库发起网络请求。 ```python import requests # 错误!这会阻塞整个程序 response = requests.get("https://api.example.com") ``` - **正确做法**: 必须使用异步 HTTP 客户端,如 `aiohttp` 或 `httpx`。 ```python import httpx # 正确,使用 async with 和 await async with httpx.AsyncClient() as client: response = await client.get("https://api.example.com") ``` #### 2. 禁止使用 `time.sleep()` - **错误示范**: 使用 `time.sleep()` 进行等待。 ```python import time # 错误!这会阻塞事件循环 time.sleep(5) ``` - **正确做法**: 必须使用 `asyncio.sleep()`。 ```python import asyncio # 正确,这会将控制权交还给事件循环 await asyncio.sleep(5) ``` #### 3. 谨慎处理文件 I/O - 对于读写小型、本地文件,直接使用 `with open(...)` 通常是可接受的。 - 但对于大型文件或网络文件系统(NFS)上的文件,同步 I/O 可能会导致明显的阻塞。 - **推荐做法**: 对于可能耗时较长的文件操作,使用 `aiofiles` 库。 ```python import aiofiles async with aiofiles.open('large_file.dat', mode='rb') as f: contents = await f.read() ``` #### 4. 将 CPU 密集型任务移出事件循环 - 如果插件需要执行复杂的计算(例如,图像处理、视频转码、数据分析),这些任务会长时间占用 CPU,同样会阻塞事件循环。 - **正确做法**: 使用 `loop.run_in_executor()` 将这类任务抛到独立的线程池或进程池中执行。 ```python import asyncio def cpu_bound_task(data): # 这是一个耗时的同步函数 # ... 进行大量计算 ... return "计算结果" # 在异步的事件处理器中调用 loop = asyncio.get_running_loop() # `None` 表示使用默认的线程池 result = await loop.run_in_executor(None, cpu_bound_task, "一些数据") await event.reply(result) ``` 遵循以上规范,可以确保您开发的插件不会成为整个机器人应用的性能瓶颈。 ### 示例:完整插件模板 ```python """ 天气查询插件 提供 /weather 指令,查询指定城市的天气信息。 """ from core.command_manager import matcher from core.bot import Bot from models import MessageEvent # 插件元数据,用于 help 指令 __plugin_meta__ = { "name": "天气查询", "description": "查询指定城市的天气信息", "usage": "/weather [城市名称]", } @matcher.command("weather") async def handle_weather(bot: Bot, event: MessageEvent, args: list[str]): """ 查询天气信息 :param bot: Bot 实例 :param event: 消息事件对象 :param args: 指令参数列表(城市名称) """ if not args: await event.reply("请输入城市名称,例如:/weather 北京") return city = " ".join(args) try: # 这里可以调用天气 API weather_info = f"{city} 的天气:晴,25℃" await event.reply(weather_info) except Exception as e: await event.reply(f"查询天气失败:{str(e)}") # 可以注册多个事件处理器 @matcher.on_notice("group_increase") async def welcome_new_member(bot: Bot, event): await bot.send_group_msg(event.group_id, f"欢迎新成员 {event.user_id} 加入!") ``` ## 📚 事件模型说明 项目采用了基于工厂模式的事件处理系统,所有事件定义在 `models/events/` 下: * **MessageEvent**: 消息事件,包含 `PrivateMessageEvent` 和 `GroupMessageEvent`。支持 `await event.reply()` 快速回复。 * **NoticeEvent**: 通知事件,如 `FriendAddNoticeEvent`, `GroupRecallNoticeEvent` 等。 * **RequestEvent**: 请求事件,如 `FriendRequestEvent`, `GroupRequestEvent`。 * **MetaEvent**: 元事件,如心跳 `HeartbeatEvent`。 所有事件均继承自 `OneBotEvent`,并包含 `bot` 属性用于调用 API。 ## 🏗️ 技术架构 NEO 框架采用分层架构设计,各层职责明确,便于维护和扩展: ### 架构层次 1. **通信层 (WebSocket Client)** - 负责与 OneBot 实现端的 Web Socket连接 - 实现断线自动重连机制 - 处理原始消息的收发和协议解析 2. **API 抽象层 (API Mixins)** - 提供类型安全的 API 封装 - 按功能领域划分:消息、群组、好友、账号 - 所有 API 返回强类型数据模型对象 3. **业务逻辑层 (Bot & Command Manager)** - Bot 类组合所有 API 功能 - 指令和事件分发器 - 插件加载和管理 4. **插件层 (Plugins)** - 支持热重载的插件系统 - 装饰器风格的注册方式 - 独立的业务逻辑模块 5. **数据模型层 (Models)** - 基于 dataclasses 的事件模型 - API 响应数据模型 - 类型安全的序列化/反序列化 ### 核心组件交互 ``` ┌─────────────────────────────────────┐ │ 插件层 (Plugins) │ │ @matcher.command() │ │ @matcher.on_notice() │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ 业务逻辑层 (Command Manager) │ │ • 事件分发与路由 │ │ • 指令参数解析 │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ Bot 组合类 │ │ • 继承所有 API Mixin │ │ • 提供统一接口 │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ API 抽象层 (Mixin) │ │ • MessageAPI │ │ • GroupAPI │ │ • FriendAPI │ │ • AccountAPI │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ 通信层 (WebSocket) │ │ • 连接管理 │ │ • 消息编解码 │ │ • 断线重连 │ └─────────────────────────────────────┘ ``` ### 设计模式应用 - **工厂模式**:事件对象的创建和管理 - **装饰器模式**:插件和指令的注册 - **组合模式**:Bot 类通过继承组合 API 功能 - **观察者模式**:事件监听和处理 - **策略模式**:不同的消息处理策略 ### 性能特点 - **异步非阻塞**:全面基于 asyncio,支持高并发 - **内存高效**:事件和模型对象使用 dataclasses,内存占用小 - **快速响应**:插件热重载和事件分发机制确保快速响应 - **可扩展性**:模块化设计便于功能扩展和定制 --- *Internal Use Only - DOGSOHA ond baby2016 by Fairy-Oracle-Sanctuary*