跳到主要内容

帮助

  • 每次更新指令时,除了要在指令配置页配置条件,还需要在 help 指令中写指令的用法,在 panel 页写测试说明、范围等等,太麻烦了
  • 于是写了一个半自动生成的机制,通过读取指令配置 command.yaml 和自定义内容 help.txt 实现指令用法与 panel 页说明的自动生成

帮助设计

  • 指令'/帮助'分为总帮助和指令组帮助
  • '/帮助'返回的是整体指令说明,包括指令、平台和使用说明
  • '/帮助,[指令组]'返回的是指令组内指令的用法

帮助文本

  • help.txt 里配置具体的帮助说明
  • 以基础指令为例
# bind_platform
用法: /绑定: 在非 LR5921 平台中生成该平台的验证消息
注意: \n验证码为系统随机生成,有效期五分钟\n其他平台绑定过 QQ 则显示已绑定
测试: \n在各平台私聊进行绑定测试,结合其他功能的状态,测试绑定是否能够同步状态\n包括同步各平台不同的状态;同步各平台相同但信息不同的状态(如答题进度)\n解绑比较麻烦且不需要,若测试时需要解绑联系管理员
  • bind_platform 是指令页面配置的函数名
  • 用法是用户在帮助页和展示页看到的说明
  • 注意和测试是显示在展示页的
  • 配置后,采用'/帮助,基础',显示:
  • /绑定: 在非 LR5921 平台中生成该平台的验证消息 (232,B,W)(私)
  • 其中基础是指令组,在配置页配置的
  • 然后是用法,一般形式为指令:解释,指令中变量可以带[],注意在帮助文本里添加上用法:
  • 后面的分别是平台、私聊、群聊,会自动根据指令配置里的平台判断
  • 如果私聊限制了身份组,则为管理指令
  • @[用户]/设置密码,[密码]: 设置测试员密码 (5921)(微部)(公测)
  • 管理指令只有管理员能看到,在常规指令空一行下方
  • 后面也是平台、私聊、群聊,如微部代表私聊中微部身份可用,公测代表群聊公测群可用
  • 展示页
  • 展示页中,功能组为系统(在 cab/panel 中配置)
  • 然后子标题为用法
  • 第一行为平台:平台,用户:用户组,群聊:群组,其中包含所有用户/群聊的会显示成'私'和'群'
  • 注意和测试会显示在下面,如果需要像这样换行显示,注意: \n验证码,需要冒号后面的换行符

特殊 1

  • 像页面功能等其他的,不在指令页配置,没有相关参数,需要自己设计,测试说明组和最后的页面功能组均在此类
  • 填写分组,会按分组显示在展示页中
  • 说明里没有冒号的句子会被直接提取出来放在下面,如此例子中的下面四行会被直接展示
# firefly_func
分组: 测试说明
用法: 此页面为测试页面,展示多个功能组与功能
功能组,相似的功能集合\n功能,系统功能,分为功能类(页面功能)和指令类(以/开头的消息功能)
每个功能下的子项为功能描述\n用法,即指令的使用方法,[]包裹的为可变内容,其他为固定值\n优先级,即指令匹配的优先级,优先级高的先匹配,不关注此项则容易指令间互相出bug\n平台,指令使用范围,LR5921(5921),LR232(232),(并称LR),WECHAT(W),BILI(B)\n用户,指令的私聊范围,除'全'外为身份组\n群聊,指令的群聊范围\n注意,指令说明\n测试,测试说明及要求
!!测试员任务!!\n在包含测试的功能下按照测试要求进行测试\n测试完成后在文本框内输入测试结果/反馈/建议
此处可直接写建议或反馈
  • 展示页

特殊 2

  • 缺少配置类指令,通常在指令中附加了筛选条件,firefly_in,activity_hunt_problem
  • 如 firefly_set 的触发条件是公测群,没有用户条件(函数内部有对于用户的判断),故加一个用户,可以覆盖掉对应的指令条件
  • 然后由于没有指定用户,会被认为是非管理指令,需要加一个管理:是
# firefly_set
用法: @[用户]/设置密码,[密码]: 设置测试员密码
用户: 微部
注意: 仅微部在公测群中可用
管理: 是

特殊 3

  • 非管理指令,通常是不希望被非管理看到的指令,base_welcome,base_unknown
  • 以及 base_welcome 由于没有用户会被归类到非管理中,但普通社员不需要知道此条指令,故加一个管理
  • 添加管理后,用户为空则不会在指令中显示用户,与结果不符,加一个用户:私
# base_welcome
用法: [私聊添加]: 欢迎消息
用户: 私
管理: 是
注意: 在所有平台添加好友时触发
测试: 考虑是否需要修改欢迎词

特殊 4

  • 无配置指令,不在指令页配置,record_write,activity_diary_answer
  • 这个是在 help_forward 中检索的一个非指定条件式指令,不在指令页配置
  • 需要手动添加分组、平台、群聊、管理
# record_write
分组: 基础
用法: [群消息]: 记录对应的群消息
平台: 全
群聊: 群
管理: 是
测试: 测试记录各种消息

