规则(options)

使用 webot.setwebot.wait 等方法时,会自动新建一条 rule , rule 定义的具体可用参数如下:

options.name

为规则命名,方便使用 webot.get 获取规则。

options.pattern

消息匹配规则,用以判断是否对用户发送的消息进行回复。如果为正则表达式和字符串, 则只匹配用户发送的文本消息(也就是 info.text !== undefined 的消息)。

所有支持的格式:

  • {String} 如果是潜在的 RegExp (如字符串 '/abc/igm' ),会被转为 RegExp,如果以 '=' 打头,则完全匹配,否则模糊匹配
  • {RegExp} 正则表达式,匹配到的捕获组会被赋予 info.param ,可通过 info.param[1], info.param[2].. 获取
  • {Function} 该函数只接受一个参数 info ,返回布尔值
  • {NULL} 不指定 pattern ,则视为通过匹配,此 Rule 的 handler 将总是会执行

示例:

// 匹配下列所有消息:
//
//    你是机器人吗
//    难道你是机器人?
//    你是不是机器人?
//    ...
//
webot.set('Blur match', {
  pattern: '是机器人',
  handler: '是的,我就是一名光荣的机器人'
});

// 当字符串 pattern 以 "=" 开头时,则会完全匹配
webot.set('Exact match', {
  pattern: '=a',
  handler: '只有回复「a」时才会看到本消息'
});

// 利用正则来匹配
webot.set('your name', {
  pattern: /^(?:my name is|i am|我(?:的名字)?(?:是|叫)?)\s*(.*)$/i,
  handler: function(info) {
    return '你好,' + info.param[1];
  },
  // 或者直接返回字符串,webot 会自动替换匹配关键字
  // handler: '你好,{1}'
});

// 类正则的字符串会被还原为正则
webot.set('/(good\s*)morning/i', '早上好,先生');

// 可以接受 function
webot.set('pattern as fn', {
  pattern: function(info){
    return info.param.eventKey === 'subscribe';
  },
  handler: '你好,欢迎关注我'
});

options.handler

指定如何生成回复消息

当返回非真值(null/false)时继续执行下一个动作,否则返回值会被回复给用户。

支持的定义格式:

  • {String} 直接返回字符串
  • {Array} 从数组中随机取一个作为 handler
  • {Object} 直接返回
  • {Function} 执行函数获取返回值,第一个参数为消息请求的 info 对象

支持异步:


webot.set('search_database', {
  description: 'Search a keyword from database',
  pattern: /^(?:s\s+)(.+)$/i,
  handler: function(info, next) {
    // assert(this.name == 'search_database');
    // 函数内的 this 变量即此规则

    // 执行一个异步操作..
    query_from_database(info.text, function(err, ret) {
      if (err) return next(500);
      return next(null, ret);
    });
  }
});

在函数执行过程中,如果设置 info.ended = true ,即使没有返回可用的回复,也不会再继续下一条规则。 此时会 fallback 到预设的 404 错误,参见 webot.codeReplies

注意

你是否注意到,handler 允许异步操作,而 pattern 却不可以?

事实上,所有的 pattern 操作,都可以放到 handler 里执行:

webot.set('test_A', {
  handler: function(info, next) {
    if (info.text == 'A') {
      next(null, 'You said A.');
    }
    next();
  }
});

或者更省略一点:

webot.set(function test_A(info) {
  if (info.text == 'A') {
    return 'You said A.';
  }
});

所以,异步的匹配可以写成:

webot.set('test', {
  handler: function(info, next) {
    var uid = info.uid;
    User.findOne(uid, function(err, doc) {
      if (!doc) {
        // 异步判断失败,进入下一条规则
        return next();
      }
      // 判断成功后需要执行的操作在这里
      return next(null, '欢迎你,' + doc.name);
    });
  }
});

相信你并不会太需要在匹配消息规则时也进行异步。 事实上,很多需求都可以转化为使用 webot.beforeReply

options.replies

指定如何再次回复用户的回复。即用户回复了根据当前规则回复的消息后,如何继续对话。必须先配置 session支持

webot.set('guess my sex', {
  pattern: /是男.还是女.|你.*男的女的/,
  handler: '你猜猜看呐',
  replies: {
    '/女|girl/i': '人家才不是女人呢',
    '/男|boy/i': '是的,我就是翩翩公子一枚',
    'both|不男不女': '你丫才不男不女呢',
    '不猜': '好的,再见',
    '/.*/': function(info) {
      // 在 replies 的 handler 里可以获得等待回复的重试次数参数
      if (info.rewaitCount < 2) {
        info.rewait();
        return '你到底还猜不猜嘛!';
      }
      return '看来你真的不想猜啊';
    },
  }

也可以用一个函数搞定:

  replies: function(info){
    return '嘻嘻,不告诉你'
  }

也可以是数组格式,每个元素为一条rule

  replies: [{
    pattern: '/^g(irl)?\\??$/i',
    handler: '猜错'
  },{
    pattern: '/^b(oy)?\\??$/i',
    handler: '猜对了'
  },{
    pattern: 'both',
    handler: '对你无语...'
  }]
});