Skip to main content

开发指南

文档说明

如果对于代码产生疑问,直接在搜索框内输入文件名即可

  • 代码规范对应 Readme 文档及 docs 文档、gitignore
  • 项目架构对应 docker-compose.yml,command 文件夹,napcat_log 文件夹以及各服务的 dockerfile
  • 消息处理对应 lrobot.message 文件夹中内容
  • 基础配置对应 main.py、config.py、secret.py 中的内容、storage 文件夹中的内容
  • 页面开发对应 vue 文件夹,lrobot.web 文件夹
  • 指令开发对应 lrobot.logic 文件夹
  • 功能开发(后端开发)最好玩
  • 前端开发样式又臭又长,也记不住,交给 AI
  • ssh与容器开发产生一大堆看不懂的日志,以及随网络变化有不同结果,错误不能复现就很麻烦,总之很诡异

后端开发

功能开发

  • 功能开发前,先想好一些常见的问题:
  • 所有的消息返回是否在数据编辑之后?可不可能消息返回'编辑成功但'数据'编辑失败'?
  • 消息是否有即时性?不能用 BILI(一分钟检测一次)
  • 是否需要复制?不能在 WECHAT 中使用换行(会自动转换成图片)
  • 是否会发送网址?不能使用 LR232(只能发送固定网址)
  • 消息中存在空值、多余的'\n'等等,会导致格式或逻辑错误吗?
  • 指令错误后,是否有错误提示指引用户输入正确指令?
条件设置
  • 在开发前,设想好功能涉及到的指令、用户、条件(顺序 or 状态)
  • 然后在localhost:5922/cab/command(或者域名/cab/command)中新建指令
  • 填写各参数
    • 指令名称和分组:便于找到指令和理解含义
    • 功能函数:指令调用的函数,
      • 一般建议以文件名_xx的格式放在logic.command.文件名里(虽然所有 logic.command 里的函数都注册完成了,但是统一以文件名开头便于查找)
    • 消息类型:包含私聊/群聊接收、添加、撤回、戳戳、回应、设精等
    • 平台:4 个平台
      • LR5921 功能最多
      • LR232 无法返回变化的网址(固定的可配置)
      • WECHAT 会发送图片无法复制
      • BILI 每隔 1 分钟反馈一次,太慢了
    • 用户组判定:返回消息发送者所在的一个或多个用户组;若在用户组中,同时返回内阁身份;若在测试员表中,返回测试员身份。若身份在配置的身份列表中则继续
    • 群组判定:返回消息所在的群组,若群组在群列表里则继续
    • 状态:必须要某状态才能触发,如必须要先进入成语接龙状态,才能进行接龙
    • 顺序
      • 用于匹配顺序,如 A 指令完全匹配的是"/你好",B 指令包含匹配的是"/你",则发送"/你好"时,如果 B 在前面,则会匹配到 B。此时应该拖动排序让 A 在前面(没有指定顺序时,显示顺序即为排序顺序)
      • 假设有一条匹配很多内容的指令(如成语接龙时,发送任意内容都要进行接龙),但是其他的"/"开头的指令又要先于它进行匹配(如"/退出成语接龙"必须要先于此指令匹配,否则永远无法退出),此时可以设置顺序,设置此指令的顺序为'-1',永远最后匹配,这样其他指令都在它前面。还可以设置 1,2,3,-1,-2,-3 之类的
    • 响应内容和匹配方式:具体可查看此处
      • 简要说明,内容可设置为:文字,[表情:xx],[at:xx],[猜拳:xx],[骰子:xx],[回复:xx],[转发:xx],[戳戳:xx],[动画表情:xx],[图片:xx],[语音:xx],[视频:xx],[文件:xx],[卡片:xx]的任意组合
      • 匹配方式分为包含匹配和完全匹配,内容均可设置多个,只需要其中一个包含匹配/完全匹配即可
      • 包含匹配为包含内容段,即一段内容区间包含匹配的内容;完全匹配需要与内容段完全相同
      • 上一点的完全相同指:如果[表情:xx]的“xx”不为 any,则必须一致;如果匹配字段为[表情:any],则可以匹配任何表情,无论是在包含匹配还是完全匹配都是如此
      • 文字的任意匹配没有 any,而是空格(仅在包含匹配中生效),即[表情:any] [at:any]能够匹配任意表情+任意文字+任意@的组合
  • 填写完成后,编辑 help_text,标题为#函数,同时写入注意、用法等,用于帮助指令的内容和功能页的展示内容,可参考此处
