當前位置:編程學習大全網 - 源碼下載 - 基於wechaty的定時消息推送(可以哄女朋友)、智能聊天和私人助理

基於wechaty的定時消息推送(可以哄女朋友)、智能聊天和私人助理

---

title: "基於wechaty的定時消息推送(可以哄女朋友)、智能聊天和私人助理"

author: jasonlovesharon

email: 54027901@163.com

tags:

? - nodejs

? - wechaty

? - wechaty-puppet-padplus

---

## 前言

- 自從2017年微信web端API限制以後,itchat等壹大批bot歇菜了,壹直都在找壹款合適的替品

- 目前來看,大部分都是針對windows微信客戶端,基於HOOK的dll註入實現對微信的操控,有壹定的封號風險,只能用固定的版本,部署在linux服務器端比較困難,意味著只能壹直開著電- -wechaty,支持IPAD,,MAC等多種協議,不用去調用WEB網頁API,並且可以布署在服務器,滿足我所有需求。[項目地址](/wechaty/wechaty)

- 看完官方文檔後([token官方介紹](/juzibot/welcome/wiki/everything-about-wechaty)), 發現需要申請Token,並且python版本的Token是要付費的,但沒有學過typescript,有點想放棄,瀏覽了壹下ding-dong-bot的Example,似乎可以看懂,那就邊學習邊摸索吧。(ps:後來偶然見發現了另壹篇可以使用將token轉變壹下實現python版wechaty,但此時已經基本用TS寫完了,如果想用Python等其他語言可以參考[官方文檔](/wechaty/wechaty/issues/1985)。)

## 具備功能

### 1. 關鍵詞觸發功能

1.1 關鍵詞"介紹壹下自己"、 "自我介紹壹下"、 "妳是誰"觸發自我介紹

1.2 地名+天氣 觸發天氣查詢

### 2. 智能聊天功能

2.1群外直接聊天

2.2群內成員皆有聊天權限“@bot” 聊天

2.3不會回復 @其他群成員 的消息

## 實現過程

Talk is cheap,show your code

### 1. 主程序

