精华内容
下载资源
问答
  • java-wechaty-getting-started 开箱即用的Java Wechaty Starter Project模板 连接聊天机器人 Wechaty是用于微信个人帐户的RPA SDK,可以帮助您使用6行Java创建聊天机器人。 世界上最短的Java ChatBot:6行代码 ...
  • Learn more about Wechaty Puppet Services from You can use Wechaty with other puppet services like WXWork, Rock, PadLocal, etc as well. 通知 (Nov, 2020) 亲爱的开发者,您好! 为了更好的提供服务,...
  • “来自我们社区的新星,现在是第三次最常使用的Wechaty Puppet Provider。非常感谢@padlocal,感谢您创建了WPP和WPS!” - :star: Wechaty 引领木偶趋势: 如何使用 PadLocal是一个完整的Wechaty人偶实现,从旧人偶...
  • java-wechaty Connecting Chatbots Wechaty is a RPA SDK for Wechat Individual Account that can help you create a chatbot in 6 lines of Java. Voice of the Developers "Wechaty is a great solution, I ...
  • - 打包图片用于wechaty发送 - 操作微信 - 控制台展示二维码图片 基本思路 抓取 墨迹天气 和 [one·一个] 的数据 编写展示用的模板并自定义样式 处理抓取到的数据渲染模板 抓取模板页并截图 操作微信发送消息 定时...
  • gRPC for Wechaty Puppet Service 用法 Node.js 维护者: (Huan LI) Python 维护者: 吴京京(吴京京) 去 维护者: (丁超飞) Java Maven: < groupId>io.github.wechaty < version>0.11.25 ...
  • 作为开发人员,您可以使用Wechaty轻松构建您的机器人,有效地管理消息发送/接收,聊天室创建/邀请,联系友谊,以及在用户和您的机器人之间愉快地添加人工智能。 该存储库应该是开箱即用的,并且是Wechaty初学者的...
  • 为了实现在微信上实现同等功能,便开始在github上寻找微信机器人,直到看到Wechaty解决方案,它是适用于微信个人及企业微信的BotSDK,提供微信机器人完美解决方案。 Wechaty 是适用于微信个人帐户的Bot SDK,可以...
  • wechaty.js.org 是官方的Wechaty网站,用于发布来自开源社区的最新新闻,博客文章和文档。 如何发布博客 叉它 创建您的Blog分支(git checkout -b your-blog) 用markdown写博客 将您的博客添加到jekyll/_post...
  • Wechaty Web Panel Wechaty Web Panel 插件,让你的 wechaty 机器人快速接入 web 控制面板 面板主要功能 微信每日说,定时给女朋友发送每日天气提醒,以及每日一句 定时提醒 当天定时提醒 例:"提醒 我 18:00 下班...
  • "Wechaty is a great solution, I believe there would be much more users recognize it." — @Gcaufy, Tencent Engineer, Author of "太好用,好用的想哭" — @xinbenlv, Google Engineer, Founder of HaoShiYou...
  • dotnet-wechaty (.NET Wechaty) dotnet-wechaty (.NET Wechaty) is a Conversational SDK for chatbot makers written in C# Connecting Chatbots Wechaty is a RPA SDK for Wechat Individual Account that can ...
  • go-wechaty Connecting Chatbots Wechaty is a RPA SDK for Wechat Individual Account that can help you create a chatbot in 6 lines of Go. Voice of the Developers "Wechaty is a great solution, I believe ...
  • 让我想到了Node 下的Wechaty,之前曾用其做消息转发,这次随手拿来玩一玩,此处采用Node来实现好友头像拼接这一效果。 PS: 虽然拼接好友头像后并没什么意义,然而这个想法很有意思,自己玩一玩还是不错的,顺便可以...
  • 该存储库是Wechaty的子模块。 参见: : 移到此处的源代码可以在Wechaty存储库中找到: 已知限制 2017年后注册的微信账号无法登录Web微信,因此无法将PuppetWeChat与微信一起使用。 请确保您的微信帐户可以访问进行...
  • wechaty-robot 基于 wechaty-puppet-padplus 协议的微信机器人助手,适用于微信好友管理及群管理,可以帮你省去一系列重复繁琐的操作。 wechaty-puppet-padplus协议于2020年已停用,更换协议为wechaty-puppet-...
  • Wechaty Framework的P提供程序的Abstract(Base)类。 该模块是 Framework SDK的一部分。 了解更多信息: Wiki: : 问题: : 文献资料 可以在...
  • 微信机器人秘书 使用须知 本项目适用网页版微信登录不成功的用户, 该项目是使用微信ipad协议开发。 使用本项目前需要先申请token, 具体操作流程请参考 初衷 前段时间发现微信群里有人天天准时准点的在发咨询或者消息...
  • WECHATY-木偶-WECHAT4U 微信微信公众号 请参阅: 关于WECHAT4U 是一个出色的微信bot框架,支持Node.js和浏览器,具有丰富的功能和活跃的经验丰富的贡献者社区。 已知限制 2017年之后迁移的微信账号无法登录Web微信...
  • java-wechaty Connecting Chatbots Wechaty is a RPA SDK for Wechat Individual Account that can help you create a chatbot in 6 lines of Java. WORK IN PROGRESS Work in progress... Please come back after 4...
  • wechaty-get-start-源码

    2021-05-13 18:41:40
    连接ChatBots。 跑步 npm git clone git@github.com:TingYinHelen/wechaty-get-start.git npm install node mybot.js
  • 之前公司web组组长有个微信机器人每周催我们交周报,私信发过去会自动更新到公司内部wiki上,一度惊为天人,后来看到公共号以及掘金上突然有好多人推荐wechaty,据说是6行代码完成一个微信聊天机器人,正好老婆那边想要个...
  • wechaty-fanli 插件 基于wechaty实现的返利微信机器人,根据淘口令生成高佣转链接,并创建新的淘口令。 本项目实现功能: 淘宝优惠券查询 参考项目 根据 的 项目改造而成,本项目属于wechaty插件,可以直接配置使用...
  • wechaty-Robot 基于 wechaty-puppet-padplus 的微信机器人助手 目前实现功能 自动通过好友验证 当有人添加机器人时,判断验证消息关键字后通过或直接通过 通过验证后自动回复并介绍机器人功能 私聊关键字回复 例如...
  • wechaty, 适用于个人帐户的微信 Bot,由 TypeScript,Docker 和 WECHATY连接 CHATBOTSWechaty Wechat个人帐户include支持 cross ( osx/mac )/cross 达尔文和 Docker Bot 。 https://github.co
  • 使用Wechaty实现微信机器人操作

    千次阅读 2020-12-30 11:37:51
    wechatyWechatyWechaty token什么是wechaty token如果获取wechaty tokenWechaty 与微信Hook的区别Wechaty会不会被封号自己的一个Wechaty的开源项目 Wechaty Wechaty 按照我的理解就是一个可以实现微信机器人的多端...

    Wechaty

    Wechaty 按照我的理解就是一个可以实现微信机器人的多端协议框架。为什么说是多端呢,因为他包含了微信pc协议,web协议,pad协议等。最近他在测试企业微信这块,所以有幸申请了一个token来玩。

    Wechaty token

    什么是wechaty token

    什么是wechaty token 呢,我们来看下面代码

    const bot = new Wechaty({
      puppet: 'wechaty-puppet-hostie',
      puppetOptions: {
        'your_token_here',
      }
    });
    

    每个wechaty实例都需要一个token,换句话说,没有token什么都做不了。

    如果获取wechaty token

    方法有两个:

    1. 靠自己的劳动获取。
      1. 去官网 加这个机器人,然后回复 wechaty 进群聊。
        wechaty官方机器人
      2. 然后机器人会给叫你去填一个分享计划的申请表,提交之后,没过几天就有人找到你,然后给你一个15天的临时token这个时候就能开始玩了。原话如下:

      您确认愿意参与开源激励计划,将最终成品代码开源同时在Wechaty社区内撰写一篇博客。在wechaty(wechaty.js.org)博客审核通过后,每在一个平台(知乎/简书/掘金等)提交一篇博客,Wechaty 社区额外提供3个月有效期 Token,凭博客链接联系JuziBOT申请Token 时长。

    2. 直接用钱砸
      简单有效,不浪费时间,200/月,直接找他们客服说付费就ok

    所以,要想要token要不然花时间,要不然就花钱。再次感慨时间就是金钱哈。还是富兰克林大大高瞻远瞩啊。

    Wechaty 与微信Hook的区别

    说起wechaty,就不得不说另一种微信机器人的构建方式 - 微信hook。
    这两者算是殊途共归。只是个人感觉微信hook比较符合国人的山寨精神。
    微信hook用山寨大神们的话来说就不外乎两个词。

    1. 获取数据
    2. 创建子程序。
      我们这里主要说wechaty,所以微信hook我就一句话归纳一下,大神们用逆向的思想在计算机上找到微信每个动作的内存池,并计算偏移量,最后,找出规律,创建子程序来模拟微信的所有操作。所以微信hook有个最大的缺点,就是太依赖微信版本,也造成了其的不稳定。一旦一个版本停用,就得重新去研究。
      而wechaty完全是两码事,他是模拟的微信的协议来创建的框架,不依赖与微信版本,程序员们可以安心的写下游代码,上游协议框架api这些事就交给wechaty团队来做。

    Wechaty会不会被封号

    本身是不会封号的,但是用力太猛就说不准了,比如,你一天转发几万条消息,自动加几百个群,几千号人。。那不封你封睡呢-_-||。

    自己的一个Wechaty的开源项目

    下面呈上自己的用typescript写的一个wecahty项目,实现简单的加群,加好友,智能聊天等操作。

    – 文件目录
    |-- app.ts
    |-- config.ts
    |-- mFriendShip.ts
    |-- mMessage.ts
    |-- mRoomJoin.ts
    |-- mScan.ts
    |-- mUser.ts

    config.ts

    let config = {
        // puppet_padplus Token
        token: "your_token_here",
        // 机器人名字
        name: "疯疯",
        // 房间/群聊
        room: {
          // 管理群组列表
          roomList: {
            // 群名(用于展示,最好是群名,可随意) : 群id(这个可不能随意)
            院子: "R:1234567890",
            桌子: "R:1234567890"
          },
          // 加入房间回复
          roomJoinReply: `\n 你好,欢迎你的加入,请自觉遵守群规则,文明交流,最后,请向大家介绍你自己! \n\n Hello, welcome to join, please consciously abide by the group rules, civilized communication, finally, please introduce yourself to everyone!😊`
        },
        // 私人
        personal: {
          // 好友验证自动通过关键字
          addFriendKeywords: ["加群", "前端"],
          // 是否开启加群
          addRoom: true
        }
      }
      export default config
    

    app.ts

    import { Wechaty } from 'wechaty'
    import mRoomJoin from "./mRoomJoin"
    import mScan from "./mScan"
    import mUser from "./mUser"
    import mMessage from "./mMessage"
    import mFriendShip from "./mFriendShip"
    
    import config from "./config"
    
    const token = config.token
    
    const bot = new Wechaty({
      puppet: 'wechaty-puppet-hostie',
      puppetOptions: {
        token,
      }
    });
    
      bot
      .on("scan", mScan) // 机器人需要扫描二维码时监听
      .on('login', mUser)
      .on("room-join", mRoomJoin) // 加入房间监听
      .on("message", mMessage(bot)) // 消息监听
      .on("friendship", mFriendShip) // 好友添加监听
      .start()
    

    mFriendShip.ts

    import { Friendship } from "wechaty"
    
    // 配置文件
    import config from "./config"
    // 好友添加验证消息自动同意关键字数组
    const addFriendKeywords = config.personal.addFriendKeywords
    
    // 好友添加监听回调
    const mFriendShip = async (friendship: any) =>{
        let logMsg
        try {
          logMsg = "添加好友" + friendship.contact().name()
          console.log(logMsg)
          switch (friendship.type()) {
            /**
             * 1. 新的好友请求
             * 设置请求后,我们可以从request.hello中获得验证消息,
             * 并通过`request.accept()`接受此请求
             */
            case Friendship.Type.Receive:
              // 判断配置信息中是否存在该验证消息
              if (addFriendKeywords.some(v => v == friendship.hello())) {
                logMsg = `自动通过验证,因为验证消息是"${friendship.hello()}"`
                // 通过验证
                await friendship.accept()
              } else {
                logMsg = "不自动通过,因为验证消息是: " + friendship.hello()
              }
              break
      
            /**
             * 2. 友谊确认
             */
            case Friendship.Type.Confirm:
              logMsg = "friend ship confirmed with " + friendship.contact().name()
              break
          }
          console.log(logMsg)
        } catch (e) {
          logMsg = e.message
        }
    }
    export default mFriendShip;
    

    mMessage.ts

    import { Message } from "wechaty"
    // node-request请求模块包
    import request from "request"
    
    // 请求参数解码
    import urlencode from "urlencode"
    // 配置文件
    import config from "./config"
    
    // 机器人名字
    let {name, room} = config
    // 管理群组列表
    const roomList = room.roomList
    
    // 消息监听回调
    let bot = (bot: any) => {
      return async function mMessage(msg: any) {
        // 判断消息来自自己,直接return
        if (msg.self()) return
    
        console.log("=============================")
        console.log(`msg : ${msg}`)
        console.log(
          `from: ${msg.from() ? msg.from().name() : null}: ${
            msg.from() ? msg.from().id : null
          }`
        )
        console.log(`to: ${msg.to()}`)
        console.log(`text: ${msg.text()}`)
        console.log(`isRoom: ${msg.room()}`)
        console.log("=============================")
    
        // 判断此消息类型是否为文本
        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("消息不是文本!")
        }
      }
    }
    
    export default bot;
    
    /**
     * @description 回复信息是关键字 “加群” 处理函数
     * @param {Object} msg 消息对象
     * @return {Promise} true-是 false-不是
     */
    async function isAddRoom(msg: any) {
      // 关键字 加群 处理
      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:any, msg:any) {
      // 回复信息为管理的群聊名
      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
    }
    
    /**
     * @description 机器人请求接口 处理函数
     * @param {String} info 发送文字
     * @return {Promise} 相应内容
     */
    function requestRobot(info: string) {
      console.log("the request info is "+info)
      return new Promise((resolve, reject) => {
        let url = `http://i.itpk.cn/api.php?question=${urlencode(info)}&api_key=xxxx&api_secret=xxxx`
        //这里去这个api网站itpk.cn登录注册一个就好
        request.get(url, (error, response, body) => {
          let sendStr:string = ""
          // console.log(response)
          if (!error && response.statusCode == 200) {
              if(body.indexOf("{") == -1){ 
                sendStr = body
                resolve(sendStr)
              }else{
                let res = JSON.stringify(body)
                res = res.substr(1)
                res = res.substr(0, res.length-1)
                if (res) {
                  const reg = /\\/g
                  let send = unescape(res.replace(/\u/g, '%u')); //unicode转中文
                  send = send.replace(reg,''); //去转义,然后编辑字符串
                  send = send.replace(/rn/g,'\\r\\n');
                  send = send.trim()
                  let sendObj = JSON.parse(send)
                  if(sendObj.title){
                    sendStr = "【标题】" + "\n" + JSON.stringify(sendObj.title)+ "\n"
                  }
                  sendStr = sendStr + "【内容】" + "\n" + JSON.stringify(sendObj.content).trim().substr(1).substr(0, res.length-1)
                  console.log("the response send is "+ sendStr)
                  // 免费的接口,所以需要把机器人名字替换成为自己设置的机器人名字
                  resolve(sendStr)
              }
            } 
          }else {
              resolve("你在说什么,我脑子有点短路诶!")
            }
         })
      })
    }
    
    
    
    
    

    mRoomJoin.ts

    // 配置文件
    import config from "./config"
    
    // 加入房间回复
    const roomJoinReply = config.room.roomJoinReply
    // 管理群组列表
    const roomList = config.room.roomList
    
    // 进入房间监听回调 room-群聊 inviteeList-受邀者名单 inviter-邀请者
    const mRoomJoin = async (room: any, inviteeList:any[], inviter:any) => {
      // 判断配置项群组id数组中是否存在该群聊id
      if (Object.values(roomList).some(v => v == room.id)) {
        // let roomTopic = await room.topic()
        inviteeList.map(c => {
          // 发送消息并@
          room.say(roomJoinReply, c)
        })
      }    
    }
    
    export default mRoomJoin;
    
    

    mScan.ts

    
    import QrcodeTerminal from "qrcode-terminal"
    import { ScanStatus } from 'wechaty-puppet'
    
    const mScan = (qrcode:any, status:any) => {
        if (status === ScanStatus.Waiting) {
          QrcodeTerminal.generate(qrcode, {
            small: true
          }) 
      }
    }
    
    export default mScan;
    

    mUser.ts

    
    const mUser = async (user: any) => {
     console.log(`user: ${JSON.stringify(user)}`)
            
    }
    
    export default mUser;
    

    代码GitHub地址: wechaty_group_managment.

    展开全文
  • 基于Paddlehub与Wechaty的微信小助手–懂懂 文章目录基于Paddlehub与Wechaty的微信小助手--懂懂1.使用docker部署服务1.1 服务部署1.2 服务部署测试2.项目功能2.1 项目功能展示2.2 项目主要代码3.个人心得4.参考链接5...

    基于Paddlehub与Wechaty的微信小助手–懂懂

    1.使用docker部署服务

    购买云服务器:推荐 阿里云、腾讯云等,并安装docker
    可参考:教你用AI Studio+wechaty+阿里云白嫖一个智能微信机器人

    1.1 服务部署

    AI ChatBot 创意赛提供的是PadLocal Puppet的token,
    可参考Python Wechaty如何使用PadLocal Puppet Service进行部署服务

    docker pull wechaty/wechaty:latest
    export WECHATY_LOG="verbose"
    export WECHATY_PUPPET="wechaty-puppet-padlocal"
    export WECHATY_PUPPET_PADLOCAL_TOKEN="puppet_padlocal_26ff2f288a7942b2a2c0496215daa5c5"    # 这里输入你自己的token
    export WECHATY_PUPPET_SERVER_PORT="8080"
    export WECHATY_TOKEN="888"
    
    docker run -ti \
      --name wechaty_puppet_service_token_gateway \
      --rm \
      -e WECHATY_LOG \
      -e WECHATY_PUPPET \
      -e WECHATY_PUPPET_PADLOCAL_TOKEN \
      -e WECHATY_PUPPET_SERVER_PORT \
      -e WECHATY_TOKEN \
      -p "$WECHATY_PUPPET_SERVER_PORT:$WECHATY_PUPPET_SERVER_PORT" \
      wechaty/wechaty:latest
    

    1.2 服务部署测试

    测试地址:https://api.chatie.io/v0/hosties/888
    这里的888对应上面docker部署里面的WECHATY_TOKEN

    如果返回了服务器的ip地址以及端口号,比如{“ip”:“81.69.14.9”,“port”:8080},就说明运行成功了

    如果返回的是{“ip”:“0.0.0.0”,“port”:0},就说明没有运行成功

    2.项目功能

    项目主要功能:

    1.收到’ding’,自动回复

    2.收到’帮助’,自动回复

    3.收到’小程序’or’微信小程序’,自动回复

    4.收到’情话@your_content’,自动回复,例如 情话@春天

    5.收到’藏头诗@your_content’,自动回复,例如 藏头诗@我喜欢你

    6.收到’city+天气’,自动回复,例如 长沙天气

    7.收到其他关键词,智能回复,例如 你叫什么名字呀

    b站演示视频地址:https://www.bilibili.com/video/BV1vV411E7Bv/

    基于Paddlehub与Wechaty的微信小助手--懂懂

    2.1 项目功能展示

    2.2 项目主要代码

    配置文件代码

    config_list ={
        'contact_name':'lei',
        'room_id':'7501001119@chatroom',
    
    }
    ACCEPTFRIEND=['PaddleHub', 'Wechaty', '懂懂']
    
    # 导入第三方库
    import os
    from wechaty import (
        Contact,
        FileBox,
        Message,
        ScanStatus,
        Wechaty,
        Friendship,
        FriendshipType
    )
    import asyncio
    from config import config_list
    import config
    from typing import Optional
    import paddlehub as hub
    import json, requests
    import hashlib
    import time
    import random
    import string
    from urllib.parse import quote
    
    # Paddlehub文本模型
    text_model1 = hub.Module(name='ernie_gen_lover_words')     # 情话模型
    text_model2 = hub.Module(name="ernie_gen_acrostic_poetry", line=4, word=7)   # 藏头诗模型
    
    
    # 获取城市天气
    def get_weather_data(city_name):
        weatherJsonUrl = "http://wthrcdn.etouch.cn/weather_mini?city={}".format(city_name)  # 将链接定义为一个字符串
        response = requests.get(weatherJsonUrl)  # 获取并下载页面,其内容会保存在respons.text成员变量里面
        response.raise_for_status()  # 这句代码的意思如果请求失败的话就会抛出异常,请求正常就上面也不会做
        # 将json文件格式导入成python的格式
        weather_dict = json.loads(response.text)
        # print(weather_dict)
        if weather_dict['desc'] == 'invilad-citykey':
            weather_info = '请输入正确的城市名!'
        else:
            forecast = weather_dict.get('data').get('forecast')
            city = '城市:' + weather_dict.get('data').get('city') + '\n'
            date = '日期:' + forecast[0].get('date') + '\n'
            type = '天气:' + forecast[0].get('type') + '\n'
            wendu = '温度:' + weather_dict.get('data').get('wendu') + '℃ ' + '\n'
            high = '高温:' + forecast[0].get('high') + '\n'
            low = '低温:' + forecast[0].get('low') + '\n'
            ganmao = '感冒提示:' + weather_dict.get('data').get('ganmao') + '\n'
            fengxiang = '风向:' + forecast[0].get('fengxiang')
            weather_info = city + date + type + wendu + high + low + ganmao + fengxiang
        return weather_info
    
    
    def curlmd5(src):
        m = hashlib.md5(src.encode('UTF-8'))
        # 将得到的MD5值所有字符转换成大写
        return m.hexdigest().upper()
    
    
    def get_params(plus_item):
        global params
        # 请求时间戳(秒级),用于防止请求重放(保证签名5分钟有效)
        t = time.time()
        time_stamp = str(int(t))
        # 请求随机字符串,用于保证签名不可预测
        nonce_str = ''.join(random.sample(string.ascii_letters + string.digits, 10))
        # 应用标志,这里修改成自己的id和key
        # 注册地址:https://ai.qq.com/product/nlpchat.shtml
        app_id = '2171755636'    # your appid
        app_key = 'HYFEyQEF5U3Zkbjo'   # your app_key
        params = {'app_id': app_id,
                  'question': plus_item,
                  'time_stamp': time_stamp,
                  'nonce_str': nonce_str,
                  'session': '10000'
                  }
        sign_before = ''
        # 要对key排序再拼接
        for key in sorted(params):
            # 键值拼接过程value部分需要URL编码,URL编码算法用大写字母,例如%E8。quote默认大写。
            sign_before += '{}={}&'.format(key, quote(params[key], safe=''))
        # 将应用密钥以app_key为键名,拼接到字符串sign_before末尾
        sign_before += 'app_key={}'.format(app_key)
        # 对字符串sign_before进行MD5运算,得到接口请求签名
        sign = curlmd5(sign_before)
        params['sign'] = sign
        return params
    
    def get_content(plus_item):
        global payload, r
        # 聊天的API地址
        url = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat"
        # 获取请求参数
        plus_item = plus_item.encode('utf-8')
        payload = get_params(plus_item)
        r = requests.post(url, data=payload)
        res = r.json()["data"]["answer"]
        if len(res) == 0:
            res = '请换个问题!'
        return res
    
    # 文本消息处理--机器对话
    def chat_bot(content, mode):
        res = ''
        if mode == '0':
            res = get_content(content)
            # print(res)
        elif mode == '1':
            res = text_model1.generate(texts=[content], use_gpu=False, beam_width=1)
            if res is None:
                return
            res = res[0][0]
            # print(res)
        elif mode == '2':
            res = text_model2.generate(texts=[content], use_gpu=False, beam_width=1)
            if res is None:
                return
            res = res[0][0]
        return res
    
    # debug时分割线
    def dividing_line(info='分割线'):
        print('-' * 30 + info + '-' * 30)
    
    
    # 发送文本消息给联系人
    async def sendTextMsgToContact(contact, text):
        if not contact:  # 好友不存在直接返回
            return
        await contact.say(text)  # 调用contact对象的say方法发送消息,contact对象很多方法,参考官方文档
    
    
    # 发送媒体消息给联系人
    async def sendMediaMsgToContact(contact, fileUrl, filePath):
        # print(contact)
        if not contact:  # 好友不存在直接返回
            return
        if fileUrl:
            fileBox1 = FileBox.from_url(url=fileUrl, name='wxapplet.png')
            await contact.say(fileBox1)
        if filePath:
            fileBox2 = FileBox.from_file(filePath)
            await contact.say(fileBox2)
    
    # 定义懂懂机器人类
    class MyBot(Wechaty):
        """
        listen wechaty event with inherited functions, which is more friendly for
        oop developer
        """
    
        def __init__(self):
            super().__init__()
    
        async def on_message(self, msg: Message):
            """
            Message Handler for the Bot
            """
            contact = msg.talker()  # 发消息人
            content = msg.text()  # 消息内容
            room = msg.room()  # 是否是群消息
            contact_name = contact.name
            if room:  # 群聊入口,未做任何处理
                if room.room_id == config_list['room_id'] and (msg.type() == Message.Type.MESSAGE_TYPE_TEXT):
                    print('群聊')
                    room_id = room.room_id
                    print('群名:{},发消息人:{},内容:{}'.format(room_id, contact_name, content))
                    print('使用API发送群消息')
            else:
                dividing_line()
                print('非群聊')
                if msg.type() == Message.Type.MESSAGE_TYPE_TEXT:  # 处理文本类型消息
                    if content == 'ding':
                        await sendTextMsgToContact(contact=contact, text="这是自动回复: dong dong dong")
                    elif content == 'hi' or content == '你好' or content == "帮助":
                        info0 = "我是机器人助手--懂懂,很高兴为您服务!\n"
                        info1 = "1.收到'ding',自动回复\n"
                        info2 = "2.收到'帮助',自动回复\n"
                        info3 = "3.收到'小程序'or'微信小程序',自动回复\n"
                        info4 = "4.收到'情话@your_content',自动回复,例如 情话@春天\n"
                        info5 = "5.收到'藏头诗@your_content',自动回复,例如 藏头诗@我喜欢你\n"
                        info6 = "6.收到'city+天气',自动回复,例如 长沙天气\n"
                        help_info = info0 + info1 + info2 + info3 + info4 + info5 + info6
                        await sendTextMsgToContact(contact=contact, text=help_info)
                    elif content == '小程序' or content == "微信小程序":
                        file_url = 'https://upload-images.jianshu.io/upload_images/10519098-690ae0fde75147a1.png' \
                                   '?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'
                        await sendMediaMsgToContact(contact=contact, fileUrl=file_url, filePath='')
                    elif '天气' in content:
                        city_name = content[:-2]
                        weather_info = get_weather_data(city_name)
                        await contact.say(weather_info)
                    elif "情话" in content:
                        content = content[3:]
                        res = chat_bot(content=content, mode='1')
                        await contact.say(res)
                    elif "藏头诗" in content:
                        # 藏头诗模式
                        content = content[4:]
                        res = chat_bot(content=content, mode='2')
                        await contact.say(res)
                    else:
                        res = chat_bot(content=content, mode='0')
                        await contact.say(res)
                #  处理图片类型消息
                elif msg.type() == Message.Type.MESSAGE_TYPE_IMAGE:
                    dividing_line()
                    await contact.say('不好意思,暂时处理不了图片类型消息,我们已经在催程序员小哥哥日夜加班优化项目了!希望您能够理解!')
    
    
        async def on_scan(self, qr_code: str, status: ScanStatus,
                          data: Optional[str] = None):
            """
            Scan Handler for the Bot
            """
            print('Scan QR Code to login: {}\n'.format(status))
            print('View QR Code Online: https://wechaty.js.org/qrcode/{}'.format(qr_code))
    
        async def on_login(self, contact: Contact):
            """
            Login Handler for the Bot
            """
            print(f'User {contact} logged in\n')
            # TODO: To be written
    
        async def on_logout(self, contact: Contact):
            print(f'User <{contact}> logout')
    
        async def on_friendship(self, friendship: Friendship):
            name = friendship.contact().name
            hello = friendship.hello()
            logMsg = name + '发送了好友请求'
            print(logMsg)
            # print(hello)
            try:
                if friendship.type() == FriendshipType.FRIENDSHIP_TYPE_RECEIVE:
                    if len(config.ACCEPTFRIEND) == 0:
                        print('无认证关键词,自动通过好友请求')
                        await friendship.accept()
                    elif len(config.ACCEPTFRIEND) > 0 and (hello in config.ACCEPTFRIEND):
                        print('触发关键词{},自动通过好友请求'.format(hello))
                        await friendship.accept()
                elif friendship.type() == Friendship.Type.Confirm:
                    logMsg = name + '已确认添加好友'
                    print(logMsg)
                else:
                    print('我不能同意你成为我的好友')
            except:
                print('添加好友出错')
    
    
    async def main():
        """
        Async Main Entry
        """
        # 配置token
        os.environ['WECHATY_PUPPET'] = "wechaty-puppet-sevice"
        # 对应docker部署的token
        Token = "888"
        os.environ['WECHATY_PUPPET_SERVICE_TOKEN'] = Token
        # 对应docker部署的地址
        os.environ['WECHATY_PUPPET_SERVICE_ENDPOINT'] = "81.69.14.8:8080"
        # Make sure we have set WECHATY_PUPPET_SERVICE_TOKEN in the environment variables.
        if 'WECHATY_PUPPET_SERVICE_TOKEN' not in os.environ:
            print('''
                Error: WECHATY_PUPPET_SERVICE_TOKEN is not found in the environment variables
                You need a TOKEN to run the Python Wechaty. Please goto our README for details
                https://github.com/wechaty/python-wechaty-getting-started/#wechaty_puppet_service_token
            ''')
        global bot
        bot = MyBot()
        await bot.start()
    
    
    if __name__ == '__main__':
        asyncio.run(main())
    
    

    3.个人心得

    通过这次比赛认识了很多大佬,收获很多,自己的项目也出现了很多bug,目前的机器人功能还不是特别完善,希望等自己有空闲时间去不断完善自己的项目,当然也欢迎各位小伙伴的加入,可以评论区留言!

    4.参考链接

    5.个人介绍

    中南大学 机电工程学院 机械工程专业 2019级 研究生 雷钢

    百度飞桨官方帮帮团成员

    Github地址:https://github.com/leigangblog

    Gitee地址:https://gitee.com/leigangblog

    B站:https://space.bilibili.com/53420969

    来AI Studio互关吧,等你哦~ https://aistudio.baidu.com/aistudio/personalcenter/thirdview/118783
    欢迎大家fork喜欢评论三连,感兴趣的朋友也可互相关注一下啊~

    展开全文
  • import { Wechaty } from 'wechaty' Wechaty.instance() .on('scan', qrcode => console.log('扫码登录:' + qrcode)) .on('login', user => console.log('登录成功:' + user)) .on('message', message => console...

    需求背景

    目前所在企业是一家创新型汽车后市场互联网科技有限公司,拓展汽车后市场B2C、B2B和O2O业务。

    前期打造链接线下6家自营大型汽车专业维修中心,12家自营汽车配件、汽保设备销售中心,3000余家加盟汽修、汽配企业及10余万个人客户的服务平台;

    由于客户维系和供应商咨询等都是基于微信群聊的。每天要在成百上千的群聊中提供服务。需要实时在群内产品报价,车架号识别,图片识别,关键字反馈。数据推送等等功能。这样的需求情况下,人力成本是巨大的。

    而我作为一名前端开发工程师,平时也喜欢写技术博客和交朋友,为此我也创建了微信技术交流群和微信公众号,一般我都会在文章下面贴出公众号和我的个人二维码,给有兴趣的小伙伴们添加微信然后我再拉他们进群这些,但是不停的同意微信好友验证,再发送群邀请真的是太痛苦了,相信很多做公众号的小伙伴都和我一样,作为一名开发,这种重复劳动是绝对不能忍受的基于这种情况和公司业务情况,调研发现了并了解到了wechaty,发现其提供的功能能够覆盖到企业和个人微信,并且能够自己定制化开发符合自己需求的功能。

    介绍

    Wechaty 是什么

    微信个人号功能非常强大和灵活,是一个非常适合用来做ChatBot的载体。它可以灵活不受限制的发送语音短信、视频、图片和文字,支持多人群聊。但是使用微信个人微信号作为ChatBot,需要通过非官方的第三方库接入微信。因为截至2018年底,微信尚无任何官方的ChatBot API发布。

    Wechaty 是一个开源的的对话机器人 SDK,支持 个人号 微信。它是一个使用Typescript 构建的Node.js 应用。支持多种微信接入方案,包括网页,ipad,ios,windows, android 等。同时支持Linux, Windows, Darwin(OSX/Mac) 和 Docker 多个平台。

    在GitHub上可以找到很多支持微信个人号接入的第三方类库,其中大多都是基于Web Wechat的API来实现的,如基于Python的WeixinBot,基于Node.js的Wechaty等。少数支持非Web协议的库,大多是商业私有闭源的,Wechaty是少有的开源项目支持非Web协议的类库。

    只需要6行代码,你就可以 通过个人号 搭建一个 微信机器人功能 ,用来自动管理微信消息。

    import { Wechaty } from 'wechaty'
    
    Wechaty.instance()
    .on('scan',        qrcode  => console.log('扫码登录:' + qrcode))
    .on('login',       user    => console.log('登录成功:' + user))
    .on('message',     message => console.log('收到消息:' + message))
    .on('friendship',  friendship => console.log('收到好友请求:' + friendship))
    .on('room-invite', invitation => console.log('收到入群邀请:' + invitation))
    .start()
    

    更多功能包括

    • 消息处理:关键词回复
    • 群管理:自动入群,拉人,踢人
    • 自动处理好友请求
    • 智能对话:通过简单配置,即可加入智能对话系统,完成指定任务
    • … 请自行开脑洞
      所有你能想到的交互模式。在微信上都有实现的可能。

    每日定时拉取天气预报。

    每天给你心爱的人发送早安和晚安信息。

    什么成语接龙啦。快问快答等等功能

    当然wechaty的功能服务并不是免费的

    200/月的费用,如果你是个人开发可能会斟酌一二。但是你可以通过社区申请一个长达15天的免费token来尝试使用和开发一个小型机器人,从而决定你是否需要购买使用。

    关于申请的地址我放在了这里Wechaty Token 申请及使用文档和常见问题

    基于wechaty-puppet-hostie开发企业级微信机器人

    目录结构

    ├── config
    │   └── index.js // 配置文件
    ├── package.json
    ├── service
    │   ├── bot-service
    │   │   ├── error-service.js
    │   │   ├── friendship-service.js
    │   │   ├── heartbeat-service.js
    │   │   ├── login-service
    │   │   │   ├── function-service.js
    │   │   │   └── index.js
    │   │   ├── logout-service.js
    │   │   ├── message-service
    │   │   │   ├── function-service.js
    │   │   │   └── index.js
    │   │   ├── ready-service
    │   │   │   ├── function-service.js
    │   │   │   └── index.js
    │   │   ├── room-invite-service.js
    │   │   ├── room-join-service.js
    │   │   ├── room-leave-service.js
    │   │   ├── room-topic-service.js
    │   │   └── scan-service
    │   │       └── index.js
    │   ├── common-service
    │   │   ├── chatbot-service.js
    │   │   ├── ding-service.js
    │   │   └── oss-service.js
    │   └── redis-service
    │       └── index.js
    ├── src
    │   └── main.js // 入口
    ├── store
    │   └── index.js // 全局存储对象
    ├── utils
    │   ├── oss.js // 阿里云oss认证
    │   └── redis.js // redis认证登录
    └── yarn.lock
    

    src/main.js

    const { Wechaty } = require('wechaty')                                          // 机器人木偶
    
    const { onScan } = require("../service/bot-service/scan-service")               // 当机器人需要扫码登陆的时候会触发这个事件。
    const { onLogin } = require("../service/bot-service/login-service")             // 当机器人成功登陆后,会触发事件,并会在事件中传递当前登陆机器人的信息
    const { onLogout } = require("../service/bot-service/logout-service")           // 当机器人检测到登出的时候,会触发事件,并会在事件中传递机器人的信息。
    const { onReady } = require("../service/bot-service/ready-service")             // 当所有数据加载完成后,会触发这个事件。在wechaty-puppet-padchat 中,它意味着已经加载完成Contact 和Room 的信息。
    const { onMessage } = require("../service/bot-service/message-service")         // 当机器人收到消息的时候会触发这个事件。
    const { onRoomInvite } = require("../service/bot-service/room-invite-service")  // 当收到群邀请的时候,会触发这个事件。
    const { onRoomTopic } = require("../service/bot-service/room-topic-service")    // 当有人修改群名称的时候会触发这个事件。
    const { onRoomJoin } = require("../service/bot-service/room-join-service")      // 当有人进入微信群的时候会触发这个事件。机器人主动进入某个微信群,那个样会触发这个事件。
    const { onRoomleave } = require("../service/bot-service/room-leave-service")    // 当机器人把群里某个用户移出群聊的时候会触发这个时间。用户主动退群是无法检测到的。
    const { onFriendship } = require("../service/bot-service/friendship-service")   // 当有人给机器人发好友请求的时候会触发这个事件。
    const { onHeartbeat } = require('../service/bot-service/heartbeat-service')     // 获取机器人的心跳。
    const { onError } = require('../service/bot-service/error-service')             // 当机器人内部出错的时候会触发error 事件。
    
    
    const { wechatyToken } = require('../config/index') // 机器人token
    const { globalData } = require('../store/index') // 全局对象
    
    globalData.bot = new Wechaty({
        puppet: 'wechaty-puppet-hostie',
        puppetOptions: {
            token: wechatyToken
        }
    });
    
    globalData.bot
        .on('scan', onScan)
        .on('login', onLogin)
        .on('logout', onLogout)
        .on('ready', onReady)
        .on('message', onMessage)
        .on('room-invite', onRoomInvite)
        .on('room-topic', onRoomTopic)
        .on('room-join', onRoomJoin)
        .on('room-leave', onRoomleave)
        .on('friendship', onFriendship)
        .on('heartbeat', onHeartbeat)
        .on('error', onError)
        .start()
    

    具体功能实现及代码

    • 扫码登录
      通过node启动后,触发onScan事件,将登录二维码打印在控制台,扫码登录
    const QrcodeTerminal = require('qrcode-terminal');
    const { ScanStatus } = require('wechaty-puppet')
    
    /**
     * @method onScan 当机器人需要扫码登陆的时候会触发这个事件。 建议你安装 qrcode-terminal(运行 npm install qrcode-terminal) 这个包,这样你可以在命令行中直接看到二维码。
     * @param {*} qrcode 
     * @param {*} status 
     */
    const onScan = async (qrcode, status) => {
        try {
            if (status === ScanStatus.Waiting) {
                console.log(`========================👉二维码状态:${status}👈========================\n\n`)
                QrcodeTerminal.generate(qrcode, {
                    small: true
                })
            }
        } catch (error) {
            console.log('onScan', error)
        }
    
    }
    
    module.exports = { onScan }
    
    • 登录成功
      扫码登录成功后会触发onLogin事件,通过事件接收到登录信息和机器人信息,通过钉钉接口将登录通知发送至钉钉群内
    const { notificationLoginInformation } = require('../../common-service/ding-service')
    const { updateBotInfo } = require('./function-service')
    const { globalData } = require('../../../store/index')
    
    /**
     * @method onLogin 当机器人成功登陆后,会触发事件,并会在事件中传递当前登陆机器人的信息
     * @param {*} botInfo 
     */
    const onLogin = async botInfo => {
        try {
            console.log('========================👉 onLogin 👈========================\n\n')
            console.log(`机器人信息:${JSON.stringify(botInfo)}\n\n`)
            console.log(`
                               //
                   \\         //
                    \\       //
            ##DDDDDDDDDDDDDDDDDDDDDD##
            ## DDDDDDDDDDDDDDDDDDDD ##      
            ## DDDDDDDDDDDDDDDDDDDD ##      
            ## hh                hh ##      ##         ## ## ## ##   ## ## ## ###   ##    ####     ##     
            ## hh    //    \\     hh ##      ##         ##       ##   ##             ##    ## ##    ##
            ## hh   //      \\    hh ##      ##         ##       ##   ##             ##    ##   ##  ##
            ## hh                hh ##      ##         ##       ##   ##     ##      ##    ##    ## ##
            ## hh      wwww      hh ##      ##         ##       ##   ##       ##    ##    ##     ####
            ## hh                hh ##      ## ## ##   ## ## ## ##   ## ## ## ###   ##    ##      ###
            ## MMMMMMMMMMMMMMMMMMMM ##    
            ##MMMMMMMMMMMMMMMMMMMMMM##      微信机器人名为: [${botInfo.payload.name}] 已经扫码登录成功了。\n\n
            `)
            // 全局存储机器人信息
            globalData.botPayload = botInfo.payload
            // 更新机器人列表
            updateBotInfo()
            // 机器人登录登出提醒/通知钉钉接口
            notificationLoginInformation(true)
        } catch (error) {
            console.log(`onLogin: ${error}`)
        }
    
    }
    
    module.exports = { onLogin }
    

    — 机器人异常退出
    当node服务异常终端,或者手机上退出机器人登录后会触发onLogout事件,同样钉钉群内通知信息,并且销毁程序中运行的一些定时器等

    const { notificationLoginInformation } = require('../common-service//ding-service')
    const { globalData } = require('../../store/index')
    
    /**
     * @method onLogout 当机器人检测到登出的时候,会触发事件,并会在事件中传递机器人的信息。
     * @param {*} botInfo 
     */
    const onLogout = async botInfo => {
        try {
            console.log('========================👉 onLogout 👈========================')
            console.log(`当bot检测到注销时,将与当前登录用户的联系人发出注销。`)
            // 全局存储机器人信息
            globalData.botPayload = botInfo.payload
            const { updateRoomInfoTimer, chatbotSayQueueTimer } = globalData
            // 机器人退出清空定时器
            if (updateRoomInfoTimer) {
                clearTimeout(updateRoomInfoTimer)
            }
            if (chatbotSayQueueTimer) {
                clearInterval(chatbotSayQueueTimer)
            }
            // 机器人登录登出提醒/通知钉钉接口
            notificationLoginInformation(false)
        } catch (error) {
            console.log(`error in onLogout:${error}`)
        }
    
    }
    
    module.exports = { onLogout }
    
    • 消息接收处理
      当微信接收到新的消息时候会触发onMessage事件,通过事件内对消息的判断,群内消息还是私聊消息等做出不同的逻辑处理。从而实现业务需求。部分代码如下
    const dayjs = require('dayjs');
    const { say } = require('../../common-service/chatbot-service')
    const {
        isCanSay,
        roomIdentifyVin,
        rooImageIdentifyVin,
        contactIdentifyVin,
        contactImageIdentifyVin,
        messageProcessing,
        storageRoomMessage,
        storageContactMessage,
    } = require('./function-service')
    const {
        roomMessageFeedback,
        contactMessageFeedback
    } = require('../../common-service/ding-service')
    const { globalData } = require('../../../store/index');
    const { Message } = require('wechaty');
    
    /**
     * @method onMessage 当机器人收到消息的时候会触发这个事件。
     * @param {*} message 
     */
    const onMessage = async message => {
        try {
            console.log('========================👉 onMessage 👈========================\n\n')
            // 机器人信息
            const { botPayload } = globalData
            // 获取发送消息的联系人
            const contact = message.from()
            // 获取消息所在的微信群,如果这条消息不在微信群中,会返回null         
            const room = message.room()
            // 查看这条消息是否为机器人发送的
            const isSelf = message.self()
            // 处理消息内容
            const text = await messageProcessing(message)
            // console.log(`========================👉 处理消息后内容为:${text} 👈========================\n\n`)
            // 消息为空不处理
            if (!text) return
    
            // 消息详情
            const messagePayload = message.payload
            // console.log(`========================👉 消息详情:${JSON.stringify(messagePayload)} 👈========================\n\n`)
            // 消息联系人详情
            const contactPayload = contact.payload
            // console.log(`========================👉 消息联系人详情:${JSON.stringify(contactPayload)} 👈========================\n\n`)
            // 群消息
            if (room) {
                console.log(`========================👉 群聊消息 👈========================\n\n`)
                // 房间详情
                const roomPayload = room.payload
                // console.log(`========================👉 房间详情:${JSON.stringify(roomPayload)} 👈========================\n\n`)
                console.log(`消息时间:${dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss')}\n\n群聊名称:${roomPayload.topic}\n\n微信名称:${contactPayload.name}\n\n微信类型:${contactPayload.type}\n\n备注昵称:${contactPayload.alias}\n\n消息内容:${text}\n\n消息类型:${messagePayload.type}\n\n`);
                // 存储消息内容
                const storeMessage = {
                    category: 'room',                               // 消息类别,room为群聊消息, contact为个人消息。
                    isSelf: isSelf,                                 // 是否自己发送的消息
    
                    messageId: messagePayload.id,                   // 消息id
                    messageToId: messagePayload.toId,               // 消息接收者id
                    messageType: messagePayload.type,               // 消息类型
                    messageText: text,                              // 消息内容
                    messageTimestamp: messagePayload.timestamp,     // 消息时间戳
                    messageTime: dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss'), // 消息时间
    
                    roomOwnerId: roomPayload.ownerId,               // 群聊群主id
                    roomTopic: roomPayload.topic,                   // 群聊名称
                    roomId: roomPayload.id,                         // 群聊名称
    
                    contactId: contactPayload.id,                   // 消息发送者id
                    contactName: contactPayload.name,               // 消息发送者昵称
                    contactType: contactPayload.type,               // 消息发送者类型
                    contactAvatar: contactPayload.avatar,           // 消息发送者头像
                    contactAlias: contactPayload.alias,             // 消息发送者备注
                }
                //  redis中存储群聊消息内容
                storageRoomMessage(roomPayload, storeMessage)
    
                // 消息是机器人自己发的 或者 消息发送到wechaty接收间隔大于半个小时
                if (isSelf || message.age() > 1800) return
    
                // 判断当前机器人在群中是否可以说话 
                if (!await isCanSay(roomPayload)) return
    
                // 有人@我
                const isMentionSelf = await message.mentionSelf()
                // 如果有人@我
                if (isMentionSelf) {
                    console.log('this message were mentioned me! [You were mentioned] tip ([有人@我]的提示)')
                    // 获取消息内容,拿到整个消息文本,去掉 @名字
                    const sendText = text.replace("@" + botPayload.name, "")
                    if (sendText == '图片') {
                        // 通过不同的关键字进行业务处理逻辑
                        say({
                            messageType: 6,
                            sender: room,
                            messageInfo: {
                                fromUrl: 'https://wework.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDqfABIxIv4ic0FyQRxgQVpUIaqlePxrDW8L2qPB3WnHSZclgQ1D1QhDs/0'
                            }
                        })
                        return
    
                    }
    
                    if (sendText == '分享') {
                        // 通过不同的关键字进行业务处理逻辑
                        say({
                            messageType: 14,
                            sender: room,
                            messageInfo: {
                                urlLink: {
                                    description: 'WeChat Bot SDK for Individual Account, Powered by TypeScript, Docker, and Love',
                                    thumbnailUrl: 'https://avatars0.githubusercontent.com/u/25162437?s=200&v=4',
                                    title: 'Welcome to Wechaty',
                                    url: 'https://github.com/wechaty/wechaty',
                                }
                            }
                        })
                        return
                    }
                    if (sendText == '名片') {
                        say({
                            messageType: 3,
                            sender: room,
                            messageInfo: {
                                contactCard: 'contactId'
                            }
                        })
                        return
                    }
    
                    if (sendText == '小程序') {
                        say({
                            messageType: 9,
                            sender: room,
                            messageInfo: {
                                miniProgram: {
                                    appid: 'xxxxx',
                                    title: '我正在使用Authing认证身份,你也来试试吧',
                                    pagePath: 'pages/home/home.html',
                                    description: '身份管家',
                                    thumbUrl: '30590201000452305002010002041092541302033d0af802040b30feb602045df0c2c5042b777875706c6f61645f31373533353339353230344063686174726f6f6d3131355f313537363035393538390204010400030201000400',
                                    thumbKey: '42f8609e62817ae45cf7d8fefb532e83',
                                }
                            }
                        })
                        return
                    }
    
    
                    // 群里正常说话
                } else {
                    // 重构机器人功能测试群
                    if (roomPayload.id !== 'R:10696051737544800') {
                        console.log(`========================👉 不是测试群消息,不处理群内业务逻辑 👈========================\n\n`)
                        return
                    }
    
                    if (/^[a-zA-Z0-9]{17}$/.test(text)) {
                        // 群聊识别vin反馈
                        roomIdentifyVin(room, contact, message, text)
                        return
                    }
    
                    // 群内消息以[弱]开头的信息为反馈信息。反馈给后台
                    if (text.indexOf('[弱]') === 0) {
                        // 群消息反馈
                        roomMessageFeedback(room, contact, text)
                        return
                    }
    
                    // 如果是图片,则图片解析vin
                    if (messagePayload.type === Message.Type.Image) {
                        // 群聊图片识别vin反馈
                        rooImageIdentifyVin(room, contact, message)
                    }
                }
    
                // 私聊消息
            } else {
                console.log(`========================👉 私聊消息 👈========================\n\n`)
                console.log(`消息时间:${dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss')}\n\n微信名称:${contactPayload.name}\n\n微信类型:${contactPayload.type}\n\n备注昵称:${contactPayload.alias}\n\n消息内容:${text}\n\n消息类型:${messagePayload.type}\n\n`);
                // 存储消息内容
                const storeMessage = {
                    category: 'contact',                            // 消息类别,room为群聊消息, contact为个人消息。
                    isSelf: isSelf,                                 // 是否自己发送的消息
    
                    messageId: messagePayload.id,                   // 消息id
                    messageToId: messagePayload.toId,               // 消息接收者id
                    messageType: messagePayload.type,               // 消息类型
                    messageText: text,                              // 消息内容
                    messageTimestamp: messagePayload.timestamp,     // 消息时间戳
                    messageTime: dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss'), // 消息时间
    
                    contactId: contactPayload.id,                   // 消息发送者id
                    contactName: contactPayload.name,               // 消息发送者昵称
                    contactType: contactPayload.type,               // 消息发送者类型
                    contactAvatar: contactPayload.avatar,           // 消息发送者头像
                    contactAlias: contactPayload.alias,             // 消息发送者备注
                }
                //  redis中存储私聊消息内容
                storageContactMessage(contact, storeMessage)
                // 消息是机器人自己发的 或者 消息发送到wechaty接收间隔大于半个小时
                if (isSelf || message.age() > 1800) return
    
                if (/^[a-zA-Z0-9]{17}$/.test(text)) {
                    // 私聊识别vin反馈
                    contactIdentifyVin(contact, message, text)
                    return
                }
    
                // 私聊消息以[弱]开头的信息为反馈信息。反馈给后台
                if (text.indexOf('[弱]') === 0) {
                    // 私聊消息反馈
                    contactMessageFeedback(contact, text)
                    return
                }
    
                // 如果是图片,则图片解析vin
                if (messagePayload.type === Message.Type.Image) {
                    // 私聊图片解析vin反馈
                    contactImageIdentifyVin(contact, message)
                }
            }
        } catch (error) {
            console.log(`onMessage:${error}`)
        }
    }
    
    module.exports = { onMessage }
    

    至于其他的一些生命周期以及钩子函数。大家可以参考文档做出属于自己的应用机器人

    封装say方法

    因为say()方法会在多处调用,并且要根据不同的消息类型发送的内容做出不同的数据处理。大家以后也会遇到,因此这里将我封装的一个say方法展示给大家用于参考

    const { MiniProgram, UrlLink, FileBox } = require('wechaty')
    const dayjs = require('dayjs');
    const { DelayQueueExector } = require('rx-queue');
    const { redisHexists, redisHset, redisHget, redisSet, redisLpush } = require('../redis-service/index')
    const { globalData } = require('../../store/index')
    
    const delay = new DelayQueueExector(10000);
    
    /**
     * @method say 机器人发送消息
     * @param {*} messageType   消息类型   7文本,1文件,6图片,3个人名片,14卡片链接 9小程序
     * @param {*} sender        来源   房间 || 个人 实例对象
     * @param {*} messageInfo 内容 
    */
    /**
     * messageInfo 数据结构
     *      tetx: string        文本消息必传
     *      fileUrl: string     文件消息必传
     *      imageUr: string     图片消息必传
     *      cardId: string      个人名片消息必传
     *      linkInfo: object    卡片消息必传
     *          description: string     描述 
     *          thumbnailUrl: string    缩略图地址
     *          title: string           标题
     *          url: string             跳转地址
     */
    
    async function say({ messageType, sender, messageInfo }) {
        // console.log(messageType);
        // console.log(sender);
        // console.log(messageInfo);
        try {
            return new Promise(async (resolve, reject) => {
                // 机器人信息
                const { bot } = globalData
                // 枚举消息类型
                const MessageType = {
                    text: 7,            // 文本
                    fromFile: 1,        // 文件
                    fromUrl: 6,         // 图片
                    contactCard: 3,     // 个人名片
                    urlLink: 14,        // 卡片链接
                    miniProgram: 9,     // 小程序
    
                }
    
                // 内容不存在
                if (!messageInfo) {
                    return
                }
                // 要发送的消息内容
                let content
    
    
                switch (messageType) {
                    // 文本 7
                    case MessageType.text:
                        content = messageInfo.text
                        break;
                    // 文件 1
                    case MessageType.fromFile:
                        content = FileBox.fromFile(messageInfo.fromFile)
                        break;
                    // 图片 6
                    case MessageType.fromUrl:
                        content = FileBox.fromUrl(messageInfo.fromUrl)
                        break;
                    // 个人名片 3
                    case MessageType.contactCard:
                        content = await bot.Contact.load('1688853777824721')
                        break;
                    // 链接 14
                    case MessageType.urlLink:
                        content = new UrlLink({
                            description: 'WeChat Bot SDK for Individual Account, Powered by TypeScript, Docker, and Love',
                            thumbnailUrl: 'https://avatars0.githubusercontent.com/u/25162437?s=200&v=4',
                            title: 'Welcome to Wechaty',
                            url: 'https://github.com/wechaty/wechaty',
                        })
                        break;
                    // 小程序 9
                    case MessageType.miniProgram:
                        content = new MiniProgram({
                            appid: 'wx60090841b63b6250',
                            title: '我正在使用Authing认证身份,你也来试试吧',
                            pagePath: 'pages/home/home.html',
                            description: '身份管家',
                            thumbUrl: '30590201000452305002010002041092541302033d0af802040b30feb602045df0c2c5042b777875706c6f61645f31373533353339353230344063686174726f6f6d3131355f313537363035393538390204010400030201000400',
                            thumbKey: '42f8609e62817ae45cf7d8fefb532e83',
                        });
                        break;
                    default:
                        break;
                }
                delay.execute(async () => {
                    sender.say(content)
                        .then(value => {
                            console.log(`========================👉 机器人回复 👈========================\n\n`)
                            resolve()
                        })
                        .catch(reason => {
                            console.log(`========================😢 机器人发送消息失败 😢========================\n\n`, reason)
                        })
                })
            })
        } catch (error) {
            console.log('error in say', error);
        }
    
    }
    module.exports = {
        say
    }
    

    对了,对于onMessage事件中消息格式的判断我也做了一层封装,这里给大家提供参考。

    /**
     * @method messageProcessing 处理消息内容
     * @param {*} message 
     */
    async function messageProcessing(message) {
        try {
            return new Promise(async (resolve, reject) => {
                console.log(`========================👉 messageProcessing 👈========================\n\n`)
                // 消息详情
                const messagePayload = message.payload
                // 获取消息的文本内容。   
                let text = message.text()
    
                /** 
                 *  Unknown: 0,
                    Attachment: 1,
                    Audio: 2,
                    Contact: 3,
                    ChatHistory: 4,
                    Emoticon: 5,
                    Image: 6,
                    Text: 7,
                    Location: 8,
                    MiniProgram: 9,
                    GroupNote: 10,
                    Transfer: 11,
                    RedEnvelope: 12,
                    Recalled: 13,
                    Url: 14,
                    Video: 15
                */
                // 消息类型
                switch (messagePayload.type) {
                    // 附件 0
                    case Message.Type.Unknown:
                        console.log(`========================👉 消息类型为未知消息:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一个未知消息,请在手机上查看]'
                        break;
                    // 附件 1
                    case Message.Type.Attachment:
                        console.log(`========================👉 消息类型为附件:${messagePayload.type} 👈========================\n\n`)
                        // 暂时不知道怎么处理
                        text = '[你收到一个附件,请在手机上查看]'
                        break;
                    // 音频 2
                    case Message.Type.Audio:
                        console.log(`========================👉 消息类型为音频:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一条语音消息,请在手机上查看]'
                        break;
                    // 个人名片 3
                    case Message.Type.Contact:
                        console.log(`========================👉 消息类型为个人名片:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一张个人名片,请在手机上查看]'
                        break;
                    // 聊天记录 4
                    case Message.Type.ChatHistory:
                        console.log(`========================👉 消息类型为聊天记录:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到聊天记录,请在手机上查看]'
                        break;
                    // 表情符号 5
                    case Message.Type.Emoticon:
                        console.log(`========================👉 消息类型为表情符号:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到表情符号,请在手机上查看]'
                        // 暂时不知道怎么处理
                        break;
                    // 图片 6
                    case Message.Type.Image:
                        console.log(`========================👉 消息类型为图片:${messagePayload.type} 👈========================\n\n`)
                        // 上传图片至阿里云获取图片地址
                        text = await addImageOss(message)
                        break;
                    // 文本 7
                    case Message.Type.Text:
                        console.log(`========================👉 消息类型为文本:${messagePayload.type} 👈========================\n\n`)
                        // 去空格换行
                        text = text.replace(/\s+/g, '')
                        break;
                    // 位置 8
                    case Message.Type.Location:
                        console.log(`========================👉 消息类型为位置:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一条图片消息,请在手机上查看]'
                        break;
                    // 小程序 9
                    case Message.Type.MiniProgram:
                        console.log(`========================👉 消息类型为小程序:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一个小程序消息,请在手机上查看]'
                        break;
                    // GroupNote 10
                    case Message.Type.GroupNote:
                        console.log(`========================👉 消息类型为GroupNote:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一个GroupNote,请在手机上查看]'
                        break;
                    // Transfer 11
                    case Message.Type.Transfer:
                        console.log(`========================👉 消息类型为Transfer:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一个Transfer,请在手机上查看]'
                        break;
                    // 红包 12
                    case Message.Type.RedEnvelope:
                        console.log(`========================👉 消息类型为红包:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一个红包,请在手机上查看]'
                        break;
                    // Recalled 13
                    case Message.Type.Recalled:
                        console.log(`========================👉 消息类型为Recalled:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一个Recalled,请在手机上查看]'
                        break;
                    // 链接地址 14
                    case Message.Type.Url:
                        console.log(`========================👉 消息类型为链接地址:${messagePayload.type} 👈========================\n\n`)
                        // 暂时不知道怎么处理
                        text = '[你收到一条链接消息,请在手机上查看]'
                        break;
                    // 视频 15
                    case Message.Type.Video:
                        console.log(`========================👉 消息类型为视频:${messagePayload.type} 👈========================\n\n`)
                        text = '[你收到一个视频消息,请在手机上查看]'
                        break;
                    default:
                        text = ''
                        break;
                }
                resolve(text)
            })
        } catch (error) {
            console.log('error in messageProcessing', error);
        }
    
    }
    

    为什么这样做一层封装处理,是因为我们的业务需求要将聊天内容进行redis和mysql数据存储。方便以后数据订正和查询使用。

    实现的功能

    基于wechaty我们实现的功能有那些呢?

    — 根据关键词,输入车辆 VIN 对应反馈出车型配件信息,并且将公司所在群区域的店铺配件库存信息反馈出来

    • 根据图片识别车辆 VIN,然后识别 VIN 对应反馈出车型配件信息,并且将公司所在群区域的店铺配件库存信息反馈出来,图片解释接口采用的百度的接口
    • 关键词指令绑定群信息。根据不同指令进行群配置。
    • redis 存储机器人信息。将群信息存储并同步在 redis 和 mysql 中。后台配置对应群是否开启某些功能等等。
    • 每月月初定时发送每个群的采购信息。销量信息等等。
    • 机器人登录调用钉钉接口,在钉钉群内发布机器人登录或者退出的提醒信息
    • 群邀请自动通过,入群以后做出相应数据存储逻辑判断功能设置等
    • 好友申请自动通过,关键字申请自动邀请入不同的群,功能覆盖等等
    • 等等功能。
      以上功能支持还在不断开发和摸索中。但已经满足目前我们的业务需求。

    最后

    你如果想用我这些东西,拉下代码config.js里换下token和一些配置信息就可以,当然我在不停更新,功能会越来越多,所以仓库中代码和文中会有些不一样,使用时简单看下代码,都写了详细注释,也很简单,但是因为代码中很多地方涉及到来企业敏感信息。我只好重新写来一份最小可执行的demo,大家仅供参考。

    ❤️ 看完帮个忙

    如果你觉得这篇内容对你挺有启发,我想邀请你帮我个小忙:

    1. 点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)

    2. 关注公众号「番茄学前端」,我会定时更新和发布前端相关信息和项目案例经验供你参考。

    3. 加个好友, 虽然帮不上你大忙,但是一些业务问题大家可以探讨交流。

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 569
精华内容 227
关键字:

wechaty