逻辑开发
  • 在 logic/command/xx 里开发对应的功能函数
from message.handler.msg import Msg
@monitor_adapter("/基础_帮助") # 数据统计中的名称
async def help_show(msg: Msg): # help.py 是文件名,函数名对应条件中的函数名
Msg(
platform=msg.platform,
event="发送",
kind=f"{msg.kind[:2]}发送",
seq=msg.seq,
content=content,
user=msg.user,
group=msg.group,
) # 消息发送,只需要 event 设置成发送,即可向对应用户发送消息
return content # 此处的 return 是用于数据统计中的结果值
  • 期间可以进行很多处理,如调用 file 中的函数等等
功能开发示例
  1. 设想
  • 假设现在需要开发一个"早上好"的功能,定期发送早上好
  • 首先设置逻辑与指令,需要三条指令:订阅早上好,发送早上好,取消订阅早上好
  • 平台面向的是所有平台吗?只有 LR5921 才能主动发送,故只设置 LR5921
  • 用户需要用户组吗?不需要,任何用户可订阅;群组功能需要吗?在群内发送不太好
  • 故消息类型设置为"私聊接收",用户、群组均不填
  • 状态?订阅早上好应该是任何状态,取消订阅应该是只有早上好状态才能触发
  • 发送早上好有消息接收吗?无,设计成定时产生消息即可
  1. 配置
  • 在 cab/command 中新建两条指令,名称为早上好_订阅,早上好_取消订阅,归于“早上好”组
  • 函数设置为 morning_subscribe,morning_unsubscribe
  • 响应内容为:"/订阅早上好","/取消订阅早上好",均为完全匹配
  • 消息类型为私聊接收,平台为 LR5921
  • 早上好_取消订阅的状态设计为"早上好""
  • 保存
  1. 开发
  • 新建 morning.py
  • 新建 morning_subscribe,morning_unsubscribe 函数
@monitor_adapter("/早上好_订阅") 
async def morning_subscribe(msg: Msg):
-----逻辑-----
Msg(
platform=msg.platform,
event="发送",
kind=f"{msg.kind[:2]}发送",
seq=msg.seq,
content="订阅成功",
user=msg.user,
group=msg.group,
)
return content
  • 逻辑处,需要给用户加上"早上好"的状态,调用 logic.data 里面的 status_add 函数
  • from logic import data await data.status_add(msg.user,"早上好") 直接引入 data 模块用于动态更新
  • 此时订阅便完成了,取消订阅的逻辑类似
  • 发送早上好需要用到定时函数 schedule_add,然后建立一个函数为 morning_send()
async def morning_send():
user_list=await data.status_check("早上好")
for user in user_list:
Msg(
platform="LR5921",
event="发送",
kind="私聊发送",
content="早上好"
user=user
)
  • 在 main 的 scheduler() 里面
asyncio.create_task(scheduler_add(morning, interval=86400))
  • 这样一个早上好的订阅、发送及取消的功能便做好啦
进阶开发
  • 可以查看指令开发/状态、用户、数据、文件,随后从后面的指令组中挑选功能相近的指令复制逻辑
  • 功能参考:
  • 常见数据库修改参考
  • 常见指令+序号逻辑、文本读取分割逻辑参考
  • 常见状态递增逻辑参考
  • 常见文字+图片两状态逻辑、图片下载逻辑参考

消息适配器开发

添加新平台
  • 在 message/adapter 下新建 xx_receive,xx_dispatch
  • 采用 fastapi 接口、ws 连接、轮询查询等方式接收消息
  • 处理成消息段格式(可以加一个 @monitor_adapter 用于统计)
  • 创建消息,将自动加入消息池处理