```typescript

import { Wechaty, Message, UrlLink,log,} from 'wechaty'

import { PuppetPadplus } from 'wechaty-puppet-padplus'

import { EventLogger, QRCodeTerminal } from 'wechaty-plugin-contrib'

import { WechatyWeixinOpenAI, } from 'wechaty-weixin-openai'

import { setSchedule, } from './schedule/index'

import { getDay, formatDate,} from './utils/index'

import { getOne, getTXweather, getSweetWord,} from './superagent/index'

// 創建微信每日說定時任務

async function initDay() {

? console.log(`已經設定每日說任務`);

? setSchedule('0 40 0 * * *', async () => {

console.log('妳的貼心小助理開始工作啦!')

let logMsg

let contact =

? (await bot.Contact.find({ name: 'Jason' })) ||

? (await bot.Contact.find({ alias: 'boss' })) // 獲取妳要發送的聯系人

let one = await getOne() //獲取每日壹句

let weather = await getTXweather() //獲取天氣信息

let today = await formatDate(new Date()) //獲取今天的日期

let memorialDay = getDay('2009/08/07') //獲取紀念日天數

let sweetWord = await getSweetWord()

let str = `${today}\n我們相愛的第${memorialDay}天\n\n元氣滿滿的壹天開始啦,要開心噢^_^\n\n今日天氣\n${weather.weatherTips}\n${

? weather.todayWeather

}\n每日壹句:<br>${one}<br><br>每日土味情話:<br>${sweetWord}<br><br>————————最愛妳的我`

try {

? logMsg = str

? await delay(2000)

? await contact.say(str) // 發送消息

} catch (e) {

? logMsg = e.message

}

console.log(logMsg)

? })

}

const padplusToken = '妳自己的TOKEN'

const puppet = new PuppetPadplus({

? token: padplusToken,

})

const bot = new Wechaty({

? name: 'jason-assistant',

? puppet,

})

bot.use(EventLogger())

bot.use(QRCodeTerminal({ small: true }))

//在Wechaty裏面引用和配置插件

const openAIToken = '妳自己的機器人TOKEN' //需要在微信對話開放平臺申請,點擊機器人設置》綁定應用》在頁面最下方即可看到

const openAIEncodingAESKey = '妳自己的EncodingAESKey' //微信對話開放平臺申請,點擊機器人設置》綁定應用》在頁面最下方即可看到

const preAnswerHook = async (message: Message) => {

? const isCommonMaterial = await processCommonMaterial(message)

? if (isCommonMaterial) {

return false

? }

}

/**

* 獲得boss聯系名片,當機器人找不到問題答案時,將BOSS的名片推送過去

*/

const getBoss = async () => {

const contact = bot.Contact.load('boss微信ID')

await contact.sync()

return contact

? }

const noAnswerHook = async (message: Message) => {

const room = message.room()

const from = message.from()

if (!room) {

? const boss = await getBoss()

? await message.say('妳的問題我不會回答,妳可以聯系我的老板')

? await message.say(boss)

? return;

}

const members = await room.memberAll()

const bossInRoom = members.find(m => m.id === 'boss微信id')

if (bossInRoom) {

? await room.say`${bossInRoom},${from}問的問題我不知道,妳幫我回答壹下吧。`

} else {

? const boss = await getBoss()

? await room.say`${from},妳的問題我不會回答,妳可以聯系我的老板`

? await room.say(boss)

}

? }

/**

* 用wechaty-weixin-openai可以實現快速接入微信對話平臺

*/

bot.use(WechatyWeixinOpenAI({

token: openAIToken,

encodingAESKey: openAIEncodingAESKey,

noAnswerHook, //在機器人無法回答時,推送設定的回答

preAnswerHook, //判斷是否是關鍵字,如果是關鍵字,觸發關鍵字回答而不接入微信開放平臺

? }))

const processCommonMaterial = async (message: Message) => {

const room = message.room()

// const from = message.from()

const mentionSelf = await message.mentionSelf()

const text = message.text()

let intro = 'Jason,愛好廣泛,廣交天下豪傑,上得了九天摘月,下得了五洋捉鱉,俗話說的好,不會烘培的飛行員不是好戶外人,不會玩音樂的水族愛好者不是好廚師,不會畫畫的極限愛好者不是好程序員,這就是我的老板Jason,吼吼吼~~'

if (room !== null && mentionSelf) {

? if (/jason|妳老板|妳上司/.test(text)) {

await room.say(intro)

await room.say(new UrlLink({

description: '戶外賤客 & Fighting,fighting,finghting and finghting,讀萬卷書,行萬裏路,學習AND吃,喝,玩,樂',

thumbnailUrl: '',

title: 'Jason',

url: '/s?__biz=MzkxODE3MjAyNQ==&mid=100000001&idx=1&sn=d05de320c6fbe6c9f9149a09a4da81ec&chksm=41b4391776c3b001c143ac2c284c58ac8b08de41d95cab682aa5a07022e32096567f5780d5be#rd',

? }))

return true

? } else if (/戶外賤客/.test(text)) {

await room.say(new UrlLink({

description: '戶外賤客 & Fighting,fighting,finghting and finghting,讀萬卷書,行萬裏路,學習AND吃,喝,玩,樂',

thumbnailUrl: '',

title: 'Jason',

url: '/s?__biz=MzkxODE3MjAyNQ==&mid=100000001&idx=1&sn=d05de320c6fbe6c9f9149a09a4da81ec&chksm=41b4391776c3b001c143ac2c284c58ac8b08de41d95cab682aa5a07022e32096567f5780d5be#rd',

? }))

return true

? }

}

return false

}

// 登錄

async function onLogin(user) {

? console.log(`貼心小助理${user}登錄了`)

? // 登陸後創建定時任務

? await initDay()

}

bot.on('login', onLogin)

bot.start()

? .then(() => log.info('StarterBot', 'Starter Bot Started.'))

? .catch(e => log.error('StarterBot', e))

```

### 2.創建schedule定時函數

```typescript

import { schedule } from 'node-schedule'

// date 參數

//其他規則見 /package/node-schedule

// 規則參數講解 *代表通配符

//

// *? *? *? *? *? *

// ┬ ┬ ┬ ┬ ┬ ┬

// │ │ │ │ │? |

// │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)

// │ │ │ │ └───── month (1 - 12)

// │ │ │ └────────── day of month (1 - 31)

// │ │ └─────────────── hour (0 - 23)

// │ └──────────────────── minute (0 - 59)

// └───────────────────────── second (0 - 59, OPTIONAL)

// 每分鐘的第30秒觸發: '30 * * * * *'

//

// 每小時的1分30秒觸發 :'30 1 * * * *'

//

// 每天的淩晨1點1分30秒觸發 :'30 1 1 * * *'

//

// 每月的1日1點1分30秒觸發 :'30 1 1 1 * *'

//

// 每周1的1點1分30秒觸發 :'30 1 1 * * 1'

function setSchedule(date,callback) {

? schedule.scheduleJob(date, callback)

}

export function setSchedule()

```

