基于wechaty实现聊天机器人(微信自动回复)

最终效果 返回前端一个二维码,扫码登录后,机器人将上线,根据后端node内代码实现自动回复等功能

初始化项目

npm init -y

安装 wechaty 核心包

npm i wechaty  wechaty-puppet  wechaty-puppet-padlocal

安装 qrcode-terminal 用于终端输出二维码

npm i qrcode-terminal

安装 express 实现接口

npm i express

创建bot.js 实现机器人

  • 注意 注释掉的 PuppetPadlocal 是可以传token的 申请地址http://pad-local.com/ 免费的7天
    这里注释掉是 需要登录的微信是17年之前注册的才行
const {
  dingDongBot,
  getMessagePayload,
  LOGPRE,
} = require("./helper");
const { log, ScanStatus, WechatyBuilder } = require("wechaty");

//const { PuppetPadlocal } = require("wechaty-puppet-padlocal");

/****************************************
 * 去掉注释,可以完全打开调试日志
 ****************************************/
// log.level("silly");

// const puppet = new PuppetPadlocal({
//   token: "自己申请的token",
// });

async function runBot() {
  return new Promise((resolve, reject) => {
    const bot = WechatyBuilder.build({
      name: "叮当猫机器",
      //puppet
    });

    bot.start().then(() => {
      log.info(LOGPRE, "机器开始启动.");
    });
    bot
      .on("scan", (qrcode, status) => {
        if (status === ScanStatus.Waiting && qrcode) {
          console.log('qrcode',qrcode)
          const qrcodeImageUrl = [
            "https://wechaty.js.org/qrcode/",
            encodeURIComponent(qrcode),
          ].join("");
          resolve(qrcode)
          log.info(
            LOGPRE,
            `扫码: ${ScanStatus[status]}(${status}) - ${qrcodeImageUrl}`
          );

          require("qrcode-terminal").generate(qrcode, { small: true });
        } else {
          log.info(LOGPRE, `扫码状态: ${ScanStatus[status]}(${status})`);
        }
      })

      .on("login", (user) => {
        log.info(LOGPRE, `${user} 登录成功`);
      })

      .on("logout", (user, reason) => {
        log.info(LOGPRE, `${user} 登出, 原因: ${reason}`);
      })

      .on("message", async (message) => {
        log.info(LOGPRE, `收到消息: ${message.toString()}`);

        await getMessagePayload(message);

        await dingDongBot(message);
      })

      .on("room-invite", async (roomInvitation) => {
        //处理邀请加入群聊
        log.info(LOGPRE, `on room-invite: ${roomInvitation}`);
      })

      .on("room-join", (room, inviteeList, inviter, date) => {
        //当有新成员加入一个群聊时,Wechaty会触发room-join事件
        log.info(
          LOGPRE,
          `新成员加入群聊, room:${room}, inviteeList:${inviteeList}, inviter:${inviter}, date:${date}`
        );
      })

      .on("room-leave", (room, leaverList, remover, date) => {
        //当有成员离开一个群聊时,Wechaty会触发room-leave事件
        log.info(
          LOGPRE,
          `有成员离开群聊, room:${room}, leaverList:${leaverList}, remover:${remover}, date:${date}`
        );
      })

      .on("room-topic", (room, newTopic, oldTopic, changer, date) => {
        //当一个群聊的名称发生变更时
        log.info(
          LOGPRE,
          `群聊的名称发生变更, room:${room}, newTopic:${newTopic}, oldTopic:${oldTopic}, changer:${changer}, date:${date}`
        );
      })

      .on("friendship", async (friendship) => {
        //friendship事件用于处理好友添加请求和确认的事件
        log.info(LOGPRE, `on friendship: ${friendship}`);
        /* if (friendship.type() === bot.Friendship.Type.Receive) {
        // 收到好友添加请求
        await friendship.accept();
        console.log(`接受了来自 ${friendship.contact().name()} 的好友添加请求`);
      } else if (friendship.type() === bot.Friendship.Type.Confirm) {
        // 好友添加请求已确认
        console.log(`已成为好友:${friendship.contact().name()}`);
      } */
      })

      .on("error", (error) => {
        log.error(LOGPRE, `程序产生错误: ${error}`);
      });
  });
}

module.exports = {
  runBot,
};

创建辅助的工具helper.js

