微信小秘书(小助手)

4,052 阅读4分钟

微信小助手/小秘书 基于wechaty-puppet-padplus

需求


看到别人有微信机器人, 自己也想拥有一个,那就开发一个。 主要功能

  • 自动通过好友验证

    当有人添加机器人时,判断验证消息关键字后通过或直接通过

    通过验证后自动回复并介绍机器人功能

  • 私聊关键字回复

    例如回复 加群 推送群列表

    回复 群名 推送群聊邀请,

  • 自动聊天

    群聊中通过 @[机器人]xxx 或以娜美 开头 就可以和机器人聊天

    私聊发送消息即可聊天

  • 加入群聊自动欢迎

    当新的小伙伴加入群聊后自动 @[新的小伙伴] 发一个文字欢迎

开源项目 wechaty-puppet-padplus

wechaty-puppet-padplus 同是 wechaty 团队基于 Node.js 开发,不同于 wechaty 基于微信 web 端,它是基于 iPad 协议。

对于不能使用网页版微信的用户非常友好。

  1. 使用这个包需要 Token
  2. 可以将JuziBOT Inc的工作人员(微信编号:botorange_yeah )添加为微信好友。添加后,您将收到一份审查表。如果您通过审查并愿意在Wechaty中写博客,则可以免费使用iPad协议(为期15天的免费Token)!
  3. 想要获取长期有效的免费token,那就参加所谓的开源激励计划,就是在15天后,需要提交一个MVP(最小可行化产品)的Github仓库,Wechaty会将其fork到社区中的同时,会提供一个长期免费Token。

说干就干


先上 源码

建项目装依赖

mkdir nami  // 创建 nami 文件夹

cd nami

npm init -y

核心包

npm i wechaty wechaty-puppet-padplus

windows 下安装 wechaty-puppet-padplus 出错,如让配置 python 环境变量 或 找不到 Visual Studio 时。

可通过 admin 权限 打开 powershell 执行

npm i --global --production windows-build-tools

然后切换 node 版本 10.x 再次 执行

npm i wechaty-puppet-padplus

还需要用到qrcode-terminal这个包,作用就是将二维码输出在终端来供我们扫码登录

npm install qrcode-terminal

官方文档上手

配置文件

所谓的配置文件就是一些常量。后期可以通过添加后台管理系统, 动态修改。

config.js

/*
 * @Author: C
 * @Date: 2020-03-08 16:31:25
 * @Description: 配置项
 */

module.exports = {
  // puppet_padplus Token
  token: "puppet_padplus_your_token",  // 换上你自己的 token
  // 机器人名字
  name: "Nami",
  // 房间/群聊
  room: {
    // 管理群组列表
    roomList: {
      // 群名(用于展示,最好是群名,可随意) : 群id(这个可不能随意)
      前端真有趣: "群id" // 先提前运行然后看群id
    },
    // 加入房间回复
    roomJoinReply: `\n 你好,欢迎你的加入,请自觉遵守群规则,文明交流,最后,请向大家介绍你自己!`
  },
  // 私人
  personal: {
    // 好友验证自动通过关键字
    addFriendKeywords: ["加群", "前端"],
    // 是否开启加群
    addRoom: true
  },
  task: {
    taskName: '发送新闻',
    roomId: '',
    url: 'http://api.tianapi.com/internet/index?key=apikey&num=10',
    time: '8:0:0', // /h/m/s
    date: ''
  }
}

入口 index.js

/*
 * @Author: C
 * @Date: 2020-03-08 16:31:25
 * @Description: wechaty-puppet-padplus入口程序
 */

const { Wechaty } = require("wechaty") // Wechaty核心包
const { PuppetPadplus } = require("wechaty-puppet-padplus") // padplus协议包
const config = require("./config") // 配置文件

const onScan = require("./onScan") // 机器人需要扫描二维码时监听回调
const onRoomJoin = require("./onRoomJoin") // 加入房间监听回调
const onMessage = require("./message/index") // 消息监听回调
const onFriendShip = require("./onFriendShip") // 好友添加监听回调