### 3.創建幾個功能函數,爬取ONE網站的每日壹句,提取通過API獲取的消息

```typescript

import * as cheerio from 'cheerio'

import * as superagent from 'superagent'

const ONE = '/' // ONE的web版網站

const TXHOST = '/txapi/' // 天行host

function req(url,method, params, data, cookies) {

? return new Promise(function (resolve,reject) {

superagent(method, url)

? .query(params)

? .send(data)

? .set('Content-Type','application/x-www-form-urlencoded')

? .end(function (err, response) {

if (err) {

reject(err)

}

resolve(response)

? })

})

}

async function getOne() {

? // 獲取每日壹句

? try {

let res = await req(ONE, 'GET')

let $ = cheerio.load(res.text)

let todayOneList = $('#carousel-one .carousel-inner .item')

let todayOne = $(todayOneList[0])

? .find('.fp-one-cita')

? .text()

? .replace(/(^\s*)|(\s*$)/g, '')

return todayOne

? } catch (err) {

console.log('錯誤', err)

return err

? }

}

async function getTXweather() {

? // 獲取天行天氣

? let url = TXHOST + 'tianqi/'

? try {

let res = await req(url, 'GET', {

? key: '妳自己的KEY',//需要自己去天行申請,地址/signup.html?source=474284281

? city: 'Arlington'

})

let content = JSON.parse(res.text)

if (content.code === 200) {

? let todayInfo = content.newslist[0]

? let obj = {

weatherTips: todayInfo.tips,

todayWeather:`阿林頓今天${todayInfo.weather}\n溫度:${todayInfo.lowest}/${todayInfo.highest}

\n${todayInfo.wind}風: ${todayInfo.windspeed}\n紫外線指數:${todayInfo.uv_index}\n濕度

${todayInfo.humidity}`

? };

? console.log('獲取天行天氣成功', obj)

? return obj

} else {

? console.log('獲取接口失敗', content.code)

}

? } catch (err) {

console.log('獲取接口失敗', err)

? }

}

async function getSweetWord() {

? // 獲取土味情話

? let url = TXHOST + 'saylove/'

? try {

let res = await req(url, 'GET', { key: '' })

let content = JSON.parse(res.text)

if (content.code === 200) {

? let sweet = content.newslist[0].content

? let str = sweet.replace('\r\n', '<br>')

? return str

} else {

? console.log('獲取接口失敗', content.msg)

}

? } catch (err) {

console.log('獲取接口失敗', err)

? }

}

export { getOne, getTXweather, getSweetWord, }

```

### 計算距離某日(生日,結婚紀念日等)還有多少天

```typescript

function getDay(date) {

? var date2 = new Date()

? var date1 = new Date(date)

? var iDays = parseInt(

Math.abs(date2.getTime() - date1.getTime()) / 1000 / 60 / 60 / 24

? )

? return iDays

}

function formatDate(date) {

? var tempDate = new Date(date)

? var year = tempDate.getFullYear()

? var month = tempDate.getMonth() + 1

? var day = tempDate.getDate()

? var hour = tempDate.getHours()

? var min = tempDate.getMinutes()

? var second = tempDate.getSeconds()

? var week = tempDate.getDay()

? var str = ''

? if (week === 0) {

str = '星期日'

? } else if (week === 1) {

str = '星期壹'

? } else if (week === 2) {

str = '星期二'

? } else if (week === 3) {

str = '星期三'

? } else if (week === 4) {

str = '星期四'

? } else if (week === 5) {

str = '星期五'

? } else if (week === 6) {

str = '星期六'

? }

? if (hour < 10) {

hour = '0' + hour

? }

? if (min < 10) {

min = '0' + min

? }

? if (second < 10) {

second = '0' + second

? }

? return year + '-' + month + '-' + day + '日 ' + hour + ':' + min + ' ' + str

}

export { getDay, formatDate }

```

![關鍵字觸發消息](/jasonlovesharon/my_bot)),由於對Typescript不熟,很多功能都是借鑒很多大神的輪子實現的,還是對Python熟悉點,下步準備用Python來實現以上功能,並進壹步拓展更多有趣的功能。

  • 上一篇:我的世界木鏟有什麽用?
  • 下一篇:房子沒有房產證可以貸款嗎(有房產證貸款流程)
  • copyright 2024編程學習大全網