Msg(
platform="LR5921",
event="处理",
kind=kind,
seq=seq,
content=content,
user=user,
group=group,
)
  • 在 main.py 的 task_set 里加上平台启动条件,新建 xx_init 函数
  • 在页面 command.vue 的平台选择项中加入此平台,在已有的指令(如绑定平台)中补充此平台
添加新消息接收类型
  • 在消息处理时根据 kind_map 匹配处新的消息类型(或者把私聊接收拆分成私聊图片、文件等也可以)
  • 修改创建的 Msg 的 kind
  • 在 storage/yml/kind.yaml 中添加对应类型

添加新消息发送类型

  • 在 xx_dispatch 中加入新函数
  • 调用 request_deal 中的处理方式
  • 在 msg_send 中加入对应的路径

前端开发

  • 使用 vscode 打开 Lrobot/vue 文件夹
  • 在 views 里添加页面(注意使用import { http } from '@/api.js';),在 router/index.js 中添加路径
  • 在后端 Lrobot/lrobot/web/cab 中添加后端代码,重新构建 lrobot 容器
  • 使用 npm run dev 进行测试,打开http://localhost:5173/
  • 调试完成后,使用 npm run build 把 vue 自动打包项目到 lrobot 中(已配置好打包路径为 lrobot/web/frontend)

开发配置

  • 整体建议使用 pycharm 进行 python 后端开发,使用 vscode 进行前端 vue3 开发

数据可视化

  • 在 pycharm 中连接与查看数据源(需启动对应数据库容器)
    • 数据库-数据源-mysql,端口选择 5925,用户名选择 root,架构选择 lrobot_data
    • 数据库-数据源-MongoDB,端口选择 5924,架构选择 lrobot_log
  • 若使用方案 A,在数据库页查看 mysql 数据,在日志页查看 mongodb 数据

标红处理(强迫症狂喜)

  • 若遇到数据库语句标红,可配置对应的数据库方言并右键选择对应架构
  • 若遇到路径标红,右键 lrobot 子文件夹,将目录标记为源代码目录
  • 若遇到项目包标红,设置-python 解释器-docker compose-选择 lrobot-选择 python 解释器

环境管理

  • 引入新包时,将包名加入到 lrobot/requirements.in 中(注意是小写的 lrobot)
  • cd lrobot进入 lrobot 文件夹(注意是里面的小写的子文件夹)
  • 输入 docker run -it --rm -v %cd%:/app -w /app python:3.11 bash -c "python -m pip install --upgrade pip && pip install -r requirements.in && pip freeze > requirements.txt"
  • 生成新的环境依赖 requirements.txt,重新构建 docker 时自动安装

项目更新

  • 进入项目,使用 git pull origin master更新
  • 一般包含 _copy 的文件不会更新
  • logic 部分需要手动解决冲突(如果经常需要获取 git 更新且自己开发过的话)

项目迁移

  • storage/data/initdb 中的文件需要在 mysql 为空时才能生效,初始化前需要清空 storage/mysql 文件夹
  • 当 git 更新中存在新表时不会自动新建,需要手动使用数据库恢复方法导入新的 mysql_sql 中的数据(移动 mysql.mql 并把下方命令改路径改成 /app/backup/mysql.mql),或者备份后删除整个 mysql 文件夹(记得保存数据)后重新启动容器再导入
  • 数据库备份方法
    • 系统 24 小时自动备份一次
    • 手动备份:docker exec -it lrobot bash,cd /app/logic/data,python backup.py(此方法导出的是带日期的备份)
    • 导出空信息表 python backup.py a(此方法导出的即 mysql.sql)
    • 备份文件在 storage/data/backup 处
  • 数据库恢复方法(清空原有数据)
    • docker exec -it mysql bash,mysql -u root lrobot_data < /app/backup/mysql_2025-07-03.sql
    • docker exec -it mongodb bash,mongorestore --drop --uri="mongodb://localhost:27017" /app/backup/mongo_2025-07-03
  • 数据库手动恢复办法
    • docker exec -it mysql bash
    • mysql -u root -p,回车
    • USE lrobot_data;
    • 执行 mysql.sql 中的语句

pycharm环境相关

  • 在 pycharm 中,未命名的环境名为路径名
  • 在 anaconda 中,未命名的环境会以路径显示且无名字,只能以路径调用,conda env list