wechaty-web-panel 1.0.3-beta.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  <project version="4">
3
3
  <component name="ChangeListManager">
4
4
  <list default="true" id="2e980355-75b9-47a9-b344-f25eda9493b2" name="Default Changelist" comment="feat(模块): 添加了个很棒的功能&#10;fix(模块): 修复了一些 bug&#10;docs(模块): 更新了一下文档&#10;UI(模块): 修改了一下样式&#10;chore(模块): 对脚手架做了些更改&#10;locale(模块): 为国际化做了微小的贡献">
5
- <change beforePath="$PROJECT_DIR$/src/service/event-dispatch-service.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/service/event-dispatch-service.js" afterDir="false" />
5
+ <change beforePath="$PROJECT_DIR$/src/proxy/tencent-open.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/proxy/tencent-open.js" afterDir="false" />
6
6
  </list>
7
7
  <option name="SHOW_DIALOG" value="false" />
8
8
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -53,6 +53,16 @@
53
53
  <recent name="$PROJECT_DIR$/koa/pubilc/static" />
54
54
  </key>
55
55
  </component>
56
+ <component name="RunManager">
57
+ <configuration name="index.template.js" type="NodeJSConfigurationType" temporary="true" nameIsGenerated="true" path-to-js-file="$PROJECT_DIR$/test/index.template.js" working-dir="$PROJECT_DIR$/test">
58
+ <method v="2" />
59
+ </configuration>
60
+ <recent_temporary>
61
+ <list>
62
+ <item itemvalue="Node.js.index.template.js" />
63
+ </list>
64
+ </recent_temporary>
65
+ </component>
56
66
  <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
57
67
  <component name="SvnConfiguration">
58
68
  <configuration />
@@ -115,7 +125,12 @@
115
125
  <workItem from="1653468787592" duration="419000" />
116
126
  <workItem from="1655173951557" duration="1402000" />
117
127
  <workItem from="1655186504356" duration="87000" />
118
- <workItem from="1655186988658" duration="163000" />
128
+ <workItem from="1655186988658" duration="336000" />
129
+ <workItem from="1655188201258" duration="26000" />
130
+ <workItem from="1655357894259" duration="3028000" />
131
+ <workItem from="1656644469354" duration="82000" />
132
+ <workItem from="1657611185486" duration="30768000" />
133
+ <workItem from="1657730101683" duration="5386000" />
119
134
  </task>
120
135
  <servers />
121
136
  </component>
package/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
1
  ## 更新日志
2
+ ### V1.0.3(2022-07-13)
3
+
4
+ 1、添加微信开发对话平台
5
+ 2、添加新闻分类事件
6
+ 3、
2
7
 
3
8
  ### V1.0.2(2022-02-21)
4
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wechaty-web-panel",
3
- "version": "1.0.3-beta.2",
3
+ "version": "1.0.4",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -36,12 +36,18 @@
36
36
  "eslint-config-prettier": "^6.11.0",
37
37
  "eslint-plugin-prettier": "^3.1.4",
38
38
  "prettier": "^2.0.5",
39
- "wechaty": "^1.13.12",
40
- "wechaty-puppet-wechat": "^1.11.12"
39
+ "wechaty": "^1.20.2",
40
+ "wechaty-puppet-wechat": "^1.18.4"
41
41
  },
42
42
  "readme": "README.md",
43
+ "engines": {
44
+ "node": ">=16",
45
+ "npm": ">=7"
46
+ },
43
47
  "dependencies": {
48
+ "axios": "^0.27.2",
44
49
  "ix": "^4.5.2",
50
+ "jsonwebtoken": "^8.5.1",
45
51
  "mqtt": "^4.2.6",
46
52
  "mustache": "^4.2.0",
47
53
  "nedb": "^1.8.0",
@@ -54,6 +60,6 @@
54
60
  "publishConfig": {
55
61
  "registry": " https://registry.npmjs.org/"
56
62
  },
57
- "_id": "wechaty-web-panel@1.0.3-beta.2",
58
- "_commitid": "e63a5b5"
63
+ "_id": "wechaty-web-panel@1.0.4",
64
+ "_commitid": "e9091a0"
59
65
  }
@@ -1,9 +1,10 @@
1
1
  const { getNews, getTXweather, getSweetWord } = require('../proxy/api')
2
- const { sendFriend, sendRoom, asyncData, getOne } = require('../proxy/aibotk')
2
+ const { sendFriend, sendRoom, asyncData, getOne, getMaterial } = require('../proxy/aibotk')
3
3
  const { getUser } = require('../common/userDb')