const { log, Message } = require("wechaty");
const PUPPET = require("wechaty-puppet");
const dayjs = require("dayjs");
const fs = require("fs");

const LOGPRE = "[终端打印日志]";

async function getMessagePayload(message) {
  switch (message.type()) {
    case PUPPET.types.Message.Text:
      log.silly(LOGPRE, `get message text: ${message.text()}`);
      break;

    case PUPPET.types.Message.Attachment:
    case PUPPET.types.Message.Audio: {
      const attachFile = await message.toFileBox();

      const dataBuffer = await attachFile.toBuffer();

      log.info(LOGPRE, `get message audio or attach: ${dataBuffer.length}`);

      break;
    }

    case PUPPET.types.Message.Video: {
      const videoFile = await message.toFileBox();

      const videoData = await videoFile.toBuffer();

      log.info(LOGPRE, `get message video: ${videoData.length}`);

      break;
    }

    case PUPPET.types.Message.Emoticon: {
      const emotionFile = await message.toFileBox();

      const emotionJSON = emotionFile.toJSON();
      log.info(
        LOGPRE,
        `get message emotion json: ${JSON.stringify(emotionJSON)}`
      );

      const emotionBuffer = await emotionFile.toBuffer();

      log.info(LOGPRE, `get message emotion: ${emotionBuffer.length}`);

      break;
    }

    case PUPPET.types.Message.Image: {
      const messageImage = await message.toImage();

      const thumbImage = await messageImage.thumbnail();
      const thumbImageData = await thumbImage.toBuffer();

      log.info(LOGPRE, `get message image, thumb: ${thumbImageData.length}`);

      const hdImage = await messageImage.hd();
      const hdImageData = await hdImage.toBuffer();

      log.info(LOGPRE, `get message image, hd: ${hdImageData.length}`);

      const artworkImage = await messageImage.artwork();
      const artworkImageData = await artworkImage.toBuffer();

      log.info(
        LOGPRE,
        `get message image, artwork: ${artworkImageData.length}`
      );

      break;
    }

    case PUPPET.types.Message.Url: {
      const urlLink = await message.toUrlLink();
      log.info(LOGPRE, `get message url: ${JSON.stringify(urlLink)}`);

      const urlThumbImage = await message.toFileBox();
      const urlThumbImageData = await urlThumbImage.toBuffer();

      log.info(LOGPRE, `get message url thumb: ${urlThumbImageData.length}`);

      break;
    }

    case PUPPET.types.Message.MiniProgram: {
      const miniProgram = await message.toMiniProgram();

      log.info(LOGPRE, `MiniProgramPayload: ${JSON.stringify(miniProgram)}`);

      break;
    }
  }
}

async function dingDongBot(message) {
  if (message.to()?.self() && message.text().indexOf("ding") !== -1) {
    await message.talker().say(message.text().replace("ding", "dong"));
  }
}


module.exports = {
  dingDongBot,
  getMessagePayload,
  LOGPRE,
};

实现入口文件 app.js

const { LOGPRE } = require("./helper");
const { runBot } = require("./bot");
const express = require("express");
const app = express();
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  next();
});
let qrcode = "";
// 返回登录二维码的接口
app.get("/qrcode", (req, res) => {
  if (qrcode) {
    // 返回二维码地址给前端
    res.json({ qrcode });
  } else {
    res.status(404).json({ error: "QR Code not found" });
  }
});

app.listen(3000, async () => {
  console.log(LOGPRE, "http://localhost:3000/qrcode");
  qrcode = (await runBot()) || "";
});

启动项目

node app.js

最终目录结构

在这里插入图片描述
效果:
在这里插入图片描述
前端访问效果
在这里插入图片描述
前端就是拿到接口返回的url,使用QRCode插件进行生成二维码即可

前端生成二维码

插件地址 https://www.npmjs.com/package/qrcode
vue示例

<template>
  <div>
    <canvas id="canvas"></canvas>
  </div>
</template>

<script>
import QRCode from "qrcode";
import axios from "axios";
export default {
  name: "QRCode",
  mounted() {
    this.getQr();
  },
  methods: {
    getQr() {
      axios("http://localhost:3000/qrcode").then((res) => {
        console.log(res, "res");
        const canvas = document.getElementById("canvas");
        QRCode.toCanvas(canvas, res.data.qrcode, function (error) {
          if (error) console.error(error);
          console.log("success!");
        });
      });
    },
  },
};
</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值