Koishi插件开发入门指南(三)

在上一节当中,我们介绍了中间件和指令系统的基本使用,那么我们接下来需要更进一步地了解指令系统。

​ 下面来看一下一个最近非常火爆的插件中的一个指令:

chatgpt -r

​ 这条指令是Koishi-ChatGPT插件中重置上下文的指令。你可能会好奇,这个-r参数是怎么实现的?在koishi中,这种-X形式的参数我们称之为“选项”,对于上面这个例子,我们实现的选项是“-r

// 其他配置项
export function apply(ctx:Context){
  ctx.command('chatgpt <input:text>')
    .option('reset', '-r')
    .action(async ({ options, session }, input) => {
      if (options?.reset) {
        //处理删除逻辑
        return '重置上下文成功!'
      }
      return "这里是机器人返回的信息";
  })
}

​ 紧接着我们保存并自动重载,当我们使用chatgpt -r指令或者chatgpt --reset之后,机器人回复了一句"重置上下文成功!“,而当我们不加任何参数的时候,机器人回复的是"这里是机器人返回的信息”。

​ Koishi的命令系统还包含一些高级选项,例如设置命令的描述,或者使用authority用于指定权限等级,这些部分的具体用法需要你参照Koishi的文档,下面是一些例子:

ctx.command("管理命令",{authority:5}) // 限制命令使用权限
ctx.command("pull","这个命令的描述") // 限制命令使用权限
ctx.command("汴京","和群友汴京",{authority:2}) // 限制命令使用权限,并给一些选项

​ 如果你还想更深入了解指令系统的相关内容,你可以参阅Koishi的官方文档https://koishi.chat/guide/command/index.html

​ 现在,让我们开始写一个带有监测违规内容的复读姬吧!这个复读姬设计有一个中间件,负责过滤发给机器人的词中不包含违禁词;以及一个命令,用于临时增加违禁词列表,那么,开始啦!

​ 首先,我们再次输入第一课所说的那个指令(yarn new/npm run new),插件名称你可以自己想,本例中采用“repeater”作为插件名称

$ yarn new
yarn run v1.22.19
> koishi-scripts new
√ plugin name: ... repeater
√ description: ... A repeater machine.

​ 然后按照第一课所说,设置好koishi.yml,接着在控制台中输入yarn dev启动开发服务器。接着我们开始编写index.ts文件

​ 在index.ts文件中,我们需要写一个中间件(用于拦截任何有违规内容的消息)、两个命令(拦截系统、复读系统),下面是一个完整的例子:

import { Context, Schema } from 'koishi'

export const name = 'repeater'

export interface Config {}

export const Config: Schema<Config> = Schema.object({})

export function apply(ctx: Context) {
  const illegalWords = ['预设的一些黑名单词汇','fxxk','sb'];
  ctx.middleware((session,next)=>{
    for(let i in illegalWords){
      if(session.content.includes(illegalWords[i]))
        return '群主!这里有人发违规词汇了!快来处理叭!';
    }
    return next();
  })

  ctx.command("拉黑 <word:string>","拉黑某个词汇")
    .action((argv,word)=>{
      illegalWords.push(word)
    })

  ctx.command("复读 <word:text>","复读一句话")
    .action((argv,text)=>{
        return text;
    })

}

​ 上述代码使用中间件在处理消息时,检查是否包含黑名单词汇。如果包含,则返回固定的提示语;否则,继续处理消息。实现了两个命令:一个名为 “拉黑” 的命令,用于将某个词汇添加到黑名单中。一个名为 “复读” 的命令,用于将输入的一句话作为回复返回给用户。

​ 但是,眼尖的小伙伴可能会发现,上述代码并没有对数据进行持久化处理,所以配置的违禁词列表在下一次重启之后就会消失,而且配置违禁词需要和机器人交互。那有人会提出疑问,那我怎么实现一个存储在配置文件,可以在Web控制台中修改的配置呢?这就是我们今天的主角----配置系统

​ 首先,配置系统里的主角,也是我们今天要介绍的,是Schema。何谓Schema?Schema是"模式验证器"的意思。用大白话理解Schema,就是你可以规定传入的数据以什么样的格式和类型传入。因此它可以被用于检测配置。我们来看一个例子:

export interface Config {
    interval:number
    content:string
}

export const Config: Schema<Config> = Schema.object({
    interval:Schema.number(),
    content:Schema.string()
})

​ 这里定义了一个number型的配置项,名为interval、和一个string型的配置项,名为content,此时你可以在该插件对应的配置中加入interval属性(你可以修改koishi.yml,也可以在WebUI中进行操作)。例如下面这个例子(我们假设这个插件的名字是scheduled-notice),那么我可以以下面这个配置文件初始化它:

plugins:
	scheduled-notice:
		interval: 3600
		content: "大家好,我是本群的提醒睡觉小助手,希望此刻看见消息的人可以和我一样,盖好被子,小心着凉,过会我会继续提醒大家及时睡觉,和我一起成为一天睡24小时的five吧!"

​ 上述这个配置文件就是符合之前的Schema定义的配置,但如果我们将interval中的值改为一个字符串"两年半",则会引发koishi弹出一下面这段提示:

2022-12-17 15:54:34 [W] app TypeError: expected number but got 两年半

​ 这就代表着Koishi正确检测到了配置的错误并弹出了错误提示。

​ 但有人突然想,我如果想要允许配置项里传入不同的类型怎么办?诶,koishi提供了一种特殊的Schema元素: union。我们修改一下上述代码,让他变成这样:

export interface Config {
  interval:number|string
  content:string
}

export const Config: Schema<Config> = Schema.object({
  interval:Schema.union([
    Schema.number(),
    Schema.string()
  ]),
  content:Schema.string()
})

​ 然后我们配置文件就可以增加interval的传入类型:

plugins:
	scheduled-notice:
		interval: "16:00"
		content: "喂!三点几嚟,做撚啊做,饮茶先啦,做咁多都冇用嘅!"

​ (注:Schema不会自动帮你处理类型,它只负责检查,所以具体的类型分类处理逻辑需要自己编写)

​ 现在,我们可以向古老的apply中添加一个参数config,也即是变成下面这样:

export function apply(ctx: Context,config:Config) {
// ... 你的代码...
}

​ 接着,我们就能在config中接收到配置文件了。现在,我们修改一下之前的代码,变成这个样子:

import { Context, Schema } from 'koishi'

export const name = 'repeater'

export interface Config {
  illegalWords:string[]
}

export const Config: Schema<Config> = Schema.object({
  illegalWords:Schema.array(Schema.string())
})

export function apply(ctx: Context,config:Config) {
  ctx.middleware((session,next)=>{
    for(let i in config.illegalWords){
      if(session.content.includes(config.illegalWords[i]))
        return '主人!这里有人发违规词汇了!快来处理叭!';
    }
    return next();
  })
  ctx.command("复读 <word:text>","复读一句话")
    .action((argv,text)=>{
        return text;
    })
}

​ 然后我们就可以在熟悉的WebUI或者koishi.yml中配置违禁词了:

4 个赞