文档解析

  • filter_set 是筛选项,help_mode 代表帮助指令格式,否则是展示页格式
  • 从 help.txt 加载文档为 base
  • 构建func:{用法:[],注意:xx,测试:xx,lines:[]}的字典
    • 其中用法可以是多行,提取列表
    • 其他带冒号的一般是用户、群聊、管理、注意、测试(其他的变量也解析不了)
    • 最后的 lines 是不带冒号的内容,用于展示在展示页最后
  • 非容器环境跳过 check_restart 指令
  • 寻找指令配置中的对应指令
  • 查找分组
    • base 中的优先,覆盖掉指令配置中的
  • 跳过不在 filter_set 筛选分组中的
  • 查找注意
    • 只在 base 中有
  • 查找测试
    • 只在 base 中有
  • 查找优先级
    • base 中的优先,覆盖掉指令配置中的
  • 查找平台
    • base 中的优先,覆盖掉指令配置中的
    • 指令配置中的进行简化
      • LR232+LR5921 变成 LR
      • WECHAT 变成 W
      • BILI 变成 B
      • 若超过三个且有 LR,变成全
  • 查找状态
    • base 中的优先,覆盖掉指令配置中的
  • 查找用户
    • base 中的优先,覆盖掉指令配置中的
    • 指令配置中的进行简化
      • 如果存在私聊接收类型且不存在配置,变为'私'
  • 查找群聊
    • base 中的优先,覆盖掉指令配置中的
    • 指令配置中的进行简化
      • 去除内测群
      • 若公测群、水群、内阁均在列表中,变为'群'
      • 公测群简化为公'测'
  • 查找管理
    • 如果存在用户配置,则是管理
    • 此处默认所有管理操作都是配置了 user 身份的
  • 展示页格式
    • title_parts 是展示页标题行,用 \n 连接
    • 先把平台、用户、群聊整成一行
    • other_lines 是展示页内容行
    • 添加平台用户群聊行、优先级行、状态行、注意行、测试行
    • other_lines.lines 是无标题行
    • func:{title,lines}的格式返回
  • 帮助说明格式
    • 对于用法列表中的多行分开处理
    • 管理指令
      • 添加用括号包着的具体的平台、用户、群
    • 普通指令
      • 存在用户则添加'私'
      • 存在群聊则添加'群'
      • 此处默认了普通的指令操作无 user 身份,且存在群则是所有群,且此操作冗余,上面已经转换了'私'和'群'

帮助

  • 使用 re 分割指令
  • 判断内阁身份(群为内阁群/公测群,私聊身份中包含'内阁')
  • 长度为 2 时
    • 根据指令组为基础,入会,收集表,游戏,工具,订阅,活动,系统调用对应的文档解析
    • 返回普通指令
    • 若有内阁身份,额外返回管理指令
  • 长度为 1 时(注:此处没加=='帮助'的判断,即'/帮助1'也会匹配到此处)
    • 返回基础帮助说明
def platform_short(platforms):
"""平台缩写转换"""
s = set(platforms)
short = set()
if "LR232" in s and "LR5921" in s:
short.add("LR")
else:
if "LR232" in s:
short.add("232")
if "LR5921" in s:
short.add("5921")
if "WECHAT" in s:
short.add("W")
if "BILI" in s:
short.add("B")
# 若四个平台都有,则简写为“全”
if len(short) >= 3 and "LR" in short:
return "全"
return ",".join(sorted(short))


def users_short(users, kinds):
"""用户转换"""
if not users and "私聊接收" in kinds:
return "私"
return ",".join(users)


def groups_short(groups):
"""群聊简称转换"""
if {"公测群", "水群", "内阁"}.issubset(groups):
return "群"
filtered = [g for g in groups if g != "内测群"]
short = ["公测" if g == "公测群" else g for g in filtered]
return ",".join(sorted(short))


def docs_merge(filter_set, help_mode=True):
"""将 command.yml 与 help.txt 信息合并"""
docs = help_txt_load()
text1, text2, text3 = {}, [], []
for func_name, base in docs.items():
if func_name == "check_restart" and not config["SERVER_IP"]:
continue # 非容器环境跳过此命令
cmd = next((c for c in config["commands"] if c["function"] == func_name), None)

group_set = base.get("分组", cmd["set"] if cmd else None)
if group_set != filter_set:
continue
attention = base.get('注意', '')
test = base.get('测试', '')
order = base.get('优先级', cmd["order"] if cmd else None)
platformshort = base.get("平台", platform_short(cmd["platforms"]) if cmd else None)
platforms = base.get("平台", cmd["platforms"] if cmd else None)
status = base.get("状态", ",".join(cmd["state"]) if cmd else None)
users = base.get("用户", users_short(cmd["users"], cmd["kind"]) if cmd else None)
groups = base.get("群聊", groups_short(cmd["groups"]) if cmd else None)
manager = base.get("管理", '是' if cmd and cmd["users"] else '否')

if not help_mode:
title_parts = []
for usage in base["用法"]:
title_parts.append(usage)
other_lines = []
p_line = ""
if platforms:
p_line += f"平台: {platforms};"
if users:
p_line += f"用户: {users};"
if groups:
p_line += f"群聊: {groups};"
if p_line:
other_lines.append(p_line)
if order:
other_lines.append(f"优先级: {order}")
if status:
other_lines.append(f"状态: {status}")
if attention:
other_lines.append(f"注意: {attention}")
if test:
other_lines.append(f"测试: {test}")
other_lines.extend(base.get("lines", [])) # 无标题行
text1[func_name] = {
"title": "\n".join(title_parts), # 用法作为title
"lines": other_lines # 其他信息行
}

continue # 跳过下面赋值

for ue in base["用法"]:
if manager == "是":
t2 = ue
t2 += f" ({platforms})"
if users:
t2 += f"({users})"
if groups:
t2 += f"({groups})"
text2.append(t2)
else:
label_kinds = []
if users:
label_kinds.append("私")
if groups:
label_kinds.append("群")
label = f"({platforms})" + "".join(f"({k})" for k in label_kinds)
t3 = f"{ue} {label}"
text3.append(t3)

if help_mode:
return text2, text3
else:
return text1