把我的老鐵機器人的顏值鑑定接口源碼放出來,邏輯都在execute函數裏面,看不懂也不解釋了。
const sharp = require('sharp')
const _ = require('lodash')
const { sendMsg, Recent, localPic } = require('../qq_api')
const { rp, UA, auraCdChk, num } = require('../utils')
module.exports = {
name: '顏值',
tags: ['exec', 'aura', 'group', 'cd'],
keywords: ['好看嗎'],
usage: ['(發照片後) [botNick_]顏值鑑定', '我好看嗎?', '@某用户 好看嗎'],
value: { 冷卻時間: { def: '20秒', chk: auraCdChk } },
help: '給照片中人物的顏值打分。AT某用户可鑑定他/她的頭像,發送“我好看嗎”則鑑定自己的頭像。\n☍ 數據接口:微軟小冰 https://ux.xiaoice.com/beautyv3',
execute: async ({ name, bot, user, msg: { content: cont, ats = [], pics: [pic] = [] }, g }) => {
cont = cont.replace(/(鑑定|的|\?|?)/, '')
if (cont === '我' || ats.length) {
const q = cont === '我' ? user : ats[0]
pic = { url: `http://q1.qlogo.cn/g?b=qq&nk=${q}&s=640` }
} else if (!pic) {
pic = await Recent.get('pic', user, g)
if (!pic) { // 需要補發照片
Recent.set('cmd', user, g, name)
return sendMsg(bot, g, user, '[at]顏值鑑定需要你提供包含人臉的照片,請在20秒內發出'), 'WAITING_PIC' // eslint-disable-line
}
Recent.del('pic', user, g)
}
;(async () => { // 異步執行,避免指令執行時間過長
try {
const opts = {
jar: rp.jar(),
headers: { 'User-Agent': UA }
}
let [res, buf] = await Promise.all([
rp.head('https://ux.xiaoice.com/beautyv3', opts), // 小冰顏值首頁,訪問此頁面僅用於填充cookies,HEAD比GET速度更快
rp.get(pic.url, { encoding: null })]) // 獲取圖像數據
// 從cookies中提取TraceId參數
const TraceId = JSON.parse(decodeURIComponent(opts.jar.getCookies('http://ux.xiaoice.com').find(c => c.key === 'logInfo').value)).tid
// 對非動畫gif,大於200K或大於30萬像素的,則縮小至30萬像素以節省流量
const img = sharp(buf)
const { format, width, height } = await img.metadata()
if (format !== 'gif' && ((buf.length > 200000) || width * height > 300000)) {
const nw = ~~Math.sqrt(width * 300000 / height)
if (nw < width) buf = await img.resize(nw).jpeg({ quality: 75, chromaSubsampling: '4:2:0' }).toBuffer()
}
// base64方式上傳圖片
_.merge(opts, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded', Referer: 'https://ux.xiaoice.com/beautyv3' },
body: buf.toString('base64')
})
res = await rp.post('https://ux.xiaoice.com/api/image/UploadBase64?exp=1', opts)
res = JSON.parse(res) // 應答體JSON格式,包含上傳後的圖片host和uri
const MsgId = Date.now()
// 調用顏值鑑定接口,一般需要10秒以上,需設定較長的超時時間
_.merge(opts, {
json: true,
timeout: 45000,
headers: { 'Content-Type': 'application/json' },
body: { MsgId, CreateTime: ~~(MsgId / 1000), TraceId, Content: { imageUrl: res.Host + res.Url } }
})
res = await rp.post('https://ux.xiaoice.com/api/imageAnalyze/Process?service=beauty', opts)
// 成功獲取到鑑定結果
const { imageUrl, metadata, text } = res.content
let txt = text
if (metadata.score) {
txt = `👆上面${{ male: '帥哥', female: '美女' }[metadata.gender]}的顏值有${metadata.score}分!👏`
if (metadata.FBR_Cnt) {
const fbr = Object.entries(metadata).reduce((o, [k, v]) => {
const mch = /^FBR_(Key|Score)(\d+)$/.exec(k)
if (mch) (o[+mch[2]] = o[+mch[2]] || {})[mch[1]] = v
return o
}, [])
txt += `\n評分詳情:\n${num(fbr.map(f => `${f.Key}:${f.Score}分`)).join('\n')}`
}
txt += `\n⭐${text}`
if (metadata.Comment_Improve) txt += `\n💡${metadata.Comment_Improve}`
}
const lpic = await localPic(imageUrl)
sendMsg(bot, g, user, txt, lpic)
} catch (e) {
sendMsg(bot, g, user, `[at]顏值鑑定失敗,錯誤:${e.message}`)
}
})()
return sendMsg(bot, g, user, `[at]正在鑑定顏值,大約需要20~30秒,請稍候`), 'OK' // eslint-disable-line
}
}