4
4
  const { formatDate, getDay, MD5, groupArray, delay } = require('../lib')
5
5
  const { UrlLink, MiniProgram } = require('wechaty')
6
6
  const { FileBox } = require('file-box')
7
+ const { allConfig } = require('../common/configDb')
7
8
  /**
8
9
  * 获取每日新闻内容
9
10
  * @param {*} sortId 新闻资讯分类Id
@@ -156,6 +157,12 @@ async function addRoomWelcomeSay(room, roomName, contactName, msg) {
156
157
  * @param {*} isRoom
157
158
  */
158
159
  async function roomSay(room, contact, msg) {
160
+ console.log('msg', msg)
161
+ const config = await allConfig()
162
+ const { role } = config.userInfo
163
+ if (msg.id && role === 'vip') {
164
+ msg = await getMaterial(msg.id)
165
+ }
159
166
  try {
160
167
  if (msg.type === 1 && msg.content) {
161
168
  // 文字
@@ -208,6 +215,12 @@ async function roomSay(room, contact, msg) {
208
215
  * type 1 文字 2 图片url 3 图片base64 4 url链接 5 小程序 6 名片
209
216
  */
210
217
  async function contactSay(contact, msg, isRoom = false) {
218
+ console.log('msg', msg)
219
+ const config = await allConfig()
220
+ const { role } = config.userInfo
221
+ if (msg.id && role === 'vip') {
222
+ msg = await getMaterial(msg.id)
223
+ }
211
224
  try {
212
225
  if (msg.type === 1 && msg.content) {
213
226
  // 文字
@@ -15,7 +15,7 @@ async function onFriend(friendship) {
15
15
  console.log(logMsg)
16
16
  if (config.autoAcceptFriend) {
17
17
  switch (friendship.type()) {
18
- case Friendship.Type.Receive:
18
+ case 2:
19
19
  if (config.acceptFriendKeyWords.length === 0) {
20
20
  console.log('无认证关键词,10秒后将会自动通过好友请求')
21
21
  await delay(10000)
@@ -28,10 +28,18 @@ async function onFriend(friendship) {
28
28
  console.log('未触发任何关键词,好友自动添加失败')
29
29
  }
30
30
  break
31
- case Friendship.Type.Confirm:
31
+ case 1:
32
32
  logMsg = '已确认添加好友:' + name
33
33
  console.log(logMsg)
34
34
  break
35
+ case 0:
36
+ logMsg = '未知错误' + name
37
+ console.log(logMsg)
38
+ break
39
+ case 3:
40
+ logMsg = '开启了验证' + name
41
+ console.log(logMsg)
42
+ break
35
43
  }
36
44
  } else {
37
45
  console.log('未开启自动添加好友功能,忽略好友添加')
package/src/lib/index.js CHANGED
@@ -233,6 +233,43 @@ function getConstellation(astro) {
233
233
  }
234
234
  }
235
235
 
236
+ /**
237
+ * 获取新闻的英文
238
+ * @param {*} msg
239
+ */
240
+ function getNewsType(msg) {
241
+ const NewsMap = {
242
+ '社会': 5,
243
+ '国内': 7,
244
+ '国际': 8,
245
+ '娱乐': 10,
246
+ '美女图片': 11,
247
+ '体育': 12,
248
+ '科技': 13,
249
+ '奇闻异事': 41,
250
+ '健康知识': 17,
251
+ '旅游': 18,
252
+ '汉服': 38,
253
+ '房产': 37,
254
+ '科学探索': 36,
255
+ '汽车': 35,
256
+ '互联网': 34,
257
+ '动漫': 33,
258
+ '财经': 32,
259
+ '游戏': 32,
260
+ 'CBA': 30,
261
+ '人工智能': 29,
262
+ '区块链': 28,
263
+ '军事': 27,
264
+ '足球': 26,
265
+ '创业': 24,
266
+ '移动互联': 23,
267
+ 'IT': 22,
268
+ 'VR科技': 21
269
+ }
270
+ return NewsMap[msg] || 7
271
+ }
272
+
236
273
  /**
237
274
  * 返回指定范围的随机整数
238
275
  * @param {*} min
@@ -608,4 +645,5 @@ module.exports = {
608
645
  groupArray,
609
646
  getRoomAvatarList,
610
647
  getRoomAvatar,
648
+ getNewsType
611
649
  }
@@ -55,7 +55,7 @@ async function getConfig() {
55
55
  }
56
56
  let content = await aiBotReq(option)
57
57
  const config = JSON.parse(content.data.config)
58
- let cres = await updateConfig(config)
58
+ let cres = await updateConfig({ puppetType: 'wechaty-puppet-wechat', ...config })
59
59
  return cres
60
60
  } catch (e) {
61
61
  console.log('获取配置文件失败:' + e)
@@ -372,6 +372,27 @@ async function getMqttConfig() {
372
372
  }
373
373
  }
374
374
 
375
+ /**
376
+ * 获取实时素材
377
+ * @param {*} version
378
+ */
379
+ async function getMaterial(id) {
380
+ try {
381
+ let option = {
382
+ method: 'GET',
383
+ url: '/wechat/material',
384
+ params: {
385
+ id,
386
+ },
387
+ }
388
+ let content = await aiBotReq(option)
389
+ console.log('素材', content.data)
390
+ return content.data
391
+ } catch (error) {
392
+ console.log('获取mqtt配置错误', error)
393
+ }
394
+ }
395
+
375
396
  module.exports = {
376
397
  getConfig,
377
398
  getScheduleList,
@@ -391,4 +412,5 @@ module.exports = {
391
412
  getMqttConfig,
392
413
  getMeiNv,
393
414
  getOne,
415
+ getMaterial,
394
416
  }
@@ -0,0 +1,222 @@
1
+ const jwt = require('jsonwebtoken')
2
+ const { allConfig } = require('../common/configDb')
3
+ const axios = require('axios')
4
+
5
+ async function getSignature(id, encodingAESKey) {
6
+ const token = jwt.sign(
7
+ {
8
+ userid: id,
9
+ },
10
+ encodingAESKey,
11
+ { algorithm: 'HS256' }
12
+ )
13
+ return token
14
+ }
15
+
16
+ function checkType(answer) {
17
+ var i = ''
18
+ i = '[object Object]' === Object.prototype.toString.call(answer) ? JSON.stringify(answer) : answer
19
+ var s = 'text'
20
+ return (
21
+ /{\s*"miniprogrampage"\s*:/.test(i)
22
+ ? (s = 'miniprogrampage')
23
+ : /{\s*"image"\s*:/.test(i)
24
+ ? (s = 'image')
25
+ : /{\s*"file"\s*:/.test(i)
26
+ ? (s = 'file')
27
+ : /{\s*"mpnews"\s*:/.test(i)
28
+ ? (s = 'mpnews')
29
+ : /{\s*"news"\s*:/.test(i)
30
+ ? (s = 'news')
31
+ : /{\s*"video"\s*:/.test(i)
32
+ ? (s = 'video')
33
+ : /{\s*"voice"\s*:/.test(i)
34
+ ? (s = 'voice')
35
+ : /{\s*"callback"\s*:/.test(i)
36
+ ? (s = 'callback')
37
+ : /weather_ans_detail/.test(i)
38
+ ? (s = 'weather')
39
+ : /{\s*"json"\s*:/.test(i)
40
+ ? (s = 'json')
41
+ : /^\[({.*:.*})*\]$/.test(i) && (s = 'nndialog'),
42
+ s
43
+ )
44
+ }
45
+
46
+ /**
47
+ * 判断是不是多个回复
48
+ * @param answer
49
+ * @returns {boolean}
50
+ */
51
+ function isMultiple(answer) {
52
+ return /{\s*"multimsg"\s*:/.test(answer)
53
+ }
54
+
55
+ /**
56
+ * 对多重回复的处理
57
+ * @param answer
58
+ */
59
+ function getMultiList(answer) {
60
+ const multiList = JSON.parse(answer).multimsg
61
+ const res = multiList.map(function (item, index) {
62
+ if ('[object Object]' === Object.prototype.toString.call(item)) {
63
+ return JSON.stringify(item)
64
+ } else {
65
+ return item
66
+ }
67
+ })
68
+ return res
69
+ }
70
+
71
+ /**
72
+ * 格式化开放平台回复内容
73
+ * @param answer
74
+ * @param options
75
+ * @param userInfo
76
+ * @returns {*[]}
77
+ */
78
+ function getFormatReply(answer, options = [], userInfo, puppetType) {
79
+ const answerType = checkType(answer)
80
+ if (answerType !== 'text') {
81
+ answer = JSON.parse(answer)
82
+ }
83
+ let replys = []
84
+ let reply = {}
85
+ switch (answerType) {
86
+ case 'text':
87
+ reply = {
88
+ type: 1,
89
+ content: answer,
90
+ }
91
+ if (options && options.length) {
92
+ options.forEach((item) => {
93
+ reply.content = reply.content + '(请输入完整的文字和序号,可以拷贝)\n' + item.title
94
+ })
95
+ }
96
+ replys = [reply]
97
+ break
98
+ case 'image':
99
+ if (Array.isArray(answer.image)) {
100
+ replys = answer.image.map((item) => {
101
+ return {
102
+ type: 2,
103
+ url: item.image.url,
104
+ }
105
+ })
106
+ break
107
+ } else {
108
+ replys = [{ type: 2, url: answer.image.url }]
109
+ break
110
+ }
111
+ case 'video':
112
+ if (answer.video && (answer.video.url || answer.video.cover_url)) {
113
+ replys = [{ type: 2, url: answer.video.url ? answer.video.url : answer.video.cover_url }]
114
+ break
115
+ }
116
+ break
117
+ case 'news':
118
+ if (puppetType === 'wechaty-puppet-wechat') {
119
+ replys = [
120
+ { type: 1, content: `【标题】${answer.news.articles[0].title}\n【描述】${answer.news.articles[0].description}\n【访问地址】${answer.news.articles[0].url}\n 【缩略图】正在路上...` },
121
+ { type: 2, url: answer.news.articles[0].picurl },
122
+ ]
123
+ } else {
124
+ replys = [{ type: 4, url: answer.news.articles[0].url, title: answer.news.articles[0].title, thumbnailUrl: answer.news.articles[0].picurl, description: answer.news.articles[0].description }]
125
+ }
126
+ break
127
+ case 'mpnews':
128
+ replys = [
129
+ { type: 1, content: `【标题】${answer.mpnews.title}\n【内容】${answer.mpnews.digest}\n【缩略图】正在路上...` },
130
+ { type: 2, url: answer.mpnews.imgurl },
131
+ ]
132
+ break
133
+ case 'voice':
134
+ if (answer.voice && answer.voice.url) {
135
+ replys = [{ type: 2, url: answer.voice.url }]
136
+ break
137
+ }
138
+ break
139
+ case 'json':
140
+ if (answer.json) {
141
+ replys = [{ type: 1, content: JSON.stringify(answer.json) }]
142
+ break
143
+ }
144
+ break
145
+ case 'miniprogrampage':
146
+ if (puppetType === 'wechaty-puppet-wechat') {
147
+ replys = [{ type: 1, content: '收到了一个小程序,但是小秘书还没学会展示😭,等等我回去再修炼五百年💪' }]
148
+ } else {
149
+ replys = [{ type: 5, appid: answer.miniprogrampage.appid, title: answer.miniprogrampage.title, pagePath: answer.miniprogrampage.pagepath, description: answer.miniprogrampage.title, thumbUrl: answer.miniprogrampage.thumb_url, thumbKey: undefined, username: userInfo.name }]
150
+ }
151
+ break
152
+ default:
153
+ break
154
+ }
155
+ return replys
156
+ }
157
+
158
+ async function getTencentOpenReply({ msg, id, userInfo }) {
159
+ const config = await allConfig()
160
+ try {
161
+ const signature = await getSignature(id, config.tencentAESKey)
162
+ const data = {
163
+ signature,
164
+ query: msg,
165
+ }
166
+ const res = await axios.post(`https://openai.weixin.qq.com/openapi/aibot/eTZV8kYIvKnmvQJgXsy7e7f3WDWeGf`, data, {})
167
+ const resData = res.data
168
+ if (!resData.errcode) {
169
+ let answer = resData.answer // 存放回答
170
+ if (resData.answer_type === 'text') {
171
+ if (isMultiple(answer)) {
172
+ const multiList = getMultiList(answer)
173
+ const replys = []
174
+ multiList.forEach((item) => {
175
+ item = item.replace(/<\/?.+?\/?>/g, '')
176
+ console.log('item', item)
177
+ const reply = getFormatReply(item, resData.options || [], userInfo, config.puppetType)
178
+ console.log('reply', reply)
179
+ replys.push(...reply)
180
+ })
181
+ return replys
182
+ } else {
183
+ const replys = getFormatReply(answer, resData.options, userInfo, config.puppetType)
184
+ return replys
185
+ }
186
+ } else if (resData.answer_type === 'music') {
187
+ // web 端协议以文字和图片的形式发送
188
+ if (config.puppetType === 'wechaty-puppet-wechat') {
189
+ const music = resData.msg[0]
190
+ const musicContent = `【歌名】:《${music && music.song_name}》\n【歌手】:${music && music.singer_name}\n【听歌地址】:${music && music.music_url}`
191
+ const musicPic = music && music.pic_url
192
+ return [
193
+ {
194
+ type: 1,
195
+ content: resData.answer + '\n\n' + musicContent,
196
+ },
197
+ {
198
+ type: 2,
199
+ url: musicPic,
200
+ },
201
+ ]
202
+ } else {
203
+ // 其他协议可以发链接的用H5卡片发送
204
+ const music = resData.msg[0]
205
+ return [
206
+ {
207
+ type: 1,
208
+ content: resData.answer,
209
+ },
210
+ { type: 4, url: music.music_url, title: music.song_name, thumbnailUrl: music.pic_url, description: music.singer_name },
211
+ ]
212
+ }
213
+ }
214
+ }
215
+ } catch (e) {
216
+ console.log('error', e)
217
+ }
218
+ }
219
+
220
+ module.exports = {
221
+ getTencentOpenReply,
222
+ }
@@ -1,10 +1,11 @@
1
1
  const api = require('../proxy/api')
2
2
  const { getConfig, getRoomPhotoConfig, getMeiNv } = require('../proxy/aibotk')
3
- const { getConstellation, msgArr, getAllSchedule, getRoomAvatar } = require('../lib')
3
+ const { getConstellation, msgArr, getAllSchedule, getRoomAvatar, getNewsType } = require('../lib')
4
4
  const { generateAvatar, generateRoomImg } = require('../puppeteer-paint/lanuch')
5
5
  const { initTaskLocalSchedule } = require('../task/index')
6
6
  const { updateContactAndRoom, updateContactOnly, updateRoomOnly } = require('../common/index')
7
7
  const { chatTencent } = require('../proxy/tencent')
8
+ const { getTencentOpenReply } = require('../proxy/tencent-open')
8
9
  /**
9
10
  * 根据事件名称分配不同的api处理,并获取返回内容
10
11
  * @param {string} eName 事件名称
@@ -33,6 +34,10 @@ async function dispatchEventContent(that, eName, msg, name, id, avatar, room) {
33
34
  let xing = getConstellation(msg)
34
35
  content = await api.getStar(xing)
35
36
  break
37
+ case 'news':
38
+ let newsId = getNewsType(msg)
39
+ content = await api.getNews(newsId)
40
+ break
36
41
  case 'xing':
37
42
  content = await api.getXing(msg)
38
43
  break
@@ -134,25 +139,38 @@ async function dispatchEventContent(that, eName, msg, name, id, avatar, room) {
134
139
  */
135
140
  async function dispatchAiBot(bot, msg, name, id) {
136
141
  try {
137
- let res
142
+ let res, replys
138
143
  switch (bot) {
139
144
  case 0:
145
+ // 天行机器人
140
146
  res = await api.getResByTX(msg, id)
147
+ replys = [{ type: 1, res }]
141
148
  break
142
149
  case 1:
150
+ // 天行图灵机器人
143
151
  res = await api.getResByTXTL(msg, id)
152
+ replys = [{ type: 1, res }]
144
153
  break
145
154
  case 2:
155
+ // 图灵机器人
146
156
  res = await api.getResByTL(msg, id)
157
+ replys = [{ type: 1, res }]
147
158
  break
148
159
  case 3:
160
+ // 微信闲聊
149
161
  res = await chatTencent(msg, id)
162
+ replys = [{ type: 1, res }]
163
+ break
164
+ case 5:
165
+ // 微信开放对话平台
166
+ res = await getTencentOpenReply({ msg, id, userInfo: { name } })
167
+ replys = res
150
168
  break
151
169
  default:
152
- res = ''
170
+ replys = [{ type: 1, content: '' }]
153
171
  break
154
172
  }
155
- return res
173
+ return replys
156
174
  } catch (e) {
157
175
  console.log('机器人接口信息获取失败', e)
158
176
  return ''
@@ -176,17 +176,13 @@ async function keywordsMsg({ msg, config }) {
176
176
  async function robotMsg({ msg, name, id, config }) {
177
177
  try {
178
178
  let msgArr = [] // 返回的消息列表
179
- let obj = { type: 1, content: '', url: '' } // 消息主体
180
179
  if (config.autoReply) {
181
180
  console.log('开启了机器人自动回复功能')
182
- obj.type = 1
183
- obj.content = await dispatch.dispatchAiBot(config.defaultBot, msg, name, id)
181
+ msgArr = await dispatch.dispatchAiBot(config.defaultBot, msg, name, id)
184
182
  } else {
185
183
  console.log('没有开启机器人自动回复功能')
186
- obj.type = 1
187
- obj.content = ''
184
+ msgArr = [{ type: 1, content: '', url: '' }]
188
185
  }
189
- msgArr.push(obj)
190
186
  return msgArr
191
187
  } catch (e) {
192
188
  console.log('robotMsg error:', e)