“每个人都可以有自己的随机脑洞” —— 一个插件化、可扩展、定位为“脑洞生成器”的 NoneBot2 Python 插件
RandomBrainHole 是一个基于 NoneBot2 的插件,旨在成为一个支持插件化扩展的“脑洞”记录、生成与分享平台。您可以自由扩展词库插件,记录、生成、分享各种天马行空的想法。本项目支持从特定格式文件导入数据到 SQLite 数据库,并通过配置驱动不同词库的随机获取、查询和填词等功能。
- 插件化词库:通过简单的配置和代码扩展,可以方便地添加新的词库类型和对应的处理逻辑。
- 数据库存储:使用 SQLite 存储所有词库数据,通过
import_data.py脚本进行数据导入和管理。 - 多功能交互:
- 随机获取:通过关键词触发,随机获取指定词库的词条。
- 查词功能:允许用户查询所有已配置词库中的特定词条。
- 随机填词:用户可以提供包含占位符的模板,插件会用相应词库的随机词条替换占位符。
- 灵活配置:通过
config.toml文件集中管理插件行为、词库关键词、数据库表名、处理函数等。 - 数据导入与校验:
import_data.py支持从 Excel (.xlsx) 和 Word (.docx) 文件导入数据,并进行文件哈希校验以避免重复导入。 - 清晰的日志记录:集成 NoneBot 日志系统,方便追踪和调试。
graph TD
A[用户发送消息] --> B{NoneBot 接收};
B --> C[plugin_loader:_master_message_handler];
C --> D{消息类型判断};
D -- 查词 --> E[查词处理流程];
D -- 随机填词 --> F[随机填词处理流程];
D -- 关键词触发 --> G[关键词触发处理流程];
D -- 其他/不匹配 --> Z[结束/传递给其他插件];
subgraph E [查词处理流程]
E1[提取查词关键词] --> E2[db_utils:search_term_in_db];
E2 --> E3[从数据库获取匹配项];
E3 --> E4{有匹配项?};
E4 -- 是 --> E5[动态加载格式化函数];
E5 --> E6[调用格式化函数];
E6 --> E7[组合结果];
E4 -- 否 --> E8[发送未找到消息];
end
subgraph F [随机填词处理流程]
F1[提取模板字符串] --> F2[解析模板中的占位符];
F2 --> F3{循环处理每个占位符};
F3 -- 未转义占位符 --> F4[db_utils:get_random_entry_from_db];
F4 --> F5[从数据库获取随机词条];
F5 --> F6[替换占位符];
F3 -- 转义占位符 --> F7[保留原文本];
F3 -- 处理完毕 --> F8[组合结果];
end
subgraph G [关键词触发处理流程]
G1[遍历config中各插件关键词] --> G2{消息命中关键词?};
G2 -- 是 --> G3[动态加载信息处理函数];
G3 --> G4[db_utils:get_random_entry_from_db];
G4 --> G5[调用信息处理函数格式化];
G2 -- 否 --> Z;
end
E7 --> H[发送响应消息给用户];
E8 --> H;
F8 --> H;
G5 --> H;
subgraph Init [初始化流程]
I1[Bot启动] --> I2[__init__.py];
I2 --> I3[加载config.toml];
I2 --> I4[注册数据库初始化钩子];
I4 --> I5[db_utils:create_tables_if_not_exists];
I2 --> I6[plugin_loader:create_plugin_handlers];
end
subgraph DataImport [数据导入流程 - 手动执行 import_data 脚本]
J1[运行 import_data.py] --> J2[读取 config.toml];
J2 --> J3[扫描 base_data_path 下各插件的 folder_name];
J3 --> J4[遍历数据文件];
J4 --> J5{文件哈希检查};
J5 -- 新文件/已更改 --> J6[调用对应解析函数];
J6 --> J7["用户确认 (示例数据)"];
J7 -- 确认 --> J8[db_utils:insert_data_to_db];
J8 --> J9[更新 imported_files_log];
J5 -- 未更改 --> J10[跳过];
end
graph LR
U[用户]
subgraph DataSource ["数据源文件"]
direction TB
Excel["词库.xlsx"]
Word["词库.docx"]
end
subgraph ImportProcess ["导入脚本 (import_data.py)"]
direction TB
IP1["读取配置 (base_data_path, folder_name)"]
IP2["文件解析器 (parse_*.py)"]
IP3["数据哈希与比较"]
IP4["数据插入逻辑"]
end
subgraph ConfigFiles ["配置文件"]
direction TB
CFG["config.toml"]
end
subgraph Database ["数据库 (SQLite)"]
direction TB
DB_Tables["词库表 (e.g., brainhole_terms)"]
DB_Log["日志表 (imported_files_log)"]
DB_Name["(random_brainhole_data.db)"]
style DB_Name fill:#fff,stroke:#fff,color:#555,fontSize:10px
end
subgraph PluginCore ["核心逻辑 (RandomBrainHole)"]
direction TB
PC_Init["初始化 (__init__.py)"]
PC_Loader["消息处理 (plugin_loader.py)"]
PC_DBUtils["数据库交互 (db_utils.py)"]
PC_Plugins["具体词库 (plugins/*.py)"]
end
subgraph BotPlatform ["Bot平台"]
direction TB
NB["NoneBot2 框架"]
OB["OneBot V11 适配器"]
end
DataSource -->|"手动放置文件"| IP1
CFG -->|"读取配置信息"| IP1
IP1 -->|"定位数据文件"| IP2
IP2 -->|"解析后数据"| IP4
IP3 -->|"文件是否更改"| IP2
IP4 -->|"写入数据与日志"| Database
U -- "发送消息" --> OB
OB -- "传递事件" --> NB
NB -- "分发给插件" --> PC_Init
PC_Init -- "加载配置" --> CFG
PC_Init -- "触发消息处理" --> PC_Loader
PC_Loader -- "请求数据" --> PC_DBUtils
PC_DBUtils -- "数据库读写" --> Database
PC_DBUtils -- "返回数据" --> PC_Loader
PC_Loader -- "调用插件逻辑" --> PC_Plugins
PC_Plugins -- "格式化数据" --> PC_Loader
PC_Loader -- "准备响应" --> NB
NB -- "通过适配器发送" --> OB
OB -- "响应消息" --> U
git clone [https://github.com/Dax233/RandomBrainHole.git](https://github.com/Dax233/RandomBrainHole.git)
# 或者直接下载 ZIP 包解压
cd RandomBrainHole(如果您的项目不是直接从该地址克隆,请调整此步骤为获取插件文件)
将 RandomBrainHole 文件夹放置到您的 NoneBot 项目的插件目录中(通常是 your_project/src/plugins/)。
确保您的 NoneBot 环境已安装以下依赖。如果您的项目使用 requirements.txt 或 pyproject.toml 管理依赖,请将这些添加到其中:
pip install pydantic toml pandas openpyxl python-docx
# 注意: NoneBot2 和适配器 (如 nonebot-adapter-onebot) 应已作为您Bot项目的基础依赖安装。
# Python 3.11+ 内置 tomllib,旧版本可能需要 toml。本插件使用 tomllib。- 复制插件目录下的
config.toml.example并重命名为config.toml。 - 编辑
config.toml,务必正确填写base_data_path指向您的原始词库文件存放的基础路径。 - 根据您的词库文件和期望功能,配置
[[plugins]]表格中的各项参数(详见下文“配置”部分)。
- 根据
config.toml中各plugins的folder_name设置,在base_data_path下创建相应的子文件夹,并将词库源文件(如.xlsx,.docx)放入。 - 检查并调整数据解析逻辑:
import_data.py中的parse_*函数需要与您的数据文件结构匹配。您可能需要修改这些函数。 - 在您的项目根目录运行数据导入脚本:
python -m src.plugins.RandomBrainHole.import_data # 或者根据您的项目结构调整路径 - 脚本会引导您完成数据导入,包括示例确认。
确保您的 NoneBot 项目已配置为加载 RandomBrainHole 插件。
例如,在您的 bot.py 或主配置文件中:
nonebot.load_plugin("src.plugins.RandomBrainHole") # 根据实际路径调整然后正常启动您的 NoneBot 机器人。
your_nonebot_project/
├── bot.py # (示例) NoneBot 项目入口/Bot主文件
├── pyproject.toml # (示例) 项目配置文件,含依赖
└── src/
└── plugins/
└── RandomBrainHole/ # 插件根目录
├── __init__.py # 插件加载入口 (元数据, 生命周期钩子)
├── config.toml.example # 配置文件模板
├── config.py # 配置模型与加载逻辑
├── db_utils.py # 数据库连接、表创建、查询工具
├── import_data.py # 数据导入脚本 (手动运行)
├── plugin_loader.py # 核心消息处理器与插件功能调度
├── plugins/ # 各具体词库的处理模块
│ ├── brainhole.py # 示例:脑洞词库模块
│ ├── pinshi.py
│ └── ... # 其他词库模块
└── README.md # (本文档)
-
创建词库逻辑模块: 在
RandomBrainHole/plugins/文件夹下新建一个 Python 文件,例如my_new_lexicon.py。 -
实现核心函数: 在该模块中,您需要实现至少两个异步函数:
async def random_info(table_name: str) -> str:- 功能:当匹配到此词库的关键词时被调用。
- 从
table_name指定的数据库表中随机获取一条记录 (可使用from ..db_utils import get_random_entry_from_db)。 - 调用下面的
format_data函数来格式化这条记录。 - 处理数据获取失败的情况(例如,如果表为空,可以返回
config.toml中配置的failure_message或抛出ValueError)。
async def format_data(word_info: Dict[str, Any], is_search_result: bool = True) -> str:- 功能:将从数据库获取的单条词库数据字典
word_info格式化为用户友好的字符串。 is_search_result参数用于区分是随机获取还是查词结果,可以据此调整输出的标题或格式。
- 功能:将从数据库获取的单条词库数据字典
-
更新数据库结构 (
db_utils.py):- 在
db_utils.py中,为您的新词库定义一个CREATE_TABLE_SQL语句,例如CREATE_MYLEXICON_TABLE_SQL。 - 将新表名和对应的 SQL 语句添加到
ALL_TABLE_SCHEMAS字典中。
- 在
-
更新数据导入脚本 (
import_data.py):- 添加一个新的数据解析函数,例如
parse_mynewlexicon_file(file_path: Path, source_file_name: str) -> Iterator[Dict[str, Any]]。此函数需要能解析您的原始数据文件格式,并yield出符合新表结构的字典。 - 在
import_data.py的main()函数内的parser_map字典中,添加新词库的映射,将词库的友好名称(将用于config.toml)映射到其解析函数和目标表名。例如:parser_map = { # ... 其他词库 ... "我的新词库": {"parser": parse_mynewlexicon_file, "table": "my_lexicon_table_name"}, }
- 添加一个新的数据解析函数,例如
-
配置新词库 (
config.toml): 在config.toml文件中,添加一个新的[[plugins]]配置块:[[plugins]] name = "我的新词库" # 对应 parser_map 中的键 module_name = "my_new_lexicon" # 对应步骤1中创建的文件名 (不含.py) info_function_name = "random_info" # 对应步骤2中实现的随机获取函数名 format_function_name = "format_data" # 对应步骤2中实现的格式化函数名 table_name = "my_lexicon_table_name" # 对应步骤3中定义的表名 search_column_name = "primary_field" # 此词库中用于搜索和填词的主要字段名 keywords = ["随机我的新词库", "来个新词库"] folder_name = "我的新词库数据" # import_data.py 使用的文件夹名,也是填词占位符 file_extensions = [".xlsx"] # 支持的文件扩展名 retry_attempts = 2 failure_message = "今天我的新词库也空空如也。"
-
导入数据与测试:
- 将您的新词库原始数据文件放到
base_data_path/我的新词库数据/目录下。 - 重新运行数据导入脚本 (
python -m src.plugins.RandomBrainHole.import_data)。 - 重启您的 NoneBot 机器人并测试新词库的功能。
- 将您的新词库原始数据文件放到
本项目默认使用 SQLite 数据库。主要的表结构在 db_utils.py 中的 CREATE_..._TABLE_SQL 常量中定义。
核心表包括:
- 词库数据表: 例如
brainhole_terms,pinshi_terms,fuzhipai_cards,suilan_terms,wuxing_terms,yuanxiao_terms,zhenxiu_terms等。这些表的具体列结构取决于对应词库的数据特性,通常在db_utils.py中定义,并在import_data.py的解析函数中体现。 imported_files_log: 用于记录已导入的数据文件及其哈希值,以避免重复导入。包含字段如file_identifier,file_hash,last_imported_at,status,plugin_type。
详细的表结构(列名、类型、约束)可以直接查看 db_utils.py 文件中的 CREATE TABLE SQL语句。
欢迎提交 issue、PR,也欢迎自定义你的“脑洞”插件!
- Fork 本仓库 (如果项目已在 GitHub 等平台开源)
- 新建分支开发你的功能 (例如:
git checkout -b feature/my-awesome-lexicon) - 提交你的更改 (例如:
git commit -m 'Add: My awesome lexicon plugin') - 推送到你的分支 (例如:
git push origin feature/my-awesome-lexicon) - 创建一个新的 Pull Request
本项目采用 MIT License。
有问题请直接提 Issue 或 PR,欢迎一起“脑洞大开”!