// 初始化
const bot = new Wechaty({
  puppet: new PuppetPadplus({
    token: config.token
  }),
  name: config.name
})
// 接下来一段链式调用,监听,启动
bot
  .on("scan", onScan) // 机器人需要扫描二维码时监听
  .on("room-join", onRoomJoin) // 加入房间监听
  .on("message", onMessage(bot)) // 消息监听 // 有些消息需要用到 wechaty 实例所以传入 bot
  .on("friendship", onFriendShip) // 好友添加监听
  .start()

message

逻辑比较多的就是 message 部分了,消息监听回调

首先对接聊天接口

免费接口文档

安装依赖

npm install --save request
npm install --save urlencode
// node-request请求模块包
const request = require("request")
// 请求参数解码
const urlencode = require("urlencode")

/**
 * @description 机器人请求接口 处理函数
 * @param {String} info 发送文字
 * @return {Promise} 相应内容
 */
function requestRobot(info) {
  return new Promise((resolve, reject) => {
    let url = `https://open.drea.cc/bbsapi/chat/get?keyWord=${urlencode(info)}`
    request(url, (error, response, body) => {
      if (!error && response.statusCode == 200) {
        let res = JSON.parse(body)
        if (res.isSuccess) {
          let send = res.data.reply
          // 免费的接口,所以需要把机器人名字替换成为自己设置的机器人名字
          send = send.replace(/Smile/g, name)
          resolve(send)
        } else {
          if (res.code == 1010) {
            resolve("老艾特我干啥,有姑娘让我约吗")
          } else {
            resolve("你说说说的什么,我怎么不知道")
          }
        }
      } else {
        resolve("你在说什么,我脑子有点短路诶!")
      }
    })
  })
}
const { Message } = require("wechaty")
// 配置文件
const config = require("./config")
// 机器人名字
const name = config.name
// 管理群组列表
const roomList = config.room.roomList

// 消息监听回调
module.exports = bot => {
  return async function onMessage(msg) {
    // 判断消息来自自己,直接return
    if (msg.self()) return

    // 判断此消息类型是否为文本
    if (msg.type() == Message.Type.Text) {
      // 判断消息类型来自群聊
      if (msg.room()) {
        // 获取群聊
        const room = await msg.room()

        // 收到消息,提到自己
        if (await msg.mentionSelf()) {
          // 获取提到自己的名字
          let self = await msg.to()
          self = "@" + self.name()
          // 获取消息内容,拿到整个消息文本,去掉 @+名字
          let sendText = msg.text().replace(self, "")
          // 请求机器人接口回复
          let res = await requestRobot(sendText)
          // 返回消息,并@来自人
          room.say(res, msg.from())
          return
        }

        // 收到消息,没有提到自己  忽略
      } else {
        // 回复信息是关键字 “加群”
        if (await isAddRoom(msg)) return
        // 回复信息是所管理的群聊名
        if (await isRoomName(bot, msg)) return
        // 请求机器人聊天接口
        let res = await requestRobot(msg.text())
        // 返回聊天接口内容
        await msg.say(res)
      }
    } else {
      console.log("消息不是文本!")
    }
  }
}

/**
 * @description 回复信息是关键字 “加群” 处理函数
 * @param {Object} msg 消息对象
 * @return {Promise} true-是 false-不是
 */
async function isAddRoom(msg) {
  // 关键字 加群 处理
  if (msg.text() == "加群") {
    let roomListName = Object.keys(roomList)
    let info = `${name}当前管理群聊有${roomListName.length}个,回复群聊名即可加入哦\n\n`
    roomListName.map(v => {
      info += "【" + v + "】" + "\n"
    })
    msg.say(info)
    return true
  }
  return false
}

/**
 * @description 回复信息是所管理的群聊名 处理函数
 * @param {Object} bot 实例对象
 * @param {Object} msg 消息对象
 * @return {Promise} true-是群聊 false-不是群聊
 */
async function isRoomName(bot, msg) {
  // 回复信息为管理的群聊名
  if (Object.keys(roomList).some(v => v == msg.text())) {
    // 通过群聊id获取到该群聊实例
    const room = await bot.Room.find({ id: roomList[msg.text()] })

    // 判断是否在房间中 在-提示并结束
    if (await room.has(msg.from())) {
      await msg.say("您已经在房间中了")
      return true
    }

    // 发送群邀请
    await room.add(msg.from())
    await msg.say("已发送群邀请")
    return true
  }
  return false
}

然后就可以本地启动试试了