From 0f9c8a7abee2bbab76fe5f07c15a62e7f5bf8588 Mon Sep 17 00:00:00 2001 From: HalcyonAlcedo <41666148+HalcyonAlcedo@users.noreply.github.com> Date: Sun, 8 Oct 2023 21:37:43 +0800 Subject: [PATCH 01/47] =?UTF-8?q?=E9=80=82=E9=85=8DTrss=20(#575)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复星火api上下文 * 将无星火ck的情况降低为warn * feat: 添加星火设定自定义代码功能 * 修复星火api模式的一些问题 * 修复导出配置问题 * feat:添加工具箱快捷登录接口 * 添加工具箱快捷登录指令 * 阻止群聊使用快捷登录 * 添加Azure配置支持,修复重复的配置项冲突 * 移除旧版本渲染和新版本帮助 * 添加工具箱 * 更新工具箱替换原有后台 * 更新工具箱适配代码 * 后台适配Trss * 修复trss不支持sendPrivateMsg的问题 * 优化路由 * 修复路由 * 适配其他uin --- apps/chat.js | 16 +++++++-------- apps/history.js | 6 +++--- apps/prompts.js | 6 +++--- resources/view/setting_view.json | 6 ++++++ server/index.js | 34 ++++++++++++++++++++------------ server/modules/user.js | 16 +++++++++------ server/modules/web_route.js | 8 ++++++++ utils/common.js | 12 +++++++++-- utils/config.js | 2 ++ utils/uploadRecord.js | 4 ++-- 10 files changed, 73 insertions(+), 37 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index 864279f..ff14e93 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -25,7 +25,7 @@ import { getUserReplySetting, getImageOcrText, getImg, - getMaxModelTokens, formatDate, generateAudio, formatDate2, mkdirs + getMaxModelTokens, formatDate, generateAudio, formatDate2, mkdirs, getUin } from '../utils/common.js' import { ChatGPTPuppeteer } from '../utils/browser.js' import { KeyvFile } from 'keyv-file' @@ -315,7 +315,7 @@ export class chatgpt extends plugin { } let ats = e.message.filter(m => m.type === 'at') const isAtMode = Config.toggleMode === 'at' - if (isAtMode) ats = ats.filter(item => item.qq !== Bot.uin) + if (isAtMode) ats = ats.filter(item => item.qq !== getUin(e)) if (ats.length === 0) { if (use === 'api3') { await redis.del(`CHATGPT:QQ_CONVERSATION:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`) @@ -764,11 +764,11 @@ export class chatgpt extends plugin { if (e.isGroup && !e.atme) { return false } - if (e.user_id == Bot.uin) return false + if (e.user_id == getUin(e)) return false prompt = e.raw_message.trim() if (e.isGroup && typeof this.e.group.getMemberMap === 'function') { let mm = await this.e.group.getMemberMap() - let me = mm.get(Bot.uin) + let me = mm.get(getUin(e)) let card = me.card let nickname = me.nickname if (nickname && card) { @@ -1477,7 +1477,7 @@ export class chatgpt extends plugin { chatViewBotName: Config.chatViewBotName || '', entry: cacheData.file, userImg: `https://q1.qlogo.cn/g?b=qq&s=0&nk=${e.sender.user_id}`, - botImg: `https://q1.qlogo.cn/g?b=qq&s=0&nk=${Bot.uin}`, + botImg: `https://q1.qlogo.cn/g?b=qq&s=0&nk=${getUin(e)}`, cacheHost: Config.serverHost, qq: e.sender.user_id }) @@ -1586,7 +1586,7 @@ export class chatgpt extends plugin { opt.qq = e.sender.user_id opt.nickname = e.sender.card opt.groupName = e.group.name - opt.botName = e.isGroup ? (e.group.pickMember(Bot.uin).card || e.group.pickMember(Bot.uin).nickname) : Bot.nickname + opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : Bot.nickname let master = (await getMasterQQ())[0] if (master && e.group) { opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname @@ -2019,7 +2019,7 @@ export class chatgpt extends plugin { opt.qq = e.sender.user_id opt.nickname = e.sender.card opt.groupName = e.group.name - opt.botName = e.isGroup ? (e.group.pickMember(Bot.uin).card || e.group.pickMember(Bot.uin).nickname) : Bot.nickname + opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : Bot.nickname let master = (await getMasterQQ())[0] if (master && e.group) { opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname @@ -2191,7 +2191,7 @@ export class chatgpt extends plugin { logger.mark(logger.green('【ChatGPT-Plugin】插件avocado-plugin未安装') + ',安装后可查看最近热映电影与体验可玩性更高的点歌工具。\n可前往 https://github.com/Qz-Sean/avocado-plugin 获取') } if (e.isGroup) { - let botInfo = await Bot.getGroupMemberInfo(e.group_id, Bot.uin, true) + let botInfo = await Bot.getGroupMemberInfo(e.group_id, getUin(e), true) if (botInfo.role !== 'member') { // 管理员才给这些工具 tools.push(...[new EditCardTool(), new JinyanTool(), new KickOutTool(), new HandleMessageMsgTool(), new SetTitleTool()]) diff --git a/apps/history.js b/apps/history.js index 3c27859..5f6d5f2 100644 --- a/apps/history.js +++ b/apps/history.js @@ -1,5 +1,5 @@ import plugin from '../../../lib/plugins/plugin.js' -import { render } from '../utils/common.js' +import { render, getUin } from '../utils/common.js' import { Config } from '../utils/config.js' import { KeyvFile } from 'keyv-file' @@ -32,7 +32,7 @@ export class history extends plugin { async history (e) { let use = await redis.get('CHATGPT:USE') || 'api' let chat = [] - let filtered = e.message.filter(m => m.type === 'at').filter(m => m.qq !== Bot.uin) + let filtered = e.message.filter(m => m.type === 'at').filter(m => m.qq !== getUin(e)) let queryUser = e.sender.user_id let user = e.sender if (filtered.length > 0) { @@ -99,7 +99,7 @@ export class history extends plugin { name: user.card || user.nickname || user.user_id }, bot: { - qq: Bot.uin, + qq: getUin(e), name: Bot.nickname }, chat diff --git a/apps/prompts.js b/apps/prompts.js index 5d4d173..3b5098c 100644 --- a/apps/prompts.js +++ b/apps/prompts.js @@ -2,7 +2,7 @@ import plugin from '../../../lib/plugins/plugin.js' import fs from 'fs' import _ from 'lodash' import { Config } from '../utils/config.js' -import { getMasterQQ, limitString, makeForwardMsg, maskQQ } from '../utils/common.js' +import { getMasterQQ, limitString, makeForwardMsg, maskQQ, getUin } from '../utils/common.js' import { deleteOnePrompt, getPromptByName, readPrompts, saveOnePrompt } from '../utils/prompts.js' import AzureTTS from "../utils/tts/microsoft-azure.js"; export class help extends plugin { @@ -246,7 +246,7 @@ export class help extends plugin { async removeSharePrompt (e) { let master = (await getMasterQQ())[0] let name = e.msg.replace(/^#(chatgpt|ChatGPT)(删除|取消|撤销)共享设定/, '') - let response = await fetch(`https://chatgpt.roki.best/prompt?name=${name}&qq=${master || (Bot.uin + '')}`, { + let response = await fetch(`https://chatgpt.roki.best/prompt?name=${name}&qq=${master || (getUin(e) + '')}`, { method: 'DELETE', headers: { 'FROM-CHATGPT': 'ikechan8370' @@ -354,7 +354,7 @@ export class help extends plugin { let toUploadBody = { title: currentUse, prompt: content, - qq: master || (Bot.uin + ''), // 上传者设定为主人qq或机器人qq + qq: master || (getUin(this.e) + ''), // 上传者设定为主人qq或机器人qq use: extraData.use === 'Custom' ? 'Sydney' : 'ChatGPT', r18, description diff --git a/resources/view/setting_view.json b/resources/view/setting_view.json index 66aac7f..9aa8063 100644 --- a/resources/view/setting_view.json +++ b/resources/view/setting_view.json @@ -122,6 +122,12 @@ "label": "额外工具url", "placeholder": "测试期间提供一个公益接口,一段时间后撤掉", "data": "extraUrl" + }, + { + "type": "text", + "label": "Trss主账号", + "placeholder": "用于Trss配置脚本时使用的主账号", + "data": "trssBotUin" } ] }, diff --git a/server/index.js b/server/index.js index d3e46ee..3651d1d 100644 --- a/server/index.js +++ b/server/index.js @@ -12,7 +12,7 @@ import websocketclient from 'ws' import { Config } from '../utils/config.js' import { UserInfo, GetUser, AddUser } from './modules/user_data.js' -import { getPublicIP, getUserData, getMasterQQ, randomString } from '../utils/common.js' +import { getPublicIP, getUserData, getMasterQQ, randomString, getUin } from '../utils/common.js' import webRoute from './modules/web_route.js' import webUser from './modules/user.js' @@ -107,7 +107,7 @@ async function mediaLink() { ws.on('open', () => { ws.send(JSON.stringify({ command: 'register', - region: Bot.uin, + region: getUin(), type: 'server', })) }) @@ -118,7 +118,11 @@ async function mediaLink() { case 'register': if (data.state) { let master = (await getMasterQQ())[0] - Bot.sendPrivateMsg(master, `当前chatgpt插件服务无法被外网访问,已启用代理链接,访问代码:${data.token}`, false) + if (Array.isArray(Bot.uin)) { + Bot.pickFriend(master).sendMsg(`当前chatgpt插件服务无法被外网访问,已启用代理链接,访问代码:${data.token}`) + } else { + Bot.sendPrivateMsg(master, `当前chatgpt插件服务无法被外网访问,已启用代理链接,访问代码:${data.token}`, false) + } } else { console.log('注册区域失败') } @@ -128,30 +132,30 @@ async function mediaLink() { const user = UserInfo(data.token) if (user) { ws.login = true - ws.send(JSON.stringify({ command: data.command, state: true, region: Bot.uin, type: 'server' })) + ws.send(JSON.stringify({ command: data.command, state: true, region: getUin(), type: 'server' })) } else { - ws.send(JSON.stringify({ command: data.command, state: false, error: '权限验证失败', region: Bot.uin, type: 'server' })) + ws.send(JSON.stringify({ command: data.command, state: false, error: '权限验证失败', region: getUin(), type: 'server' })) } } break case 'post_login': if (data.qq && data.passwd) { const token = randomString(32) - if (data.qq == Bot.uin && await redis.get('CHATGPT:ADMIN_PASSWD') == data.passwd) { + if (data.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == data.passwd) { AddUser({ user: data.qq, token: token, autho: 'admin' }) - ws.send(JSON.stringify({ command: data.command, state: true, autho: 'admin', token: token, region: Bot.uin, type: 'server' })) + ws.send(JSON.stringify({ command: data.command, state: true, autho: 'admin', token: token, region: getUin(), type: 'server' })) } else { const user = await getUserData(data.qq) if (user.passwd != '' && user.passwd === data.passwd) { AddUser({ user: data.qq, token: token, autho: 'user' }) - ws.send(JSON.stringify({ command: data.command, state: true, autho: 'user', token: token, region: Bot.uin, type: 'server' })) + ws.send(JSON.stringify({ command: data.command, state: true, autho: 'user', token: token, region: getUin(), type: 'server' })) } else { - ws.send(JSON.stringify({ command: data.command, state: false, error: `用户名密码错误,如果忘记密码请私聊机器人输入 ${data.qq == Bot.uin ? '#修改管理密码' : '#修改用户密码'} 进行修改`, region: Bot.uin, type: 'server' })) + ws.send(JSON.stringify({ command: data.command, state: false, error: `用户名密码错误,如果忘记密码请私聊机器人输入 ${data.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改`, region: getUin(), type: 'server' })) } } } else { - ws.send(JSON.stringify({ command: data.command, state: false, error: '未输入用户名或密码', region: Bot.uin, type: 'server' })) + ws.send(JSON.stringify({ command: data.command, state: false, error: '未输入用户名或密码', region: getUin(), type: 'server' })) } break case 'post_command': @@ -163,7 +167,7 @@ async function mediaLink() { const response = await fetch(`http://localhost:${Config.serverPort || 3321}${data.postPath}`, fetchOptions) if (response.ok) { const json = await response.json() - ws.send(JSON.stringify({ command: data.command, state: true, region: Bot.uin, type: 'server', path: data.postPath, data: json })) + ws.send(JSON.stringify({ command: data.command, state: true, region: getUin(), type: 'server', path: data.postPath, data: json })) } break } @@ -189,7 +193,7 @@ export async function createServer() { if (body.code) { const pattern = /^[a-zA-Z0-9]+$/ if (!pattern.test(body.code)) { - reply.send({error: 'bad request'}) + reply.send({ error: 'bad request' }) } const dir = 'resources/ChatGPTCache/page' const filename = body.code + '.json' @@ -342,7 +346,11 @@ export async function createServer() { if (data.group) { Bot.sendGroupMsg(parseInt(data.id), data.message, data.quotable) } else { - Bot.sendPrivateMsg(parseInt(data.id), data.message, data.quotable) + if (Array.isArray(Bot.uin)) { + Bot.pickFriend(parseInt(data.id)).sendMsg(data.message) + } else { + Bot.sendPrivateMsg(parseInt(data.id), data.message, data.quotable) + } } await connection.socket.send(JSON.stringify({ command: data.command, state: true, })) } else { diff --git a/server/modules/user.js b/server/modules/user.js index bc15482..7458805 100644 --- a/server/modules/user.js +++ b/server/modules/user.js @@ -1,5 +1,5 @@ import { UserInfo, AddUser } from './user_data.js' -import { randomString, getUserData, getMasterQQ } from '../../utils/common.js' +import { randomString, getUserData, getMasterQQ, getUin } from '../../utils/common.js' import fs from 'fs' async function User(fastify, options) { @@ -8,7 +8,7 @@ async function User(fastify, options) { const body = request.body || {} if (body.qq && body.passwd) { const token = randomString(32) - if (body.qq == Bot.uin && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) { + if (body.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) { AddUser({ user: body.qq, token: token, autho: 'admin' }) reply.setCookie('token', token, { path: '/' }) reply.send({ login: true, autho: 'admin', token: token }) @@ -19,16 +19,16 @@ async function User(fastify, options) { reply.setCookie('token', token, { path: '/' }) reply.send({ login: true, autho: 'user', token: token }) } else { - reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == Bot.uin ? '#修改管理密码' : '#修改用户密码'} 进行修改` }) + reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改` }) } } } else if (body.otp) { const token = randomString(32) const opt = await redis.get(`CHATGPT:SERVER_QUICK`) if (opt && body.otp == opt) { - AddUser({ user: Bot.uin, token: token, autho: 'admin' }) + AddUser({ user: getUin(), token: token, autho: 'admin' }) reply.setCookie('token', token, { path: '/' }) - reply.send({ login: true, autho: 'admin', token: token, user: Bot.uin }) + reply.send({ login: true, autho: 'admin', token: token, user: getUin() }) } else { reply.send({ login: false, err: `快捷登录代码错误,请检查后重试` }) } @@ -46,7 +46,11 @@ async function User(fastify, options) { { EX: 60000 } ) const master = (await getMasterQQ())[0] - Bot.sendPrivateMsg(master, `收到工具箱快捷登录请求,1分钟内有效:${otp}`, false) + if (Array.isArray(Bot.uin)) { + Bot.pickFriend(master).sendMsg(`收到工具箱快捷登录请求,1分钟内有效:${otp}`) + } else { + Bot.sendPrivateMsg(master, `收到工具箱快捷登录请求,1分钟内有效:${otp}`, false) + } reply.send({ state: true }) return reply }) diff --git a/server/modules/web_route.js b/server/modules/web_route.js index 90bc9dc..e5f1d24 100644 --- a/server/modules/web_route.js +++ b/server/modules/web_route.js @@ -50,6 +50,14 @@ async function routes(fastify, options) { reply.type('text/html').send(stream) return reply }) + fastify.setNotFoundHandler((request, reply) => { + if (request.method == 'GET') { + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + } else { + reply.code(404).send(new Error('Not Found')) + } + }) } export default routes \ No newline at end of file diff --git a/utils/common.js b/utils/common.js index b25e51d..62181c8 100644 --- a/utils/common.js +++ b/utils/common.js @@ -84,14 +84,14 @@ export async function makeForwardMsg (e, msg = [], dec = '') { let nickname = Bot.nickname if (e.isGroup) { try { - let info = await Bot.getGroupMemberInfo(e.group_id, Bot.uin) + let info = await Bot.getGroupMemberInfo(e.group_id, getUin(e)) nickname = info.card || info.nickname } catch (err) { console.error(`Failed to get group member info: ${err}`) } } let userInfo = { - user_id: Bot.uin, + user_id: getUin(e), nickname } @@ -821,6 +821,14 @@ export function getMaxModelTokens (model = 'gpt-3.5-turbo') { } } +export function getUin (e) { + if (e?.bot?.uin) return e.bot.uin + if (Array.isArray(Bot.uin)) { + if (Config.trssBotUin && Bot.uin.indexOf(Config.trssBotUin) > -1) return Config.trssBotUin + else return Bot.uin[0] + } else return Bot.uin +} + /** * 生成当前语音模式下可发送的音频信息 * @param e - 上下文对象 diff --git a/utils/config.js b/utils/config.js index c3ae38d..c7f9bfd 100644 --- a/utils/config.js +++ b/utils/config.js @@ -151,6 +151,8 @@ const defaultConfig = { claudeAITimeout: 120, claudeAIJA3: '772,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,27-5-65281-13-35-0-51-18-16-43-10-45-11-17513-23,29-23-24,0', claudeAIUA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', + // trss配置 + trssBotUin: '', version: 'v2.7.5' } const _path = process.cwd() diff --git a/utils/uploadRecord.js b/utils/uploadRecord.js index f26f419..98d650b 100644 --- a/utils/uploadRecord.js +++ b/utils/uploadRecord.js @@ -9,7 +9,7 @@ import crypto from 'crypto' import child_process from 'child_process' import { Config } from './config.js' import path from 'path' -import { mkdirs } from './common.js' +import { mkdirs, getUin } from './common.js' let module try { module = await import('oicq') @@ -139,7 +139,7 @@ async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') { 2: 3, 5: { 1: Contactable.target, - 2: Bot.uin, + 2: getUin(e), 3: 0, 4: hash, 5: buf.length, From e574681ad1326e72a05e3518d155e439bc1f9a9f Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sun, 8 Oct 2023 21:50:30 +0800 Subject: [PATCH 02/47] =?UTF-8?q?fix:=20=E9=BB=98=E8=AE=A4=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E8=BD=AC=E4=B8=BASydney=E9=81=BF=E5=85=8D=E6=96=B0?= =?UTF-8?q?=E8=A3=85=E7=9B=B4=E6=8E=A5200?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/config.js b/utils/config.js index c7f9bfd..91fd596 100644 --- a/utils/config.js +++ b/utils/config.js @@ -30,7 +30,7 @@ const defaultConfig = { drawCD: 30, model: '', temperature: 0.8, - toneStyle: 'balanced', // or creative, precise + toneStyle: 'Sydney', // or creative, precise sydney: pureSydneyInstruction, sydneyReverseProxy: 'https://666102.201666.xyz', sydneyForceUseReverse: false, From 0f310a8ff38df7fb9ce696d1a409235e328d6bab Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sun, 8 Oct 2023 21:52:04 +0800 Subject: [PATCH 03/47] =?UTF-8?q?fix:=20=E5=AF=B9=E8=AF=9D=E5=8F=8D?= =?UTF-8?q?=E4=BB=A3=E9=BB=98=E8=AE=A4=E5=BC=80=E5=90=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/config.js b/utils/config.js index 91fd596..cfb7e6a 100644 --- a/utils/config.js +++ b/utils/config.js @@ -34,7 +34,7 @@ const defaultConfig = { sydney: pureSydneyInstruction, sydneyReverseProxy: 'https://666102.201666.xyz', sydneyForceUseReverse: false, - sydneyWebsocketUseProxy: false, + sydneyWebsocketUseProxy: true, sydneyBrainWash: true, sydneyBrainWashStrength: 15, sydneyBrainWashName: 'Sydney', From ae58a20cc2d8e2711390e82404f1117271726d8f Mon Sep 17 00:00:00 2001 From: HalcyonAlcedo <41666148+HalcyonAlcedo@users.noreply.github.com> Date: Fri, 13 Oct 2023 19:48:08 +0800 Subject: [PATCH 04/47] =?UTF-8?q?=E6=B7=BB=E5=8A=A0bing=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E7=BB=98=E5=9B=BE=20(#580)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复星火api上下文 * 将无星火ck的情况降低为warn * feat: 添加星火设定自定义代码功能 * 修复星火api模式的一些问题 * 修复导出配置问题 * feat:添加工具箱快捷登录接口 * 添加工具箱快捷登录指令 * 阻止群聊使用快捷登录 * 添加Azure配置支持,修复重复的配置项冲突 * 移除旧版本渲染和新版本帮助 * 添加工具箱 * 更新工具箱替换原有后台 * 更新工具箱适配代码 * 后台适配Trss * 修复trss不支持sendPrivateMsg的问题 * 优化路由 * 修复路由 * 适配其他uin * 添加bing第三方绘图 * 修复bing绘图第三方调用错误 * 添加bing第三方绘图采样配置 * 修复错误 * 添加bing第三方绘图图片大小配置 * 修复视图错误 * 使用ap替换第三方绘图 * 适配trss --- apps/chat.js | 50 ++++++++++++++++++-------------- resources/view/setting_view.json | 6 ++++ utils/config.js | 1 + 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index ff14e93..1bea8a3 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -548,7 +548,7 @@ export class chatgpt extends plugin { await this.reply('本功能当前仅支持API3模式', true) return false } - if (ats.length === 0 || (ats.length === 1 && e.atme)) { + if (ats.length === 0 || (ats.length === 1 && (e.atme || e.atBot))) { let conversationId = _.trimStart(e.msg, '#chatgpt删除对话').trim() if (!conversationId) { await this.reply('指令格式错误,请同时加上对话id或@某人以删除他当前进行的对话', true) @@ -761,14 +761,14 @@ export class chatgpt extends plugin { if (!e.raw_message || e.msg?.startsWith('#')) { return false } - if (e.isGroup && !e.atme) { + if (e.isGroup && !(e.atme || e.atBot)) { return false } if (e.user_id == getUin(e)) return false prompt = e.raw_message.trim() if (e.isGroup && typeof this.e.group.getMemberMap === 'function') { let mm = await this.e.group.getMemberMap() - let me = mm.get(getUin(e)) + let me = mm.get(getUin(e)) || {} let card = me.card let nickname = me.nickname if (nickname && card) { @@ -797,7 +797,7 @@ export class chatgpt extends plugin { } } else { let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#chat') } @@ -1324,7 +1324,7 @@ export class chatgpt extends plugin { return false } let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#chat1') } @@ -1343,7 +1343,7 @@ export class chatgpt extends plugin { return false } let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#chat3') } @@ -1362,7 +1362,7 @@ export class chatgpt extends plugin { return false } let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#chatglm') } @@ -1381,7 +1381,7 @@ export class chatgpt extends plugin { return false } let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#bing') } @@ -1400,7 +1400,7 @@ export class chatgpt extends plugin { return false } let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#claude2') } @@ -1419,7 +1419,7 @@ export class chatgpt extends plugin { return false } let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#claude') } @@ -1438,7 +1438,7 @@ export class chatgpt extends plugin { return false } let ats = e.message.filter(m => m.type === 'at') - if (!e.atme && ats.length > 0) { + if (!(e.atme || e.atBot) && ats.length > 0) { if (Config.debug) { logger.mark('艾特别人了,没艾特我,忽略#xh') } @@ -1665,16 +1665,24 @@ export class chatgpt extends plugin { if (Config.debug) { logger.mark(`开始生成内容:${response.details.imageTag}`) } - let client = new BingDrawClient({ - baseUrl: Config.sydneyReverseProxy, - userToken: bingToken - }) - await redis.set(`CHATGPT:DRAW:${e.sender.user_id}`, 'c', { EX: 30 }) - try { - await client.getImages(response.details.imageTag, e) - } catch (err) { - await redis.del(`CHATGPT:DRAW:${e.sender.user_id}`) - await e.reply('绘图失败:' + err) + if (Config.bingAPDraw) { + // 调用第三方API进行绘图 + let apDraw = new APTool() + apDraw.func({ + prompt: response.details.imageTag + }, e) + } else { + let client = new BingDrawClient({ + baseUrl: Config.sydneyReverseProxy, + userToken: bingToken + }) + await redis.set(`CHATGPT:DRAW:${e.sender.user_id}`, 'c', { EX: 30 }) + try { + await client.getImages(response.details.imageTag, e) + } catch (err) { + await redis.del(`CHATGPT:DRAW:${e.sender.user_id}`) + await e.reply('绘图失败:' + err) + } } } diff --git a/resources/view/setting_view.json b/resources/view/setting_view.json index 9aa8063..78ebca4 100644 --- a/resources/view/setting_view.json +++ b/resources/view/setting_view.json @@ -636,6 +636,12 @@ "label": "必应验证码pass服务", "placeholder": "必应出验证码会自动用该服务绕过", "data": "bingCaptchaOneShotUrl" + }, + { + "type": "check", + "label": "第三方绘图", + "placeholder": "使用AP插件代替Bing进行绘图", + "data": "bingAPDraw" } ] }, diff --git a/utils/config.js b/utils/config.js index cfb7e6a..f37951a 100644 --- a/utils/config.js +++ b/utils/config.js @@ -96,6 +96,7 @@ const defaultConfig = { maxNumUserMessagesInConversation: 20, sydneyApologyIgnored: true, enforceMaster: false, + bingAPDraw: false, serverPort: 3321, serverHost: '', viewHost: '', From dce7503c413dda37d8820346be7e43f37951954b Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Fri, 13 Oct 2023 22:15:06 +0800 Subject: [PATCH 05/47] =?UTF-8?q?fix:=20=E5=BE=AE=E8=BD=AF=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=90=8E=EF=BC=8C=E7=AC=AC=E4=B8=80=E6=AC=A1=E5=AF=B9?= =?UTF-8?q?=E8=AF=9D=E6=89=8B=E5=8A=A8=E5=AF=B9=E8=AF=9D=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BB=A5=E9=81=BF=E5=85=8D=E6=97=A0=E9=99=90=E5=BE=AA=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index 1bea8a3..d375415 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -761,7 +761,7 @@ export class chatgpt extends plugin { if (!e.raw_message || e.msg?.startsWith('#')) { return false } - if (e.isGroup && !(e.atme || e.atBot)) { + if ((e.isGroup || e.group_id) && !(e.atme || e.atBot)) { return false } if (e.user_id == getUin(e)) return false @@ -1720,8 +1720,11 @@ export class chatgpt extends plugin { } } else { // 未登录用户maxConv目前为5或10,出验证码没救 - logger.warn(`token [${bingToken}] 无效或已过期`) + logger.warn(`token [${bingToken}] 无效或已过期,如确认token无误,请前往网页版必应对话一次`) + retry = 0 } + } else { + retry = 0 } } else if (message && typeof message === 'string' && message.indexOf('限流') > -1) { From 95e730f250f2eab65139691be7e496388e3d932a Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Fri, 13 Oct 2023 22:57:16 +0800 Subject: [PATCH 06/47] =?UTF-8?q?fix:=20=E8=81=8A=E5=A4=A9=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E9=80=82=E9=85=8DTRSS+chronocat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 13 +++++++++---- utils/SydneyAIClient.js | 10 +++++----- utils/version.js | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 utils/version.js diff --git a/apps/chat.js b/apps/chat.js index d375415..c2835ab 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -9,6 +9,7 @@ import SydneyAIClient from '../utils/SydneyAIClient.js' import { PoeClient } from '../utils/poe/index.js' import AzureTTS from '../utils/tts/microsoft-azure.js' import VoiceVoxTTS from '../utils/tts/voicevox.js' +import Version from '../utils/version.js' import { render, renderUrl, @@ -183,7 +184,7 @@ export class chatgpt extends plugin { reg: toggleMode === 'at' ? '^[^#][sS]*' : '^#chat[^gpt][sS]*', /** 执行方法 */ fnc: 'chatgpt', - log: false + log: true }, { reg: '^#(chatgpt)?对话列表$', @@ -756,16 +757,17 @@ export class chatgpt extends plugin { * #chatgpt */ async chatgpt (e) { + let msg = Version.isTrss ? e.msg : e.raw_message let prompt if (this.toggleMode === 'at') { - if (!e.raw_message || e.msg?.startsWith('#')) { + if (!msg || e.msg?.startsWith('#')) { return false } if ((e.isGroup || e.group_id) && !(e.atme || e.atBot)) { return false } if (e.user_id == getUin(e)) return false - prompt = e.raw_message.trim() + prompt = msg.trim() if (e.isGroup && typeof this.e.group.getMemberMap === 'function') { let mm = await this.e.group.getMemberMap() let me = mm.get(getUin(e)) || {} @@ -1582,6 +1584,7 @@ export class chatgpt extends plugin { // opt.messageType = allThrottled ? 'Chat' : 'SearchQuery' if (Config.enableGroupContext && e.isGroup && typeof e.group.getMemberMap === 'function') { try { + let memberMap = await e.group.getMemberMap() opt.groupId = e.group_id opt.qq = e.sender.user_id opt.nickname = e.sender.card @@ -1605,7 +1608,9 @@ export class chatgpt extends plugin { let mm = await e.group.getMemberMap() chats.forEach(chat => { let sender = mm.get(chat.sender.user_id) - chat.sender = sender + if (sender) { + chat.sender = sender + } }) // console.log(chats) opt.chats = chats diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index e2e3a07..cefc4bd 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -11,6 +11,7 @@ import { formatDate, getMasterQQ, isCN, getUserData } from './common.js' import delay from 'delay' import moment from 'moment' import { getProxy } from './proxy.js' +import Version from './version.js' if (!globalThis.fetch) { globalThis.fetch = fetch @@ -80,7 +81,7 @@ export default class SydneyAIClient { // 'x-ms-client-request-id': crypto.randomUUID(), // 'x-ms-useragent': 'azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.3 OS/macOS', // cookie: this.opts.cookies || `_U=${this.opts.userToken}`, - Referer: 'https://edgeservices.bing.com/edgesvc/chat?udsframed=1&form=SHORUN&clientscopes=chat,noheader,channelstable,', + Referer: 'https://edgeservices.bing.com/edgesvc/chat?udsframed=1&form=SHORUN&clientscopes=chat,noheader,channelstable,' // 'Referrer-Policy': 'origin-when-cross-origin', // Workaround for request being blocked due to geolocation // 'x-forwarded-for': '1.1.1.1' @@ -461,11 +462,10 @@ export default class SydneyAIClient { admin: '管理员' } if (chats) { - context += `以下是一段qq群内的对话,提供给你作为上下文,你在回答所有问题时必须优先考虑这些信息,结合这些上下文进行回答,这很重要!!!。" - ` + context += '以下是一段qq群内的对话,提供给你作为上下文,你在回答所有问题时必须优先考虑这些信息,结合这些上下文进行回答,这很重要!!!。"' context += chats .map(chat => { - let sender = chat.sender || {} + let sender = chat.sender || chat || {} // if (sender.user_id === Bot.uin && chat.raw_message.startsWith('建议的回复')) { if (chat.raw_message.startsWith('建议的回复')) { // 建议的回复太容易污染设定导致对话太固定跑偏了 @@ -655,7 +655,7 @@ export default class SydneyAIClient { text: replySoFar.join('') } // 获取到图片内容 - if (messages.some(obj => obj.contentType === "IMAGE")) { + if (messages.some(obj => obj.contentType === 'IMAGE')) { message.imageTag = messages.filter(m => m.contentType === 'IMAGE').map(m => m.text).join('') } message.text = messages.filter(m => m.author === 'bot' && m.contentType != 'IMAGE').map(m => m.text).join('') diff --git a/utils/version.js b/utils/version.js new file mode 100644 index 0000000..a3a8c60 --- /dev/null +++ b/utils/version.js @@ -0,0 +1,33 @@ +import fs from 'fs' + +/** + * from miao-plugin + * + * @type {any} + */ +let packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')) + +const yunzaiVersion = packageJson.version +const isV3 = yunzaiVersion[0] === '3' +let isMiao = false; let isTrss = false +let name = 'Yunzai-Bot' +if (packageJson.name === 'miao-yunzai') { + isMiao = true + name = 'Miao-Yunzai' +} else if (packageJson.name === 'trss-yunzai') { + isMiao = true + isTrss = true + name = 'TRSS-Yunzai' +} + +let Version = { + isV3, + isMiao, + isTrss, + name, + get yunzai () { + return yunzaiVersion + } +} + +export default Version From 4066f178478e524723ca31c29d3cc95d96b7a468 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sat, 14 Oct 2023 00:47:39 +0800 Subject: [PATCH 07/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DTRSS=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E9=94=99=E8=AF=AF=EF=BC=8Cchronocat=20linux=E5=BA=94?= =?UTF-8?q?=E8=AF=A5=E8=BF=98=E6=B2=A1=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 50 ++++++++++++++++++++++++++----------------------- utils/common.js | 25 ++++++++++++++----------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index c2835ab..c6de4aa 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -768,34 +768,38 @@ export class chatgpt extends plugin { } if (e.user_id == getUin(e)) return false prompt = msg.trim() - if (e.isGroup && typeof this.e.group.getMemberMap === 'function') { - let mm = await this.e.group.getMemberMap() - let me = mm.get(getUin(e)) || {} - let card = me.card - let nickname = me.nickname - if (nickname && card) { - if (nickname.startsWith(card)) { - // 例如nickname是"滚筒洗衣机",card是"滚筒" - prompt = prompt.replace(`@${nickname}`, '').trim() - } else if (card.startsWith(nickname)) { - // 例如nickname是"十二",card是"十二|本月已发送1000条消息" - prompt = prompt.replace(`@${card}`, '').trim() - // 如果是好友,显示的还是昵称 - prompt = prompt.replace(`@${nickname}`, '').trim() - } else { - // 互不包含,分别替换 - if (nickname) { + try { + if (e.isGroup && typeof this.e.group.getMemberMap === 'function') { + let mm = await this.e.group.getMemberMap() + let me = mm.get(getUin(e)) || {} + let card = me.card + let nickname = me.nickname + if (nickname && card) { + if (nickname.startsWith(card)) { + // 例如nickname是"滚筒洗衣机",card是"滚筒" prompt = prompt.replace(`@${nickname}`, '').trim() - } - if (card) { + } else if (card.startsWith(nickname)) { + // 例如nickname是"十二",card是"十二|本月已发送1000条消息" prompt = prompt.replace(`@${card}`, '').trim() + // 如果是好友,显示的还是昵称 + prompt = prompt.replace(`@${nickname}`, '').trim() + } else { + // 互不包含,分别替换 + if (nickname) { + prompt = prompt.replace(`@${nickname}`, '').trim() + } + if (card) { + prompt = prompt.replace(`@${card}`, '').trim() + } } + } else if (nickname) { + prompt = prompt.replace(`@${nickname}`, '').trim() + } else if (card) { + prompt = prompt.replace(`@${card}`, '').trim() } - } else if (nickname) { - prompt = prompt.replace(`@${nickname}`, '').trim() - } else if (card) { - prompt = prompt.replace(`@${card}`, '').trim() } + } catch (err) { + logger.warn(err) } } else { let ats = e.message.filter(m => m.type === 'at') diff --git a/utils/common.js b/utils/common.js index 62181c8..b9f9f33 100644 --- a/utils/common.js +++ b/utils/common.js @@ -1,18 +1,20 @@ // import { remark } from 'remark' // import stripMarkdown from 'strip-markdown' -import {exec} from 'child_process' +import { exec } from 'child_process' import lodash from 'lodash' import fs from 'node:fs' import path from 'node:path' import buffer from 'buffer' import yaml from 'yaml' import puppeteer from '../../../lib/puppeteer/puppeteer.js' -import {Config} from './config.js' -import {convertSpeaker, generateVitsAudio, speakers as vitsRoleList} from './tts.js' -import VoiceVoxTTS, {supportConfigurations as voxRoleList} from './tts/voicevox.js' -import AzureTTS, {supportConfigurations as azureRoleList} from './tts/microsoft-azure.js' -import {translate} from './translate.js' +import common from '../../../lib/common/common.js' +import { Config } from './config.js' +import { convertSpeaker, generateVitsAudio, speakers as vitsRoleList } from './tts.js' +import VoiceVoxTTS, { supportConfigurations as voxRoleList } from './tts/voicevox.js' +import AzureTTS, { supportConfigurations as azureRoleList } from './tts/microsoft-azure.js' +import { translate } from './translate.js' import uploadRecord from './uploadRecord.js' +import Version from './version.js' // export function markdownToText (markdown) { // return remark() // .use(stripMarkdown) @@ -81,6 +83,9 @@ export async function tryTimes (promiseFn, maxTries = 10) { } export async function makeForwardMsg (e, msg = [], dec = '') { + if (Version.isTrss) { + return common.makeForwardMsg(e, msg, dec) + } let nickname = Bot.nickname if (e.isGroup) { try { @@ -127,9 +132,9 @@ export async function makeForwardMsg (e, msg = [], dec = '') { } } forwardMsg.data = forwardMsg.data - .replace(/\n/g, '') - .replace(/(.+?)<\/title>/g, '___') - .replace(/___+/, `<title color="#777777" size="26">${dec}`) + .replace(/\n/g, '') + .replace(/(.+?)<\/title>/g, '___') + .replace(/___+/, `<title color="#777777" size="26">${dec}`) if (!is_sign) { forwardMsg.data = forwardMsg.data .replace('转发的', '不可转发的') @@ -919,7 +924,6 @@ export async function generateAzureAudio (pendingText, role = '随机', speaking let languagePrefix = azureRoleList.find(config => config.code === speaker).languageDetail.charAt(0) languagePrefix = languagePrefix.startsWith('E') ? '英' : languagePrefix pendingText = (await translate(pendingText, languagePrefix)).replace('\n', '') - } else { let role, languagePrefix role = azureRoleList[Math.floor(Math.random() * azureRoleList.length)] @@ -961,4 +965,3 @@ export function getUserSpeaker (userSetting) { return userSetting.ttsRoleVoiceVox || Config.voicevoxTTSSpeaker } } - From 0a3c95d30567f9e2520cf42fc36166fdb7b9c916 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sat, 14 Oct 2023 01:11:53 +0800 Subject: [PATCH 08/47] =?UTF-8?q?fix:=20=E6=9F=90=E4=BA=9B=E7=89=B9?= =?UTF-8?q?=E6=AE=8A=E6=83=85=E5=86=B5=E7=BE=A4=E8=81=8A=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index c6de4aa..cad7c7a 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -1588,7 +1588,6 @@ export class chatgpt extends plugin { // opt.messageType = allThrottled ? 'Chat' : 'SearchQuery' if (Config.enableGroupContext && e.isGroup && typeof e.group.getMemberMap === 'function') { try { - let memberMap = await e.group.getMemberMap() opt.groupId = e.group_id opt.qq = e.sender.user_id opt.nickname = e.sender.card @@ -1601,23 +1600,28 @@ export class chatgpt extends plugin { if (master && !e.group) { opt.masterName = Bot.getFriendList().get(parseInt(master))?.nickname } - let latestChat = await e.group.getChatHistory(0, 1) - let seq = latestChat[0].seq - let chats = [] - while (chats.length < Config.groupContextLength) { - let chatHistory = await e.group.getChatHistory(seq, 20) - chats.push(...chatHistory) - } - chats = chats.slice(0, Config.groupContextLength) - let mm = await e.group.getMemberMap() - chats.forEach(chat => { - let sender = mm.get(chat.sender.user_id) - if (sender) { - chat.sender = sender + let latestChats = await e.group.getChatHistory(0, 1) + if (latestChats.length > 0) { + let latestChat = latestChats[0] + if (latestChat) { + let seq = latestChat.seq + let chats = [] + while (chats.length < Config.groupContextLength) { + let chatHistory = await e.group.getChatHistory(seq, 20) + chats.push(...chatHistory) + } + chats = chats.slice(0, Config.groupContextLength) + let mm = await e.group.getMemberMap() + chats.forEach(chat => { + let sender = mm.get(chat.sender.user_id) + if (sender) { + chat.sender = sender + } + }) + // console.log(chats) + opt.chats = chats } - }) - // console.log(chats) - opt.chats = chats + } } catch (err) { logger.warn('获取群聊聊天记录失败,本次对话不携带聊天记录', err) } From 4c737d5728223dfe1c40a7aaddba5aeaaf821cc5 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sat, 14 Oct 2023 12:55:41 +0800 Subject: [PATCH 09/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E6=A8=A1=E5=BC=8F=E5=9C=A8TRSS=E4=B8=8B=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/chat.js b/apps/chat.js index cad7c7a..85d3534 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -2215,7 +2215,7 @@ export class chatgpt extends plugin { logger.mark(logger.green('【ChatGPT-Plugin】插件avocado-plugin未安装') + ',安装后可查看最近热映电影与体验可玩性更高的点歌工具。\n可前往 https://github.com/Qz-Sean/avocado-plugin 获取') } if (e.isGroup) { - let botInfo = await Bot.getGroupMemberInfo(e.group_id, getUin(e), true) + let botInfo = await e.bot.getGroupMemberInfo(e.group_id, getUin(e), true) if (botInfo.role !== 'member') { // 管理员才给这些工具 tools.push(...[new EditCardTool(), new JinyanTool(), new KickOutTool(), new HandleMessageMsgTool(), new SetTitleTool()]) From 59ab8df6580a7c475c92e2aec1799b349fdfcc42 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sat, 14 Oct 2023 13:07:01 +0800 Subject: [PATCH 10/47] =?UTF-8?q?fix:=20=E5=85=BC=E5=AE=B9=E6=80=A7?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 14 +- apps/entertainment.js | 12 +- apps/history.js | 14 +- apps/management.js | 4 +- utils/SydneyAIClient.js | 1 - utils/common.js | 16 +- utils/poe/index 2.js | 278 ------------------ utils/tools/APTool.js | 2 +- utils/tools/EditCardTool.js | 4 +- utils/tools/EliMovieTool.js | 2 +- utils/tools/HandleMessageMsgTool.js | 4 +- utils/tools/JinyanTool.js | 4 +- utils/tools/KickOutTool.js | 2 +- utils/tools/QueryGenshinTool.js | 2 +- utils/tools/QueryStarRailTool.js | 2 +- utils/tools/SendAudioMessageTool.js | 8 +- utils/tools/SendAvatarTool.js | 6 +- utils/tools/SendBilibiliTool.js | 4 +- utils/tools/SendDiceTool.js | 8 +- .../SendMessageToSpecificGroupOrUserTool.js | 8 +- utils/tools/SendMusicTool.js | 4 +- utils/tools/SendPictureTool.js | 8 +- utils/tools/SendRPSTool.js | 8 +- utils/tools/SetTitleTool.js | 4 +- 24 files changed, 70 insertions(+), 349 deletions(-) delete mode 100644 utils/poe/index 2.js diff --git a/apps/chat.js b/apps/chat.js index 85d3534..4abc1de 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -1592,13 +1592,13 @@ export class chatgpt extends plugin { opt.qq = e.sender.user_id opt.nickname = e.sender.card opt.groupName = e.group.name - opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : Bot.nickname + opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname let master = (await getMasterQQ())[0] if (master && e.group) { opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname } if (master && !e.group) { - opt.masterName = Bot.getFriendList().get(parseInt(master))?.nickname + opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname } let latestChats = await e.group.getChatHistory(0, 1) if (latestChats.length > 0) { @@ -2043,13 +2043,13 @@ export class chatgpt extends plugin { opt.qq = e.sender.user_id opt.nickname = e.sender.card opt.groupName = e.group.name - opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : Bot.nickname + opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname let master = (await getMasterQQ())[0] if (master && e.group) { opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname } if (master && !e.group) { - opt.masterName = Bot.getFriendList().get(parseInt(master))?.nickname + opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname } let latestChat = await e.group.getChatHistory(0, 1) let seq = latestChat[0].seq @@ -2087,7 +2087,7 @@ export class chatgpt extends plugin { system += chats .map(chat => { let sender = chat.sender || {} - // if (sender.user_id === Bot.uin && chat.raw_message.startsWith('建议的回复')) { + // if (sender.user_id === e.bot.uin && chat.raw_message.startsWith('建议的回复')) { if (chat.raw_message.startsWith('建议的回复')) { // 建议的回复太容易污染设定导致对话太固定跑偏了 return '' @@ -2215,7 +2215,7 @@ export class chatgpt extends plugin { logger.mark(logger.green('【ChatGPT-Plugin】插件avocado-plugin未安装') + ',安装后可查看最近热映电影与体验可玩性更高的点歌工具。\n可前往 https://github.com/Qz-Sean/avocado-plugin 获取') } if (e.isGroup) { - let botInfo = await e.bot.getGroupMemberInfo(e.group_id, getUin(e), true) + let botInfo = await e.e.bot.getGroupMemberInfo(e.group_id, getUin(e), true) if (botInfo.role !== 'member') { // 管理员才给这些工具 tools.push(...[new EditCardTool(), new JinyanTool(), new KickOutTool(), new HandleMessageMsgTool(), new SetTitleTool()]) @@ -2467,7 +2467,7 @@ export class chatgpt extends plugin { } if (bots.code === 0) { if (bots.data.pageList.length > 0) { - this.reply(await makeForwardMsg(this.e, bots.data.pageList.map(msg => `${msg.bot.botId} - ${msg.bot.botName}`))) + this.reply(await makeForwardMsg(this.e, bots.data.pageList.map(msg => `${msg.e.bot.botId} - ${msg.e.bot.botName}`))) } else { await e.reply('未查到相关助手', true) } diff --git a/apps/entertainment.js b/apps/entertainment.js index 870c578..fb8ff7f 100644 --- a/apps/entertainment.js +++ b/apps/entertainment.js @@ -296,7 +296,7 @@ ${translateLangLabels} let groupId = e.msg.replace(/^#chatgpt打招呼/, '') logger.info(groupId) groupId = parseInt(groupId) - if (groupId && !Bot.getGroupList().get(groupId)) { + if (groupId && !e.bot.getGroupList().get(groupId)) { await e.reply('机器人不在这个群里!') return } @@ -310,7 +310,7 @@ ${translateLangLabels} if (!groupId) { await e.reply(sendable) } else { - await Bot.sendGroupMsg(groupId, sendable) + await e.bot.sendGroupMsg(groupId, sendable) await e.reply('发送成功!') } } @@ -325,7 +325,7 @@ ${translateLangLabels} continue } let groupId = parseInt(element) - if (Bot.getGroupList().get(groupId)) { + if (this.e.bot.getGroupList().get(groupId)) { // 打招呼概率 if (Math.floor(Math.random() * 100) < Config.helloProbability) { let message = await generateHello() @@ -381,12 +381,12 @@ ${translateLangLabels} } } if (useSilk) { - await Bot.sendGroupMsg(groupId, await uploadRecord(audio)) + await this.e.bot.sendGroupMsg(groupId, await uploadRecord(audio)) } else { - await Bot.sendGroupMsg(groupId, segment.record(audio)) + await this.e.bot.sendGroupMsg(groupId, segment.record(audio)) } } else { - await Bot.sendGroupMsg(groupId, message) + await this.e.bot.sendGroupMsg(groupId, message) } } else { logger.info(`时机未到,这次就不打招呼给群聊${groupId}了`) diff --git a/apps/history.js b/apps/history.js index 5f6d5f2..c76b8e1 100644 --- a/apps/history.js +++ b/apps/history.js @@ -66,12 +66,12 @@ export class history extends plugin { let parentMessageId = previousConversation.parentMessageId let tmp = {} const previousCachedMessages = getMessagesForConversation(conversation.messages, parentMessageId) - .map((message) => { - return { - text: message.message, - author: message.role === 'User' ? 'user' : 'bot' - } - }) + .map((message) => { + return { + text: message.message, + author: message.role === 'User' ? 'user' : 'bot' + } + }) previousCachedMessages.forEach(m => { if (m.author === 'user') { tmp.prompt = m.text @@ -100,7 +100,7 @@ export class history extends plugin { }, bot: { qq: getUin(e), - name: Bot.nickname + name: e.bot.nickname }, chat }, {}) diff --git a/apps/management.js b/apps/management.js index 40b48b8..5837afe 100644 --- a/apps/management.js +++ b/apps/management.js @@ -990,7 +990,7 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie } } else if (match) { const groupId = parseInt(match[1], 10) - if (Bot.getGroupList().get(groupId)) { + if (e.bot.getGroupList().get(groupId)) { if (await redis.get(`CHATGPT:SHUT_UP:${groupId}`)) { await redis.del(`CHATGPT:SHUT_UP:${groupId}`) await redis.set(`CHATGPT:SHUT_UP:${groupId}`, '1', { EX: time }) @@ -1040,7 +1040,7 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie return false } const groupId = parseInt(match[1], 10) - if (Bot.getGroupList().get(groupId)) { + if (e.bot.getGroupList().get(groupId)) { if (await redis.get(`CHATGPT:SHUT_UP:${groupId}`)) { await redis.del(`CHATGPT:SHUT_UP:${groupId}`) await e.reply(`好的主人,我终于又可以在群${groupId}和大家聊天了`) diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index cefc4bd..f24a4fb 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -466,7 +466,6 @@ export default class SydneyAIClient { context += chats .map(chat => { let sender = chat.sender || chat || {} - // if (sender.user_id === Bot.uin && chat.raw_message.startsWith('建议的回复')) { if (chat.raw_message.startsWith('建议的回复')) { // 建议的回复太容易污染设定导致对话太固定跑偏了 return '' diff --git a/utils/common.js b/utils/common.js index b9f9f33..ebef5eb 100644 --- a/utils/common.js +++ b/utils/common.js @@ -86,10 +86,10 @@ export async function makeForwardMsg (e, msg = [], dec = '') { if (Version.isTrss) { return common.makeForwardMsg(e, msg, dec) } - let nickname = Bot.nickname + let nickname = e.bot.nickname if (e.isGroup) { try { - let info = await Bot.getGroupMemberInfo(e.group_id, getUin(e)) + let info = await e.bot.getGroupMemberInfo(e.group_id, getUin(e)) nickname = info.card || info.nickname } catch (err) { console.error(`Failed to get group member info: ${err}`) @@ -792,7 +792,7 @@ export async function getImageOcrText (e) { let resultArr = [] let eachImgRes = '' for (let i in img) { - const imgOCR = await Bot.imageOcr(img[i]) + const imgOCR = await e.bot.imageOcr(img[i]) for (let text of imgOCR.wordslist) { eachImgRes += (`${text?.words} \n`) } @@ -827,11 +827,11 @@ export function getMaxModelTokens (model = 'gpt-3.5-turbo') { } export function getUin (e) { - if (e?.bot?.uin) return e.bot.uin - if (Array.isArray(Bot.uin)) { - if (Config.trssBotUin && Bot.uin.indexOf(Config.trssBotUin) > -1) return Config.trssBotUin - else return Bot.uin[0] - } else return Bot.uin + if (e?.bot?.uin) return e.e.bot.uin + if (Array.isArray(e.bot.uin)) { + if (Config.trssBotUin && e.bot.uin.indexOf(Config.trssBotUin) > -1) return Config.trssBotUin + else return e.bot.uin[0] + } else return e.bot.uin } /** diff --git a/utils/poe/index 2.js b/utils/poe/index 2.js deleted file mode 100644 index a01189a..0000000 --- a/utils/poe/index 2.js +++ /dev/null @@ -1,278 +0,0 @@ -import { readFileSync } from 'fs' -import { scrape } from './credential.js' -import fetch from 'node-fetch' -import crypto from 'crypto' -// used when test as a single file -// const _path = process.cwd() -const _path = process.cwd() + '/plugins/chatgpt-plugin/utils/poe' -const gqlDir = `${_path}/graphql` -const queries = { - // chatViewQuery: readFileSync(gqlDir + '/ChatViewQuery.graphql', 'utf8'), - addMessageBreakMutation: readFileSync(gqlDir + '/AddMessageBreakMutation.graphql', 'utf8'), - chatPaginationQuery: readFileSync(gqlDir + '/ChatPaginationQuery.graphql', 'utf8'), - addHumanMessageMutation: readFileSync(gqlDir + '/AddHumanMessageMutation.graphql', 'utf8'), - loginMutation: readFileSync(gqlDir + '/LoginWithVerificationCodeMutation.graphql', 'utf8'), - signUpWithVerificationCodeMutation: readFileSync(gqlDir + '/SignupWithVerificationCodeMutation.graphql', 'utf8'), - sendVerificationCodeMutation: readFileSync(gqlDir + '/SendVerificationCodeForLoginMutation.graphql', 'utf8') -} -const optionMap = [ - { title: 'Claude (Powered by Anthropic)', value: 'a2' }, - { title: 'Sage (Powered by OpenAI - logical)', value: 'capybara' }, - { title: 'Dragonfly (Powered by OpenAI - simpler)', value: 'nutria' }, - { title: 'ChatGPT (Powered by OpenAI - current)', value: 'chinchilla' }, - { title: 'Claude+', value: 'a2_2' }, - { title: 'GPT-4', value: 'beaver' } -] -export class PoeClient { - constructor (props) { - this.config = props - } - - headers = { - 'Content-Type': 'application/json', - Referrer: 'https://poe.com/', - Origin: 'https://poe.com', - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36' - } - - chatId = 0 - bot = '' - - reConnectWs = false - - async setCredentials () { - let result = await scrape(this.config.quora_cookie) - console.log(result) - this.config.quora_formkey = result.appSettings.formkey - this.config.channel_name = result.channelName - this.config.app_settings = result.appSettings - - // set value - this.headers['poe-formkey'] = this.config.quora_formkey - this.headers['poe-tchannel'] = this.config.channel_name - this.headers.Cookie = this.config.quora_cookie - console.log(this.headers) - } - - async subscribe () { - const query = { - queryName: 'subscriptionsMutation', - variables: { - subscriptions: [ - { - subscriptionName: 'messageAdded', - query: 'subscription subscriptions_messageAdded_Subscription(\n $chatId: BigInt!\n) {\n messageAdded(chatId: $chatId) {\n id\n messageId\n creationTime\n state\n ...ChatMessage_message\n ...chatHelpers_isBotMessage\n }\n}\n\nfragment ChatMessageDownvotedButton_message on Message {\n ...MessageFeedbackReasonModal_message\n ...MessageFeedbackOtherModal_message\n}\n\nfragment ChatMessageDropdownMenu_message on Message {\n id\n messageId\n vote\n text\n ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageFeedbackButtons_message on Message {\n id\n messageId\n vote\n voteReason\n ...ChatMessageDownvotedButton_message\n}\n\nfragment ChatMessageOverflowButton_message on Message {\n text\n ...ChatMessageDropdownMenu_message\n ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageSuggestedReplies_SuggestedReplyButton_message on Message {\n messageId\n}\n\nfragment ChatMessageSuggestedReplies_message on Message {\n suggestedReplies\n ...ChatMessageSuggestedReplies_SuggestedReplyButton_message\n}\n\nfragment ChatMessage_message on Message {\n id\n messageId\n text\n author\n linkifiedText\n state\n ...ChatMessageSuggestedReplies_message\n ...ChatMessageFeedbackButtons_message\n ...ChatMessageOverflowButton_message\n ...chatHelpers_isHumanMessage\n ...chatHelpers_isBotMessage\n ...chatHelpers_isChatBreak\n ...chatHelpers_useTimeoutLevel\n ...MarkdownLinkInner_message\n}\n\nfragment MarkdownLinkInner_message on Message {\n messageId\n}\n\nfragment MessageFeedbackOtherModal_message on Message {\n id\n messageId\n}\n\nfragment MessageFeedbackReasonModal_message on Message {\n id\n messageId\n}\n\nfragment chatHelpers_isBotMessage on Message {\n ...chatHelpers_isHumanMessage\n ...chatHelpers_isChatBreak\n}\n\nfragment chatHelpers_isChatBreak on Message {\n author\n}\n\nfragment chatHelpers_isHumanMessage on Message {\n author\n}\n\nfragment chatHelpers_useTimeoutLevel on Message {\n id\n state\n text\n messageId\n}\n' - }, - { - subscriptionName: 'viewerStateUpdated', - query: 'subscription subscriptions_viewerStateUpdated_Subscription {\n viewerStateUpdated {\n id\n ...ChatPageBotSwitcher_viewer\n }\n}\n\nfragment BotHeader_bot on Bot {\n displayName\n ...BotImage_bot\n}\n\nfragment BotImage_bot on Bot {\n profilePicture\n displayName\n}\n\nfragment BotLink_bot on Bot {\n displayName\n}\n\nfragment ChatPageBotSwitcher_viewer on Viewer {\n availableBots {\n id\n ...BotLink_bot\n ...BotHeader_bot\n }\n}\n' - } - ] - }, - query: 'mutation subscriptionsMutation(\n $subscriptions: [AutoSubscriptionQuery!]!\n) {\n autoSubscribe(subscriptions: $subscriptions) {\n viewer {\n id\n }\n }\n}\n' - } - - await this.makeRequest(query) - } - - async makeRequest (request) { - let payload = JSON.stringify(request) - let baseString = payload + this.headers['poe-formkey'] + 'WpuLMiXEKKE98j56k' - const md5 = crypto.createHash('md5').update(baseString).digest('hex') - const response = await fetch('https://poe.com/api/gql_POST', { - method: 'POST', - headers: Object.assign(this.headers, { - 'poe-tag-id': md5, - 'content-type': 'application/json' - }), - body: payload - }) - let text = await response.text() - try { - let result = JSON.parse(text) - console.log({ result }) - return result - } catch (e) { - console.error(text) - throw e - } - } - - async getBot (displayName) { - let r - let retry = 10 - while (retry >= 0) { - let url = `https://poe.com/_next/data/${this.nextData.buildId}/${displayName}.json` - let r = await fetch(url, { - headers: this.headers - }) - let res = await r.text() - try { - let chatData = (JSON.parse(res)).pageProps.payload.chatOfBotDisplayName - return chatData - } catch (e) { - r = res - retry-- - } - } - throw new Error(r) - } - - async getChatId () { - let r = await fetch('https://poe.com', { - headers: this.headers - }) - let text = await r.text() - const jsonRegex = / - + + diff --git a/utils/common.js b/utils/common.js index f298ac5..0d120d3 100644 --- a/utils/common.js +++ b/utils/common.js @@ -828,17 +828,17 @@ export function getMaxModelTokens (model = 'gpt-3.5-turbo') { export function getUin (e) { if (e?.bot?.uin) return e.bot.uin - if (e) { - if (Array.isArray(e.bot.uin)) { - if (Config.trssBotUin && e.bot.uin.indexOf(Config.trssBotUin) > -1) return Config.trssBotUin - else return e.bot.uin[0] - } else return e.bot.uin - } else { - if (Array.isArray(Bot.uin)) { - if (Config.trssBotUin && Bot.uin.indexOf(Config.trssBotUin) > -1) return Config.trssBotUin - else return Bot.uin[0] - } else return Bot.uin - } + if (Array.isArray(Bot.uin)) { + if (Config.trssBotUin && Bot.uin.indexOf(Config.trssBotUin) > -1) {return Config.trssBotUin} + else { + Bot.uin.forEach((u) => { + if (Bot[u].self_id) { + return Bot[u].self_id + } + }) + return Bot.uin[Bot.uin.length - 1] + } + } else return Bot.uin } /** From 6d16861fe654cce0cf895ebcbd6b72964a0e1f32 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Wed, 18 Oct 2023 13:12:30 +0800 Subject: [PATCH 20/47] fix: update bing ai bundle version --- utils/SydneyAIClient.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index f24a4fb..f570cb6 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -101,12 +101,12 @@ export default class SydneyAIClient { this.opts.host = 'https://edgeservices.bing.com/edgesvc' } logger.mark('使用host:' + this.opts.host) - let response = await fetch(`${this.opts.host}/turing/conversation/create?bundleVersion=1.1055.6`, fetchOptions) + let response = await fetch(`${this.opts.host}/turing/conversation/create?bundleVersion=1.1055.10`, fetchOptions) let text = await response.text() let retry = 10 while (retry >= 0 && response.status === 200 && !text) { await delay(400) - response = await fetch(`${this.opts.host}/turing/conversation/create`, fetchOptions) + response = await fetch(`${this.opts.host}/turing/conversation/create?bundleVersion=1.1055.10`, fetchOptions) text = await response.text() retry-- } From 1a95c671309871555f1066818d06b876e9580bed Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Thu, 19 Oct 2023 20:15:49 +0800 Subject: [PATCH 21/47] =?UTF-8?q?feat:=20=E4=B8=BA=E5=BF=85=E5=BA=94?= =?UTF-8?q?=E5=92=8Cclaude2=E6=8F=90=E4=BE=9B=E8=AF=BB=E5=8F=96=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=83=BD=E5=8A=9B=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + apps/chat.js | 74 +++++++------ package.json | 8 +- utils/SydneyAIClient.js | 27 ++++- utils/bilibili/wbi.js | 71 ++++++++++++ utils/claude.ai/index.js | 1 + utils/common.js | 233 +++++++++++++++++++++++++++++++++++++-- 7 files changed, 369 insertions(+), 46 deletions(-) create mode 100644 utils/bilibili/wbi.js diff --git a/README.md b/README.md index 634d9d7..cba7ab7 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ * 2023-05-29 支持gpt-4 API.必应无需cookie即可对话(Sydney和自定义模式) * 2023-07 支持智能模式,机器人可以实现禁言、群名片/头衔(需给机器人管理员/群主)、分享音乐视频、主动发音频、对接ap,sr和喵喵等插件、联网搜索等,需api模式0613系列模型。智能模式所需的额外api和搜索api分别可以参考[chatgpt-plugin-extras](https://github.com/ikechan8370/chatgpt-plugin-extras) 和 [search-api](https://github.com/ikechan8370/search-api) 自行搭建,其中后者提供了一个公益版本,前者可使用[huggingface](https://huggingface.co/spaces/ikechan8370/cp-extra)部署 * 2023-09-10 支持来自claude.ai的claude-2模型 +* 2023-10-19 支持读取文件,(目前适配必应模式和Claude2模式) ### 如果觉得这个插件有趣或者对你有帮助,请点一个star吧! ## 版本要求 diff --git a/apps/chat.js b/apps/chat.js index 698f10d..43cf3af 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -26,7 +26,15 @@ import { getUserReplySetting, getImageOcrText, getImg, - getMaxModelTokens, formatDate, generateAudio, formatDate2, mkdirs, getUin + getMaxModelTokens, + formatDate, + generateAudio, + formatDate2, + mkdirs, + getUin, + downloadFile, + isPureText, + extractContentFromFile } from '../utils/common.js' import { ChatGPTPuppeteer } from '../utils/browser.js' import { KeyvFile } from 'keyv-file' @@ -1626,6 +1634,20 @@ export class chatgpt extends plugin { logger.warn('获取群聊聊天记录失败,本次对话不携带聊天记录', err) } } + let toSummaryFileContent + try { + if (e.source) { + let msgs = e.isGroup ? await e.group.getChatHistory(e.source.seq, 1) : await e.friend.getChatHistory(e.source.time, 1) + let sourceMsg = msgs[0] + let fileMsgElem = sourceMsg.message.find(msg => msg.type === 'file') + if (fileMsgElem) { + toSummaryFileContent = await extractContentFromFile(fileMsgElem, e) + } + } + } catch (err) { + logger.warn('读取文件内容出错, 忽略文件内容', err) + } + opt.toSummaryFileContent = toSummaryFileContent } else { // 重新创建client,因为token可能换到别的了 if (bingToken?.indexOf('=') > -1) { @@ -1893,40 +1915,30 @@ export class chatgpt extends plugin { debug: Config.debug, proxy: Config.proxy }) - let fileUrl, filename, attachments - if (e.source && e.source.message === '[文件]') { - if (e.isGroup) { - let source = (await e.group.getChatHistory(e.source.seq, 1))[0] - let file = source.message.find(m => m.type === 'file') - if (file) { - filename = file.name - fileUrl = await e.group.getFileUrl(file.fid) - } - } else { - let source = (await e.friend.getChatHistory(e.source.time, 1))[0] - let file = source.message.find(m => m.type === 'file') - if (file) { - filename = file.name - fileUrl = await e.group.getFileUrl(file.fid) + let toSummaryFileContent + try { + if (e.source) { + let msgs = e.isGroup ? await e.group.getChatHistory(e.source.seq, 1) : await e.friend.getChatHistory(e.source.time, 1) + let sourceMsg = msgs[0] + let fileMsgElem = sourceMsg.message.find(msg => msg.type === 'file') + if (fileMsgElem) { + toSummaryFileContent = await extractContentFromFile(fileMsgElem, e) } } + } catch (err) { + logger.warn('读取文件内容出错, 忽略文件内容', err) } - if (fileUrl) { - logger.info('文件地址:' + fileUrl) - mkdirs('data/chatgpt/files') - let destinationPath = 'data/chatgpt/files/' + filename - const response = await fetch(fileUrl) - const fileStream = fs.createWriteStream(destinationPath) - await new Promise((resolve, reject) => { - response.body.pipe(fileStream) - response.body.on('error', (err) => { - reject(err) - }) - fileStream.on('finish', () => { - resolve() - }) + + let attachments = [] + if (toSummaryFileContent?.content) { + attachments.push({ + extracted_content: toSummaryFileContent.content, + file_name: toSummaryFileContent.name, + file_type: 'pdf', + file_size: 200312, + totalPages: 20 }) - attachments = [await client.convertDocument(destinationPath, filename)] + logger.info(toSummaryFileContent.content) } if (conversationId) { return await client.sendMessage(prompt, conversationId, attachments) diff --git a/package.json b/package.json index f45922a..dbd3040 100644 --- a/package.json +++ b/package.json @@ -35,14 +35,18 @@ "ws": "^8.13.0" }, "optionalDependencies": { + "xlsx": "^0.18.5", + "mammoth": "^1.6.0", + "pdfjs-dist": "^3.11.174", + "nodejs-pptx": "^1.2.4", "@node-rs/jieba": "^1.6.2", + "cycletls": "^1.0.21", "jimp": "^0.22.7", "node-silk": "^0.1.0", "puppeteer-extra": "^3.3.6", "puppeteer-extra-plugin-recaptcha": "^3.6.8", "puppeteer-extra-plugin-stealth": "^2.11.2", - "sharp": "^0.32.3", - "cycletls": "^1.0.21" + "sharp": "^0.32.3" }, "devDependencies": { "ts-node": "^10.9.1", diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index f24a4fb..b1a7a8e 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -7,7 +7,7 @@ import fetch, { import crypto from 'crypto' import WebSocket from 'ws' import { Config, pureSydneyInstruction } from './config.js' -import { formatDate, getMasterQQ, isCN, getUserData } from './common.js' +import { formatDate, getMasterQQ, isCN, getUserData, limitString } from './common.js' import delay from 'delay' import moment from 'moment' import { getProxy } from './proxy.js' @@ -222,8 +222,8 @@ export default class SydneyAIClient { timeout = Config.defaultTimeoutMs, firstMessageTimeout = Config.sydneyFirstMessageTimeout, groupId, nickname, qq, groupName, chats, botName, masterName, - messageType = 'Chat' - + messageType = 'Chat', + toSummaryFileContent } = opts // if (messageType === 'Chat') { // logger.warn('该Bing账户token已被限流,降级至使用非搜索模式。本次对话AI将无法使用Bing搜索返回的内容') @@ -372,6 +372,10 @@ export default class SydneyAIClient { let maxConv = Config.maxNumUserMessagesInConversation const currentDate = moment().format('YYYY-MM-DDTHH:mm:ssZ') const imageDate = await this.kblobImage(opts.imageUrl) + if (toSummaryFileContent?.content) { + // message = `请不要进行搜索,用户的问题是:"${message}"` + messageType = 'Chat' + } let argument0 = { source: 'cib', optionsSets, @@ -415,10 +419,12 @@ export default class SydneyAIClient { text: message, messageType, userIpAddress: await generateRandomIP(), - timestamp: currentDate + timestamp: currentDate, + privacy: 'Internal' // messageType: 'SearchQuery' }, tone: 'Creative', + privacy: 'Internal', conversationSignature, participant: { id: clientId @@ -440,7 +446,7 @@ export default class SydneyAIClient { } // simulates document summary function on Edge's Bing sidebar // unknown character limit, at least up to 7k - if (groupId) { + if (groupId && !toSummaryFileContent?.content) { context += '注意,你现在正在一个qq群里和人聊天,现在问你问题的人是' + `${nickname}(${qq})。` if (Config.enforceMaster && master) { if (qq === master) { @@ -493,6 +499,17 @@ export default class SydneyAIClient { messageType: 'Context', messageId: 'discover-web--page-ping-mriduna-----' }) + } else if (toSummaryFileContent?.content) { + obj.arguments[0].previousMessages.push({ + author: 'user', + description: limitString(toSummaryFileContent?.content, 50000, true), + contextType: 'WebPage', + messageType: 'Context', + sourceName: toSummaryFileContent?.name, + sourceUrl: 'file:///C:/Users/turing/Downloads/Documents/' + toSummaryFileContent?.name || 'file.pdf', + // locale: 'und', + // privacy: 'Internal' + }) } else { obj.arguments[0].previousMessages.push({ author: 'user', diff --git a/utils/bilibili/wbi.js b/utils/bilibili/wbi.js new file mode 100644 index 0000000..790c5c4 --- /dev/null +++ b/utils/bilibili/wbi.js @@ -0,0 +1,71 @@ +import md5 from 'md5' +import fetch from 'node-fetch' + +const mixinKeyEncTab = [ + 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, + 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, + 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, + 36, 20, 34, 44, 52 +] + +// 对 imgKey 和 subKey 进行字符顺序打乱编码 +function getMixinKey (orig) { + let temp = '' + mixinKeyEncTab.forEach((n) => { + temp += orig[n] + }) + return temp.slice(0, 32) +} + +// 为请求参数进行 wbi 签名 +function encWbi (params, imgKey, subKey) { + const mixinKey = getMixinKey(imgKey + subKey) + const currTime = Math.round(Date.now() / 1000) + const chrFilter = /[!'()*]/g + let query = [] + Object.assign(params, { wts: currTime }) // 添加 wts 字段 + // 按照 key 重排参数 + Object.keys(params).sort().forEach((key) => { + query.push( + `${encodeURIComponent(key)}=${encodeURIComponent( + // 过滤 value 中的 "!'()*" 字符 + params[key].toString().replace(chrFilter, '') + )}` + ) + }) + query = query.join('&') + const wbiSign = md5(query + mixinKey) // 计算 w_rid + return query + '&w_rid=' + wbiSign +} + +// 获取最新的 img_key 和 sub_key +async function getWbiKeys () { + const resp = await fetch('https://api.bilibili.com/x/web-interface/nav') + const jsonContent = resp.data + const imgUrl = jsonContent.data.wbi_img.img_url + const subUrl = jsonContent.data.wbi_img.sub_url + + return { + img_key: imgUrl.slice( + imgUrl.lastIndexOf('/') + 1, + imgUrl.lastIndexOf('.') + ), + sub_key: subUrl.slice( + subUrl.lastIndexOf('/') + 1, + subUrl.lastIndexOf('.') + ) + } +} + +// getWbiKeys().then((wbi_keys) => { +// const query = encWbi( +// { +// foo: '114', +// bar: '514', +// baz: 1919810 +// }, +// wbi_keys.img_key, +// wbi_keys.sub_key +// ) +// console.log(query) +// }) diff --git a/utils/claude.ai/index.js b/utils/claude.ai/index.js index d6cfbcc..e208731 100644 --- a/utils/claude.ai/index.js +++ b/utils/claude.ai/index.js @@ -186,6 +186,7 @@ export class ClaudeAIClient { } else if (streamDataRes.status === 408) { throw new Error('claude.ai响应超时,可能是回复文本太多,请调高超时时间重试') } else { + logger.error(streamDataRes.status, streamDataRes.body) throw new Error('unknown error') } } diff --git a/utils/common.js b/utils/common.js index f298ac5..2485fce 100644 --- a/utils/common.js +++ b/utils/common.js @@ -1,5 +1,3 @@ -// import { remark } from 'remark' -// import stripMarkdown from 'strip-markdown' import { exec } from 'child_process' import lodash from 'lodash' import fs from 'node:fs' @@ -15,12 +13,26 @@ import AzureTTS, { supportConfigurations as azureRoleList } from './tts/microsof import { translate } from './translate.js' import uploadRecord from './uploadRecord.js' import Version from './version.js' -// export function markdownToText (markdown) { -// return remark() -// .use(stripMarkdown) -// .processSync(markdown ?? '') -// .toString() -// } +import fetch from 'node-fetch' +let pdfjsLib +try { + pdfjsLib = require('pdfjs-dist') +} catch (err) {} + +let mammoth +try { + mammoth = require('mammoth') +} catch (err) {} + +let XLSX +try { + XLSX = require('xlsx') +} catch (err) {} + +let PPTX +try { + PPTX = require('nodejs-pptx') +} catch (err) {} let _puppeteer try { @@ -972,3 +984,208 @@ export function getUserSpeaker (userSetting) { return userSetting.ttsRoleVoiceVox || Config.voicevoxTTSSpeaker } } + +/** + * + * @param url 要下载的文件链接 + * @param destPath 目标路径,如received/abc.pdf. 目前如果文件名重复会覆盖。 + * @param absolute 是否是绝对路径,默认为false,此时拼接在data/chatgpt下 + * @returns {Promise} 最终下载文件的存储位置 + */ +export async function downloadFile (url, destPath, absolute = false) { + let response = await fetch(url) + if (!response.ok) { + throw new Error(`download file http error: status: ${response.status}`) + } + let dest = destPath + if (!absolute) { + const _path = process.cwd() + dest = path.join(_path, 'data', 'chatgpt', dest) + const lastLevelDirPath = path.dirname(dest) + mkdirs(lastLevelDirPath) + } + const fileStream = fs.createWriteStream(dest) + await new Promise((resolve, reject) => { + response.body.pipe(fileStream) + response.body.on('error', err => { + reject(err) + }) + fileStream.on('finish', function () { + resolve() + }) + }) + logger.info(`File downloaded successfully! URL: ${url}, Destination: ${dest}`) + return dest +} + +export function isPureText (filename) { + const ext = path.extname(filename).toLowerCase() + + // List of file extensions that can be treated as pure text + const textFileExtensions = ['.txt', '.log', '.md', '.csv', '.html', '.css', '.js', '.json', '.xml', '.py', '.java', '.cpp', '.c', '.rb', '.php', '.sql', '.sh', '.pl', '.r', '.swift', '.go', '.ts', '.htm', '.yaml', '.yml', '.ini', '.properties', '.tsv'] + + // File types that require additional processing + const processingExtensions = ['.docx', '.pptx', '.xlsx', '.pdf', '.epub'] + + if (textFileExtensions.includes(ext)) { + return 'text' + } else if (processingExtensions.includes(ext)) { + // Return the file extension if additional processing is needed + return ext.replace('.', '') + } else { + return false + } +} + +/** + * 从文件中提取文本内容 + * @param fileMsgElem MessageElem + * @returns {Promise<{}>} 提取的文本内容和文件名 + */ +export async function extractContentFromFile (fileMsgElem, e) { + logger.info('filename: ' + fileMsgElem.name) + let fileType = isPureText(fileMsgElem.name) + if (fileType) { + // 可读的文件类型 + let fileUrl = e.isGroup ? await e.group.getFileUrl(fileMsgElem.fid) : await e.friend.getFileUrl(fileMsgElem.fid) + let filePath = await downloadFile(fileUrl, path.join('received', fileMsgElem.name)) + switch (fileType) { + case 'pdf': { + if (!pdfjsLib) { + return {} + } + const data = new Uint8Array(fs.readFileSync(filePath)) + let loadingTask = pdfjsLib.getDocument(data) + try { + const pdfDocument = await loadingTask.promise + const numPages = pdfDocument.numPages + let pdfText = '' + + // limit pages to prevent OOM or LLM down + let maxPage = 100 + // Iterate through each page and extract text + for (let pageNum = 1; pageNum <= Math.min(numPages, maxPage); ++pageNum) { + const page = await pdfDocument.getPage(pageNum) + const textContent = await page.getTextContent() + const pageText = textContent.items.map(item => item.str).join(' ') + pdfText += pageText + } + + return { + content: pdfText, + name: fileMsgElem.name + } + } catch (error) { + console.error('Error reading PDF file:', error) + return {} + } + } + case 'doc': { + logger.error('not supported file type now') + return '' + } + case 'docx': { + if (!mammoth) { + return {} + } + try { + const { value } = await mammoth.extractRawText({ path: filePath }) + return { + content: value, + name: fileMsgElem.name + } + } catch (error) { + logger.error('Error reading .docx file:', error) + return {} + } + } + case 'xls': { + logger.error('not supported file type now') + return {} + } + case 'xlsx': { + if (!XLSX) { + return {} + } + try { + const workbook = XLSX.readFile(filePath) + const sheetName = workbook.SheetNames[0] // Assuming the first sheet is the one you want to read + const sheet = workbook.Sheets[sheetName] + const data = XLSX.utils.sheet_to_json(sheet, { header: 1 }) + + // Convert the 2D array to plain text + return { + content: data.map(row => row.join('\t')).join('\n'), + name: fileMsgElem.name + } + } catch (error) { + console.error('Error reading .xlsx file:', error) + return {} + } + } + case 'ppt': { + logger.error('not supported file type now') + return {} + } + case 'pptx': { + if (!PPTX) { + return {} + } + try { + let pptx = new PPTX.Composer() + await pptx.load(filePath) + let presentationContent = [] + let slideNumber = 1 + let maxSlideNumber = 60 + while (slideNumber <= maxSlideNumber) { + let slide + try { + slide = pptx.getSlide(slideNumber) + } catch (error) { + // Slide number out of range, break the loop + break + } + + let slideContent = [] + + // Iterate through slide elements and extract text content + slide.elements.forEach(element => { + if (element.text) { + slideContent.push(element.text) + } + }) + + // Add slide content to the presentation content array + presentationContent.push(slideContent.join('\n')) + + // Move to the next slide + slideNumber++ + } + return { + content: presentationContent.join('\n'), + name: fileMsgElem.name + } + } catch (error) { + console.error('Error reading .pptx file:', error) + return {} + } + } + case 'epub': { + logger.error('not supported file type now') + return {} + } + default: { + // text type + const data = fs.readFileSync(filePath) + let text = String(data) + if (text) { + return { + content: text, + name: fileMsgElem.name + } + } + } + } + return {} + } +} From 74626e66768d1ad190f9ab374be8dc371f0a849a Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Thu, 19 Oct 2023 21:02:14 +0800 Subject: [PATCH 22/47] =?UTF-8?q?fix:=20AI=E5=86=99=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=B8=80=E5=AE=9A=E8=A6=81=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/common.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils/common.js b/utils/common.js index ef4e130..2b166e7 100644 --- a/utils/common.js +++ b/utils/common.js @@ -16,22 +16,22 @@ import Version from './version.js' import fetch from 'node-fetch' let pdfjsLib try { - pdfjsLib = require('pdfjs-dist') + pdfjsLib = (await import('pdfjs-dist')).default } catch (err) {} let mammoth try { - mammoth = require('mammoth') + mammoth = (await import('mammoth')).default } catch (err) {} let XLSX try { - XLSX = require('xlsx') + XLSX = (await import('xlsx')).default } catch (err) {} let PPTX try { - PPTX = require('nodejs-pptx') + PPTX = (await import('nodejs-pptx')).default } catch (err) {} let _puppeteer @@ -845,7 +845,7 @@ export function getUin (e) { else { Bot.uin.forEach((u) => { if (Bot[u].self_id) { - return Bot[u].self_id + return Bot[u].self_id } }) return Bot.uin[Bot.uin.length - 1] From b1e3fb78929765e5117fa478a074a5a59d0e3bc1 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Thu, 19 Oct 2023 21:12:53 +0800 Subject: [PATCH 23/47] =?UTF-8?q?fix:=20=E5=87=8F=E5=B0=91=E5=BF=85?= =?UTF-8?q?=E5=BA=94=E6=8E=A5=E5=8F=97=E7=9A=84context=E9=95=BF=E5=BA=A6?= =?UTF-8?q?=E4=B8=8D=E7=84=B6=E7=88=86=E7=82=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/SydneyAIClient.js | 2 +- utils/tools/EditCardTool.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index 009c33c..47dce8c 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -502,7 +502,7 @@ export default class SydneyAIClient { } else if (toSummaryFileContent?.content) { obj.arguments[0].previousMessages.push({ author: 'user', - description: limitString(toSummaryFileContent?.content, 50000, true), + description: limitString(toSummaryFileContent?.content, 20000, true), contextType: 'WebPage', messageType: 'Context', sourceName: toSummaryFileContent?.name, diff --git a/utils/tools/EditCardTool.js b/utils/tools/EditCardTool.js index 597eb5e..a74e667 100644 --- a/utils/tools/EditCardTool.js +++ b/utils/tools/EditCardTool.js @@ -28,7 +28,7 @@ export class EditCardTool extends AbstractTool { qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim()) groupId = isNaN(groupId) || !groupId ? e.group_id : parseInt(groupId.trim()) - let group = await e.bot.pickGroup(groupId) + let group = await e.bot.(groupId) try { let mm = await group.getMemberMap() if (!mm.has(qq)) { From 9e7a614ded83317abcc18e176dffa1c5e0592c58 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Thu, 19 Oct 2023 22:07:54 +0800 Subject: [PATCH 24/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=8D?= =?UTF-8?q?=E7=9F=A5=E9=81=93=E5=95=A5=E6=97=B6=E5=80=99=E4=B8=8D=E5=B0=8F?= =?UTF-8?q?=E5=BF=83=E7=A2=B0=E5=88=B0=E9=94=AE=E7=9B=98=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/tools/EditCardTool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/tools/EditCardTool.js b/utils/tools/EditCardTool.js index a74e667..597eb5e 100644 --- a/utils/tools/EditCardTool.js +++ b/utils/tools/EditCardTool.js @@ -28,7 +28,7 @@ export class EditCardTool extends AbstractTool { qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim()) groupId = isNaN(groupId) || !groupId ? e.group_id : parseInt(groupId.trim()) - let group = await e.bot.(groupId) + let group = await e.bot.pickGroup(groupId) try { let mm = await group.getMemberMap() if (!mm.has(qq)) { From dc19009e2a6918a3d83ace8abc99a55e24632d0f Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sat, 21 Oct 2023 16:06:31 +0800 Subject: [PATCH 25/47] =?UTF-8?q?fix:=20getUin=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/uploadRecord.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/uploadRecord.js b/utils/uploadRecord.js index 98d650b..f689537 100644 --- a/utils/uploadRecord.js +++ b/utils/uploadRecord.js @@ -139,7 +139,7 @@ async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') { 2: 3, 5: { 1: Contactable.target, - 2: getUin(e), + 2: getUin(), 3: 0, 4: hash, 5: buf.length, @@ -183,7 +183,7 @@ async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') { const fid = rsp[11].toBuffer() const b = core.pb.encode({ 1: 4, - 2: Bot.uin, + 2: getUin(), 3: fid, 4: hash, 5: hash.toString('hex') + '.amr', From e0f96e3ac0fbb0c9b6d789799d0d7cde80e6468c Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Wed, 25 Oct 2023 17:40:22 +0800 Subject: [PATCH 26/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dcontext=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/SydneyAIClient.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index 47dce8c..701f2ec 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -491,15 +491,8 @@ export default class SydneyAIClient { }).join('\n') context += '\n' } - if (context) { - obj.arguments[0].previousMessages.push({ - author: 'user', - description: context, - contextType: 'WebPage', - messageType: 'Context', - messageId: 'discover-web--page-ping-mriduna-----' - }) - } else if (toSummaryFileContent?.content) { + if (toSummaryFileContent?.content) { + // 忽略context 不然可能会爆炸 obj.arguments[0].previousMessages.push({ author: 'user', description: limitString(toSummaryFileContent?.content, 20000, true), @@ -510,6 +503,14 @@ export default class SydneyAIClient { // locale: 'und', // privacy: 'Internal' }) + } else if (context) { + obj.arguments[0].previousMessages.push({ + author: 'user', + description: context, + contextType: 'WebPage', + messageType: 'Context', + messageId: 'discover-web--page-ping-mriduna-----' + }) } else { obj.arguments[0].previousMessages.push({ author: 'user', From c0936e6e2a01b08c4c24c1ea0fa52a98b769b5ab Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Wed, 25 Oct 2023 21:50:44 +0800 Subject: [PATCH 27/47] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E9=80=9A?= =?UTF-8?q?=E4=B9=89=E5=8D=83=E9=97=AE=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + apps/chat.js | 220 ++++++++++++++------ apps/management.js | 26 ++- guoba.support.js | 47 +++++ utils/alibaba/qwen-api.js | 394 ++++++++++++++++++++++++++++++++++++ utils/alibaba/qwen-api.ts | 382 ++++++++++++++++++++++++++++++++++ utils/alibaba/tokenizer.js | 6 + utils/alibaba/tokenizer.ts | 8 + utils/alibaba/tsconfig.json | 5 + utils/alibaba/types.js | 26 +++ utils/alibaba/types.ts | 313 ++++++++++++++++++++++++++++ utils/common.js | 14 +- utils/config.js | 10 +- 13 files changed, 1380 insertions(+), 72 deletions(-) create mode 100644 utils/alibaba/qwen-api.js create mode 100644 utils/alibaba/qwen-api.ts create mode 100644 utils/alibaba/tokenizer.js create mode 100644 utils/alibaba/tokenizer.ts create mode 100644 utils/alibaba/tsconfig.json create mode 100644 utils/alibaba/types.js create mode 100644 utils/alibaba/types.ts diff --git a/README.md b/README.md index cba7ab7..c682394 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ * 2023-07 支持智能模式,机器人可以实现禁言、群名片/头衔(需给机器人管理员/群主)、分享音乐视频、主动发音频、对接ap,sr和喵喵等插件、联网搜索等,需api模式0613系列模型。智能模式所需的额外api和搜索api分别可以参考[chatgpt-plugin-extras](https://github.com/ikechan8370/chatgpt-plugin-extras) 和 [search-api](https://github.com/ikechan8370/search-api) 自行搭建,其中后者提供了一个公益版本,前者可使用[huggingface](https://huggingface.co/spaces/ikechan8370/cp-extra)部署 * 2023-09-10 支持来自claude.ai的claude-2模型 * 2023-10-19 支持读取文件,(目前适配必应模式和Claude2模式) +* 2023-10-25 增加支持通义千问官方API ### 如果觉得这个插件有趣或者对你有帮助,请点一个star吧! ## 版本要求 diff --git a/apps/chat.js b/apps/chat.js index 43cf3af..d6f65c3 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -1,85 +1,82 @@ import plugin from '../../../lib/plugins/plugin.js' import _ from 'lodash' -import { Config, defaultOpenAIAPI } from '../utils/config.js' -import { v4 as uuid } from 'uuid' +import {Config, defaultOpenAIAPI} from '../utils/config.js' +import {v4 as uuid} from 'uuid' import delay from 'delay' -import { ChatGPTAPI } from '../utils/openai/chatgpt-api.js' -import { BingAIClient } from '@waylaidwanderer/chatgpt-api' +import {ChatGPTAPI} from '../utils/openai/chatgpt-api.js' +import {BingAIClient} from '@waylaidwanderer/chatgpt-api' import SydneyAIClient from '../utils/SydneyAIClient.js' -import { PoeClient } from '../utils/poe/index.js' +import {PoeClient} from '../utils/poe/index.js' import AzureTTS from '../utils/tts/microsoft-azure.js' import VoiceVoxTTS from '../utils/tts/voicevox.js' import Version from '../utils/version.js' import { - render, - renderUrl, - getMessageById, - makeForwardMsg, - upsertMessage, - randomString, completeJSON, - isImage, - getUserData, + extractContentFromFile, + formatDate, + formatDate2, + generateAudio, getDefaultReplySetting, - isCN, - getMasterQQ, - getUserReplySetting, getImageOcrText, getImg, + getMasterQQ, getMaxModelTokens, - formatDate, - generateAudio, - formatDate2, - mkdirs, + getMessageById, getUin, - downloadFile, - isPureText, - extractContentFromFile + getUserData, + getUserReplySetting, + isCN, + isImage, + makeForwardMsg, + randomString, + render, + renderUrl, + upsertMessage } from '../utils/common.js' -import { ChatGPTPuppeteer } from '../utils/browser.js' -import { KeyvFile } from 'keyv-file' -import { OfficialChatGPTClient } from '../utils/message.js' +import {ChatGPTPuppeteer} from '../utils/browser.js' +import {KeyvFile} from 'keyv-file' +import {OfficialChatGPTClient} from '../utils/message.js' import fetch from 'node-fetch' -import { deleteConversation, getConversations, getLatestMessageIdByConversationId } from '../utils/conversation.js' -import { convertSpeaker, speakers } from '../utils/tts.js' +import {deleteConversation, getConversations, getLatestMessageIdByConversationId} from '../utils/conversation.js' +import {convertSpeaker, speakers} from '../utils/tts.js' import ChatGLMClient from '../utils/chatglm.js' -import { convertFaces } from '../utils/face.js' -import { SlackClaudeClient } from '../utils/slack/slackClient.js' -import { getPromptByName } from '../utils/prompts.js' +import {convertFaces} from '../utils/face.js' +import {SlackClaudeClient} from '../utils/slack/slackClient.js' +import {getPromptByName} from '../utils/prompts.js' import BingDrawClient from '../utils/BingDraw.js' import XinghuoClient from '../utils/xinghuo/xinghuo.js' import Bard from '../utils/bard.js' -import { JinyanTool } from '../utils/tools/JinyanTool.js' -import { SendVideoTool } from '../utils/tools/SendBilibiliTool.js' -import { KickOutTool } from '../utils/tools/KickOutTool.js' -import { EditCardTool } from '../utils/tools/EditCardTool.js' -import { SearchVideoTool } from '../utils/tools/SearchBilibiliTool.js' -import { SearchMusicTool } from '../utils/tools/SearchMusicTool.js' -import { QueryStarRailTool } from '../utils/tools/QueryStarRailTool.js' -import { WebsiteTool } from '../utils/tools/WebsiteTool.js' -import { WeatherTool } from '../utils/tools/WeatherTool.js' -import { SerpTool } from '../utils/tools/SerpTool.js' -import { SerpIkechan8370Tool } from '../utils/tools/SerpIkechan8370Tool.js' -import { SendPictureTool } from '../utils/tools/SendPictureTool.js' -import { SerpImageTool } from '../utils/tools/SearchImageTool.js' -import { ImageCaptionTool } from '../utils/tools/ImageCaptionTool.js' -import { SendAudioMessageTool } from '../utils/tools/SendAudioMessageTool.js' -import { ProcessPictureTool } from '../utils/tools/ProcessPictureTool.js' -import { APTool } from '../utils/tools/APTool.js' -import { QueryGenshinTool } from '../utils/tools/QueryGenshinTool.js' -import { HandleMessageMsgTool } from '../utils/tools/HandleMessageMsgTool.js' -import { QueryUserinfoTool } from '../utils/tools/QueryUserinfoTool.js' -import { EliMovieTool } from '../utils/tools/EliMovieTool.js' -import { EliMusicTool } from '../utils/tools/EliMusicTool.js' -import { SendMusicTool } from '../utils/tools/SendMusicTool.js' -import { SendDiceTool } from '../utils/tools/SendDiceTool.js' -import { SendAvatarTool } from '../utils/tools/SendAvatarTool.js' -import { SendMessageToSpecificGroupOrUserTool } from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js' -import { SetTitleTool } from '../utils/tools/SetTitleTool.js' -import { solveCaptchaOneShot } from '../utils/bingCaptcha.js' -import { ClaudeAIClient } from '../utils/claude.ai/index.js' -import fs from 'fs' -import { getProxy } from '../utils/proxy.js' +import {JinyanTool} from '../utils/tools/JinyanTool.js' +import {SendVideoTool} from '../utils/tools/SendBilibiliTool.js' +import {KickOutTool} from '../utils/tools/KickOutTool.js' +import {EditCardTool} from '../utils/tools/EditCardTool.js' +import {SearchVideoTool} from '../utils/tools/SearchBilibiliTool.js' +import {SearchMusicTool} from '../utils/tools/SearchMusicTool.js' +import {QueryStarRailTool} from '../utils/tools/QueryStarRailTool.js' +import {WebsiteTool} from '../utils/tools/WebsiteTool.js' +import {WeatherTool} from '../utils/tools/WeatherTool.js' +import {SerpTool} from '../utils/tools/SerpTool.js' +import {SerpIkechan8370Tool} from '../utils/tools/SerpIkechan8370Tool.js' +import {SendPictureTool} from '../utils/tools/SendPictureTool.js' +import {SerpImageTool} from '../utils/tools/SearchImageTool.js' +import {ImageCaptionTool} from '../utils/tools/ImageCaptionTool.js' +import {SendAudioMessageTool} from '../utils/tools/SendAudioMessageTool.js' +import {ProcessPictureTool} from '../utils/tools/ProcessPictureTool.js' +import {APTool} from '../utils/tools/APTool.js' +import {QueryGenshinTool} from '../utils/tools/QueryGenshinTool.js' +import {HandleMessageMsgTool} from '../utils/tools/HandleMessageMsgTool.js' +import {QueryUserinfoTool} from '../utils/tools/QueryUserinfoTool.js' +import {EliMovieTool} from '../utils/tools/EliMovieTool.js' +import {EliMusicTool} from '../utils/tools/EliMusicTool.js' +import {SendMusicTool} from '../utils/tools/SendMusicTool.js' +import {SendDiceTool} from '../utils/tools/SendDiceTool.js' +import {SendAvatarTool} from '../utils/tools/SendAvatarTool.js' +import {SendMessageToSpecificGroupOrUserTool} from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js' +import {SetTitleTool} from '../utils/tools/SetTitleTool.js' +import {solveCaptchaOneShot} from '../utils/bingCaptcha.js' +import {ClaudeAIClient} from '../utils/claude.ai/index.js' +import {getProxy} from '../utils/proxy.js' +import {QwenApi} from '../utils/alibaba/qwen-api.js' try { await import('@azure/openai') @@ -187,6 +184,12 @@ export class chatgpt extends plugin { reg: '^#星火(搜索|查找)助手', fnc: 'searchxhBot' }, + { + /** 命令正则匹配 */ + reg: '^#qwen[sS]*', + /** 执行方法 */ + fnc: 'qwen' + }, { /** 命令正则匹配 */ reg: toggleMode === 'at' ? '^[^#][sS]*' : '^#chat[^gpt][sS]*', @@ -374,6 +377,14 @@ export class chatgpt extends plugin { await redis.del(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`) await this.reply('已结束当前对话,请@我进行聊天以开启新的对话', true) } + } else if (use === 'qwen') { + let c = await redis.get(`CHATGPT:CONVERSATIONS_QWEN:${e.sender.user_id}`) + if (!c) { + await this.reply('当前没有开启对话', true) + } else { + await redis.del(`CHATGPT:CONVERSATIONS_QWEN:${e.sender.user_id}`) + await this.reply('已结束当前对话,请@我进行聊天以开启新的对话', true) + } } else if (use === 'bing') { let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${e.sender.user_id}`) if (!c) { @@ -435,6 +446,14 @@ export class chatgpt extends plugin { await redis.del(`CHATGPT:CONVERSATIONS:${qq}`) await this.reply(`已结束${atUser}的对话,TA仍可以@我进行聊天以开启新的对话`, true) } + } else if (use === 'qwen') { + let c = await redis.get(`CHATGPT:CONVERSATIONS_QWEN:${qq}`) + if (!c) { + await this.reply(`当前${atUser}没有开启对话`, true) + } else { + await redis.del(`CHATGPT:CONVERSATIONS_QWEN:${qq}`) + await this.reply(`已结束${atUser}的对话,TA仍可以@我进行聊天以开启新的对话`, true) + } } else if (use === 'bing') { let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${qq}`) if (!c) { @@ -1037,6 +1056,10 @@ export class chatgpt extends plugin { key = `CHATGPT:CONVERSATIONS_AZURE:${e.sender.user_id}` break } + case 'qwen': { + key = `CHATGPT:CONVERSATIONS_QWEN:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}` + break + } } let ctime = new Date() previousConversation = (key ? await redis.get(key) : null) || JSON.stringify({ @@ -1447,6 +1470,25 @@ export class chatgpt extends plugin { return true } + async qwen (e) { + if (!Config.allowOtherMode) { + return false + } + let ats = e.message.filter(m => m.type === 'at') + if (!(e.atme || e.atBot) && ats.length > 0) { + if (Config.debug) { + logger.mark('艾特别人了,没艾特我,忽略#xh') + } + return false + } + let prompt = _.replace(e.raw_message.trimStart(), '#qwen', '').trim() + if (prompt.length === 0) { + return false + } + await this.abstractChat(e, prompt, 'qwen') + return true + } + async xh (e) { if (!Config.allowOtherMode) { return false @@ -1988,6 +2030,57 @@ export class chatgpt extends plugin { let completion = choices[0].message return { text: completion.content, message: completion } } + case 'qwen': { + let completionParams = { + parameters: { + top_p: Config.qwenTopP || 0.5, + top_k: Config.qwenTopK || 50, + seed: Config.qwenSeed > 0 ? Config.qwenSeed : Math.floor(Math.random() * 114514), + temperature: Config.qwenTemperature || 1, + enable_search: !!Config.qwenEnableSearch + } + } + if (Config.qwenModel) { + completionParams.model = Config.qwenModel + } + const currentDate = new Date().toISOString().split('T')[0] + async function um (message) { + return await upsertMessage(message, 'QWEN') + } + async function gm (id) { + return await getMessageById(id, 'QWEN') + } + let opts = { + apiKey: Config.qwenApiKey, + debug: false, + upsertMessage: um, + getMessageById: gm, + systemMessage: `You are ${Config.assistantLabel} ${useCast?.api || Config.promptPrefixOverride || defaultPropmtPrefix} + Current date: ${currentDate}`, + completionParams, + assistantLabel: Config.assistantLabel, + fetch: newFetch + } + this.qwenApi = new QwenApi(opts) + let option = { + timeoutMs: 600000, + completionParams + } + if (conversation) { + if (!conversation.conversationId) { + conversation.conversationId = uuid() + } + option = Object.assign(option, conversation) + } + let msg + try { + msg = await this.qwenApi.sendMessage(prompt, option) + } catch (err) { + logger.error(err) + throw new Error(err) + } + return msg + } case 'bard': { // 处理cookie const matchesPSID = /__Secure-1PSID=([^;]+)/.exec(Config.bardPsid) @@ -2146,6 +2239,9 @@ export class chatgpt extends plugin { } option.systemMessage = system if (conversation) { + if (!conversation.conversationId) { + conversation.conversationId = uuid() + } option = Object.assign(option, conversation) } if (Config.smartMode) { diff --git a/apps/management.js b/apps/management.js index 5837afe..94386e4 100644 --- a/apps/management.js +++ b/apps/management.js @@ -124,6 +124,11 @@ export class ChatgptManagement extends plugin { fnc: 'useBardBasedSolution', permission: 'master' }, + { + reg: '^#chatgpt切换(通义千问|qwen|千问)$', + fnc: 'useQwenSolution', + permission: 'master' + }, { reg: '^#chatgpt(必应|Bing)切换', fnc: 'changeBingTone', @@ -289,9 +294,9 @@ ${userSetting.useTTS === true ? '当前语音模式为' + Config.ttsMode : ''}` const matchCommand = e.msg.match(/^#(chatgpt)?(vits|azure|vox)?语音(服务|角色列表)/) if (matchCommand[3] === '服务') { await this.reply(`当前支持vox、vits、azure语音服务,可使用'#(vox|azure|vits)语音角色列表'查看支持的语音角色。 - + vits语音:主要有赛马娘,原神中文,原神日语,崩坏 3 的音色、结果有随机性,语调可能很奇怪。 - + vox语音:Voicevox 是一款由日本 DeNA 开发的语音合成软件,它可以将文本转换为自然流畅的语音。Voicevox 支持多种语言和声音,可以用于制作各种语音内容,如动画、游戏、广告等。Voicevox 还提供了丰富的调整选项,可以调整声音的音调、速度、音量等参数,以满足不同需求。除了桌面版软件外,Voicevox 还提供了 Web 版本和 API 接口,方便开发者在各种平台上使用。 azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,它可以帮助开发者将语音转换为文本、将文本转换为语音、实现自然语言理解和对话等功能。Azure 语音支持多种语言和声音,可以用于构建各种语音应用程序,如智能客服、语音助手、自动化电话系统等。Azure 语音还提供了丰富的 API 和 SDK,方便开发者在各种平台上集成使用。 @@ -864,6 +869,7 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务, await this.reply('当前已经是星火模式了') } } + async useAzureBasedSolution () { let use = await redis.get('CHATGPT:USE') if (use !== 'azure') { @@ -884,6 +890,16 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务, } } + async useQwenSolution () { + let use = await redis.get('CHATGPT:USE') + if (use !== 'qwen') { + await redis.set('CHATGPT:USE', 'qwen') + await this.reply('已切换到基于通义千问的解决方案') + } else { + await this.reply('当前已经是通义千问模式了') + } + } + async changeBingTone (e) { let tongStyle = e.msg.replace(/^#chatgpt(必应|Bing)切换/, '') if (!tongStyle) { @@ -1275,9 +1291,9 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie const viewHost = Config.serverHost ? `http://${Config.serverHost}/` : `http://${await getPublicIP()}:${Config.serverPort || 3321}/` const otp = randomString(6) await redis.set( - `CHATGPT:SERVER_QUICK`, - otp, - { EX: 60000 } + 'CHATGPT:SERVER_QUICK', + otp, + { EX: 60000 } ) await this.reply(`请登录http://tools.alcedogroup.com/login?server=${viewHost}&otp=${otp}`, true) } diff --git a/guoba.support.js b/guoba.support.js index 9e2a904..7ca1260 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -741,6 +741,53 @@ export function supportGuoba () { bottomHelpMessage: '开启后将通过反代访问bard', component: 'Switch' }, + { + label: '以下为通义千问API方式的配置', + component: 'Divider' + }, + { + field: 'qwenApiKey', + label: '通义千问API Key', + component: 'InputPassword' + }, + { + field: 'qwenModel', + label: '通义千问模型', + bottomHelpMessage: '指明需要调用的模型,目前可选 qwen-turbo 和 qwen-plus', + component: 'Input' + }, + { + field: 'qwenTopP', + label: '通义千问topP', + bottomHelpMessage: '生成时,核采样方法的概率阈值。例如,取值为0.8时,仅保留累计概率之和大于等于0.8的概率分布中的token,作为随机采样的候选集。取值范围为(0,1.0),取值越大,生成的随机性越高;取值越低,生成的随机性越低。默认值 0.5。注意,取值不要大于等于1', + component: 'InputNumber' + }, + { + field: 'qwenTopK', + label: '通义千问topK', + bottomHelpMessage: '生成时,采样候选集的大小。例如,取值为50时,仅将单次生成中得分最高的50个token组成随机采样的候选集。取值越大,生成的随机性越高;取值越小,生成的确定性越高。注意:如果top_k的值大于100,top_k将采用默认值0,表示不启用top_k策略,此时仅有top_p策略生效。', + component: 'InputNumber' + }, + { + field: 'qwenSeed', + label: '通义千问Seed', + bottomHelpMessage: '生成时,随机数的种子,用于控制模型生成的随机性。如果使用相同的种子,每次运行生成的结果都将相同;当需要复现模型的生成结果时,可以使用相同的种子。seed参数支持无符号64位整数类型。默认值 0, 表示每次随机生成', + component: 'InputNumber' + }, + { + field: 'qwenTemperature', + label: '通义千问温度', + bottomHelpMessage: '用于控制随机性和多样性的程度。具体来说,temperature值控制了生成文本时对每个候选词的概率分布进行平滑的程度。较高的temperature值会降低概率分布的峰值,使得更多的低概率词被选择,生成结果更加多样化;而较低的temperature值则会增强概率分布的峰值,使得高概率词更容易被选择,生成结果更加确定。\n' + + '\n' + + '取值范围: (0, 2),系统默认值1.0', + component: 'InputNumber' + }, + { + field: 'qwenEnableSearch', + label: '通义千问允许搜索', + bottomHelpMessage: '生成时,是否参考夸克搜索的结果。注意:打开搜索并不意味着一定会使用搜索结果;如果打开搜索,模型会将搜索结果作为prompt,进而“自行判断”是否生成结合搜索结果的文本,默认为false', + component: 'Switch' + }, { label: '以下为杂七杂八的配置', component: 'Divider' diff --git a/utils/alibaba/qwen-api.js b/utils/alibaba/qwen-api.js new file mode 100644 index 0000000..c1e12a9 --- /dev/null +++ b/utils/alibaba/qwen-api.js @@ -0,0 +1,394 @@ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +import Keyv from 'keyv'; +import pTimeout from 'p-timeout'; +import QuickLRU from 'quick-lru'; +import { v4 as uuidv4 } from 'uuid'; +import * as tokenizer from './tokenizer.js'; +import * as types from './types.js'; +import globalFetch from 'node-fetch'; +var CHATGPT_MODEL = 'qwen-turbo'; // qwen-plus +var USER_LABEL_DEFAULT = 'User'; +var ASSISTANT_LABEL_DEFAULT = '同义千问'; +var QwenApi = /** @class */ (function () { + /** + * Creates a new client wrapper around Qwen's chat completion API, mimicing the official ChatGPT webapp's functionality as closely as possible. + * + * @param opts + */ + function QwenApi(opts) { + var apiKey = opts.apiKey, _a = opts.apiBaseUrl, apiBaseUrl = _a === void 0 ? 'https://dashscope.aliyuncs.com/api/v1' : _a, _b = opts.debug, debug = _b === void 0 ? false : _b, messageStore = opts.messageStore, completionParams = opts.completionParams, parameters = opts.parameters, systemMessage = opts.systemMessage, getMessageById = opts.getMessageById, upsertMessage = opts.upsertMessage, _c = opts.fetch, fetch = _c === void 0 ? globalFetch : _c; + this._apiKey = apiKey; + this._apiBaseUrl = apiBaseUrl; + this._debug = !!debug; + this._fetch = fetch; + this._completionParams = __assign({ model: CHATGPT_MODEL, parameters: __assign({ top_p: 0.5, top_k: 50, temperature: 1.0, seed: 114514, enable_search: true, result_format: "text", incremental_output: false }, parameters) }, completionParams); + this._systemMessage = systemMessage; + if (this._systemMessage === undefined) { + var currentDate = new Date().toISOString().split('T')[0]; + this._systemMessage = "You are ChatGPT, a large language model trained by Qwen. Answer as concisely as possible.\nKnowledge cutoff: 2021-09-01\nCurrent date: ".concat(currentDate); + } + this._getMessageById = getMessageById !== null && getMessageById !== void 0 ? getMessageById : this._defaultGetMessageById; + this._upsertMessage = upsertMessage !== null && upsertMessage !== void 0 ? upsertMessage : this._defaultUpsertMessage; + if (messageStore) { + this._messageStore = messageStore; + } + else { + this._messageStore = new Keyv({ + store: new QuickLRU({ maxSize: 10000 }) + }); + } + if (!this._apiKey) { + throw new Error('Qwen missing required apiKey'); + } + if (!this._fetch) { + throw new Error('Invalid environment; fetch is not defined'); + } + if (typeof this._fetch !== 'function') { + throw new Error('Invalid "fetch" is not a function'); + } + } + /** + * Sends a message to the Qwen chat completions endpoint, waits for the response + * to resolve, and returns the response. + * + * If you want your response to have historical context, you must provide a valid `parentMessageId`. + * + * If you want to receive a stream of partial responses, use `opts.onProgress`. + * + * Set `debug: true` in the `ChatGPTAPI` constructor to log more info on the full prompt sent to the Qwen chat completions API. You can override the `systemMessage` in `opts` to customize the assistant's instructions. + * + * @param message - The prompt message to send + * @param opts.parentMessageId - Optional ID of the previous message in the conversation (defaults to `undefined`) + * @param opts.conversationId - Optional ID of the conversation (defaults to `undefined`) + * @param opts.messageId - Optional ID of the message to send (defaults to a random UUID) + * @param opts.systemMessage - Optional override for the chat "system message" which acts as instructions to the model (defaults to the ChatGPT system message) + * @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout) + * @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated + * @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) + * @param completionParams - Optional overrides to send to the [Qwen chat completion API](https://platform.openai.com/docs/api-reference/chat/create). Options like `temperature` and `presence_penalty` can be tweaked to change the personality of the assistant. + * + * @returns The response from ChatGPT + */ + QwenApi.prototype.sendMessage = function (text, opts, role) { + if (opts === void 0) { opts = {}; } + if (role === void 0) { role = 'user'; } + return __awaiter(this, void 0, void 0, function () { + var parentMessageId, _a, messageId, timeoutMs, completionParams, conversationId, abortSignal, abortController, message, latestQuestion, _b, messages, maxTokens, numTokens, result, responseP; + var _this = this; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + parentMessageId = opts.parentMessageId, _a = opts.messageId, messageId = _a === void 0 ? uuidv4() : _a, timeoutMs = opts.timeoutMs, completionParams = opts.completionParams, conversationId = opts.conversationId; + abortSignal = opts.abortSignal; + abortController = null; + if (timeoutMs && !abortSignal) { + abortController = new AbortController(); + abortSignal = abortController.signal; + } + message = { + role: role, + id: messageId, + conversationId: conversationId, + parentMessageId: parentMessageId, + text: text, + }; + latestQuestion = message; + return [4 /*yield*/, this._buildMessages(text, role, opts, completionParams)]; + case 1: + _b = _c.sent(), messages = _b.messages, maxTokens = _b.maxTokens, numTokens = _b.numTokens; + console.log("maxTokens: ".concat(maxTokens, ", numTokens: ").concat(numTokens)); + result = { + role: 'assistant', + id: uuidv4(), + conversationId: conversationId, + parentMessageId: messageId, + text: undefined, + }; + this._completionParams.input = { messages: messages }; + responseP = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { + var url, headers, body, res, reason, msg, error, response, err_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + url = "".concat(this._apiBaseUrl, "/services/aigc/text-generation/generation"); + headers = { + 'Content-Type': 'application/json', + Authorization: "Bearer ".concat(this._apiKey) + }; + body = __assign(__assign({}, this._completionParams), completionParams); + if (this._debug) { + console.log(JSON.stringify(body)); + } + if (this._debug) { + console.log("sendMessage (".concat(numTokens, " tokens)"), body); + } + _a.label = 1; + case 1: + _a.trys.push([1, 6, , 7]); + return [4 /*yield*/, this._fetch(url, { + method: 'POST', + headers: headers, + body: JSON.stringify(body), + signal: abortSignal + })]; + case 2: + res = _a.sent(); + if (!!res.ok) return [3 /*break*/, 4]; + return [4 /*yield*/, res.text()]; + case 3: + reason = _a.sent(); + msg = "Qwen error ".concat(res.status || res.statusText, ": ").concat(reason); + error = new types.ChatGPTError(msg, { cause: res }); + error.statusCode = res.status; + error.statusText = res.statusText; + return [2 /*return*/, reject(error)]; + case 4: return [4 /*yield*/, res.json()]; + case 5: + response = _a.sent(); + if (this._debug) { + console.log(response); + } + if (response === null || response === void 0 ? void 0 : response.request_id) { + result.id = response.request_id; + } + result.detail = response; + result.text = response.output.text; + return [2 /*return*/, resolve(result)]; + case 6: + err_1 = _a.sent(); + return [2 /*return*/, reject(err_1)]; + case 7: return [2 /*return*/]; + } + }); + }); }).then(function (message) { return __awaiter(_this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, Promise.all([ + this._upsertMessage(latestQuestion), + this._upsertMessage(message) + ]).then(function () { return message; })]; + }); + }); }); + if (timeoutMs) { + if (abortController) { + // This will be called when a timeout occurs in order for us to forcibly + // ensure that the underlying HTTP request is aborted. + ; + responseP.cancel = function () { + abortController.abort(); + }; + } + return [2 /*return*/, pTimeout(responseP, { + milliseconds: timeoutMs, + message: 'Qwen timed out waiting for response' + })]; + } + else { + return [2 /*return*/, responseP]; + } + return [2 /*return*/]; + } + }); + }); + }; + Object.defineProperty(QwenApi.prototype, "apiKey", { + get: function () { + return this._apiKey; + }, + set: function (apiKey) { + this._apiKey = apiKey; + }, + enumerable: false, + configurable: true + }); + QwenApi.prototype._buildMessages = function (text, role, opts, completionParams) { + return __awaiter(this, void 0, void 0, function () { + var _a, systemMessage, parentMessageId, userLabel, assistantLabel, maxNumTokens, messages, systemMessageOffset, nextMessages, functionToken, numTokens, prompt_1, nextNumTokensEstimate, _i, nextMessages_1, m1, _b, isValidPrompt, parentMessage, parentMessageRole, maxTokens; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + _a = opts.systemMessage, systemMessage = _a === void 0 ? this._systemMessage : _a; + parentMessageId = opts.parentMessageId; + userLabel = USER_LABEL_DEFAULT; + assistantLabel = ASSISTANT_LABEL_DEFAULT; + maxNumTokens = 6000; + messages = []; + if (systemMessage) { + messages.push({ + role: 'system', + content: systemMessage + }); + } + systemMessageOffset = messages.length; + nextMessages = text + ? messages.concat([ + { + role: role, + content: text + } + ]) + : messages; + functionToken = 0; + numTokens = functionToken; + _c.label = 1; + case 1: + prompt_1 = nextMessages + .reduce(function (prompt, message) { + switch (message.role) { + case 'system': + return prompt.concat(["Instructions:\n".concat(message.content)]); + case 'user': + return prompt.concat(["".concat(userLabel, ":\n").concat(message.content)]); + default: + return message.content ? prompt.concat(["".concat(assistantLabel, ":\n").concat(message.content)]) : prompt; + } + }, []) + .join('\n\n'); + return [4 /*yield*/, this._getTokenCount(prompt_1)]; + case 2: + nextNumTokensEstimate = _c.sent(); + _i = 0, nextMessages_1 = nextMessages; + _c.label = 3; + case 3: + if (!(_i < nextMessages_1.length)) return [3 /*break*/, 6]; + m1 = nextMessages_1[_i]; + _b = nextNumTokensEstimate; + return [4 /*yield*/, this._getTokenCount('')]; + case 4: + nextNumTokensEstimate = _b + _c.sent(); + _c.label = 5; + case 5: + _i++; + return [3 /*break*/, 3]; + case 6: + isValidPrompt = nextNumTokensEstimate + functionToken <= maxNumTokens; + if (prompt_1 && !isValidPrompt) { + return [3 /*break*/, 9]; + } + messages = nextMessages; + numTokens = nextNumTokensEstimate + functionToken; + if (!isValidPrompt) { + return [3 /*break*/, 9]; + } + if (!parentMessageId) { + return [3 /*break*/, 9]; + } + return [4 /*yield*/, this._getMessageById(parentMessageId)]; + case 7: + parentMessage = _c.sent(); + if (!parentMessage) { + return [3 /*break*/, 9]; + } + parentMessageRole = parentMessage.role || 'user'; + nextMessages = nextMessages.slice(0, systemMessageOffset).concat(__spreadArray([ + { + role: parentMessageRole, + content: parentMessage.text + } + ], nextMessages.slice(systemMessageOffset), true)); + parentMessageId = parentMessage.parentMessageId; + _c.label = 8; + case 8: + if (true) return [3 /*break*/, 1]; + _c.label = 9; + case 9: + maxTokens = Math.max(1, Math.min(this._maxModelTokens - numTokens, this._maxResponseTokens)); + return [2 /*return*/, { messages: messages, maxTokens: maxTokens, numTokens: numTokens }]; + } + }); + }); + }; + QwenApi.prototype._getTokenCount = function (text) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (!text) { + return [2 /*return*/, 0]; + } + // TODO: use a better fix in the tokenizer + text = text.replace(/<\|endoftext\|>/g, ''); + return [2 /*return*/, tokenizer.encode(text).length]; + }); + }); + }; + QwenApi.prototype._defaultGetMessageById = function (id) { + return __awaiter(this, void 0, void 0, function () { + var res; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this._messageStore.get(id)]; + case 1: + res = _a.sent(); + return [2 /*return*/, res]; + } + }); + }); + }; + QwenApi.prototype._defaultUpsertMessage = function (message) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this._messageStore.set(message.request_id, message)]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + return QwenApi; +}()); +export { QwenApi }; diff --git a/utils/alibaba/qwen-api.ts b/utils/alibaba/qwen-api.ts new file mode 100644 index 0000000..c308f31 --- /dev/null +++ b/utils/alibaba/qwen-api.ts @@ -0,0 +1,382 @@ +import Keyv from 'keyv' +import pTimeout from 'p-timeout' +import QuickLRU from 'quick-lru' +import { v4 as uuidv4 } from 'uuid' + +import * as tokenizer from './tokenizer' +import * as types from './types' +import globalFetch from 'node-fetch' +import {qwen, Role} from "./types"; + +const CHATGPT_MODEL = 'qwen-turbo' // qwen-plus + +const USER_LABEL_DEFAULT = 'User' +const ASSISTANT_LABEL_DEFAULT = '同义千问' + +export class QwenApi { + protected _apiKey: string + protected _apiBaseUrl: string + protected _debug: boolean + + protected _systemMessage: string + protected _completionParams: Omit< + types.qwen.CreateChatCompletionRequest, + 'messages' | 'n' + > + protected _maxModelTokens: number + protected _maxResponseTokens: number + protected _fetch: types.FetchFn + + protected _getMessageById: types.GetMessageByIdFunction + protected _upsertMessage: types.UpsertMessageFunction + + protected _messageStore: Keyv + + /** + * Creates a new client wrapper around Qwen's chat completion API, mimicing the official ChatGPT webapp's functionality as closely as possible. + * + * @param opts + */ + constructor(opts: types.QWenAPIOptions) { + const { + apiKey, + apiBaseUrl = 'https://dashscope.aliyuncs.com/api/v1', + debug = false, + messageStore, + completionParams, + parameters, + systemMessage, + getMessageById, + upsertMessage, + fetch = globalFetch + } = opts + + this._apiKey = apiKey + this._apiBaseUrl = apiBaseUrl + this._debug = !!debug + this._fetch = fetch + + this._completionParams = { + model: CHATGPT_MODEL, + parameters: { + top_p: 0.5, + top_k: 50, + temperature: 1.0, + seed: 114514, + enable_search: true, + result_format: "text", + incremental_output: false, + ...parameters + }, + ...completionParams + } + + this._systemMessage = systemMessage + + if (this._systemMessage === undefined) { + const currentDate = new Date().toISOString().split('T')[0] + this._systemMessage = `You are ChatGPT, a large language model trained by Qwen. Answer as concisely as possible.\nKnowledge cutoff: 2021-09-01\nCurrent date: ${currentDate}` + } + + this._getMessageById = getMessageById ?? this._defaultGetMessageById + this._upsertMessage = upsertMessage ?? this._defaultUpsertMessage + + if (messageStore) { + this._messageStore = messageStore + } else { + this._messageStore = new Keyv({ + store: new QuickLRU({ maxSize: 10000 }) + }) + } + + if (!this._apiKey) { + throw new Error('Qwen missing required apiKey') + } + + if (!this._fetch) { + throw new Error('Invalid environment; fetch is not defined') + } + + if (typeof this._fetch !== 'function') { + throw new Error('Invalid "fetch" is not a function') + } + } + + /** + * Sends a message to the Qwen chat completions endpoint, waits for the response + * to resolve, and returns the response. + * + * If you want your response to have historical context, you must provide a valid `parentMessageId`. + * + * If you want to receive a stream of partial responses, use `opts.onProgress`. + * + * Set `debug: true` in the `ChatGPTAPI` constructor to log more info on the full prompt sent to the Qwen chat completions API. You can override the `systemMessage` in `opts` to customize the assistant's instructions. + * + * @param message - The prompt message to send + * @param opts.parentMessageId - Optional ID of the previous message in the conversation (defaults to `undefined`) + * @param opts.conversationId - Optional ID of the conversation (defaults to `undefined`) + * @param opts.messageId - Optional ID of the message to send (defaults to a random UUID) + * @param opts.systemMessage - Optional override for the chat "system message" which acts as instructions to the model (defaults to the ChatGPT system message) + * @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout) + * @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated + * @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) + * @param completionParams - Optional overrides to send to the [Qwen chat completion API](https://platform.openai.com/docs/api-reference/chat/create). Options like `temperature` and `presence_penalty` can be tweaked to change the personality of the assistant. + * + * @returns The response from ChatGPT + */ + async sendMessage( + text: string, + opts: types.SendMessageOptions = {}, + role: Role = 'user', + ): Promise { + const { + parentMessageId, + messageId = uuidv4(), + timeoutMs, + completionParams, + conversationId + } = opts + + let { abortSignal } = opts + + let abortController: AbortController = null + if (timeoutMs && !abortSignal) { + abortController = new AbortController() + abortSignal = abortController.signal + } + + const message: types.ChatMessage = { + role, + id: messageId, + conversationId, + parentMessageId, + text, + } + + const latestQuestion = message + + const { messages, maxTokens, numTokens } = await this._buildMessages( + text, + role, + opts, + completionParams + ) + console.log(`maxTokens: ${maxTokens}, numTokens: ${numTokens}`) + const result: types.ChatMessage = { + role: 'assistant', + id: uuidv4(), + conversationId, + parentMessageId: messageId, + text: undefined, + } + this._completionParams.input = { messages } + const responseP = new Promise( + async (resolve, reject) => { + const url = `${this._apiBaseUrl}/services/aigc/text-generation/generation` + const headers = { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this._apiKey}` + } + const body = { + ...this._completionParams, + ...completionParams + } + if (this._debug) { + console.log(JSON.stringify(body)) + } + + if (this._debug) { + console.log(`sendMessage (${numTokens} tokens)`, body) + } + try { + const res = await this._fetch(url, { + method: 'POST', + headers, + body: JSON.stringify(body), + signal: abortSignal + }) + + if (!res.ok) { + const reason = await res.text() + const msg = `Qwen error ${ + res.status || res.statusText + }: ${reason}` + const error = new types.ChatGPTError(msg, { cause: res }) + error.statusCode = res.status + error.statusText = res.statusText + return reject(error) + } + + const response: types.qwen.CreateChatCompletionResponse = + await res.json() + if (this._debug) { + console.log(response) + } + + if (response?.request_id) { + result.id = response.request_id + } + result.detail = response + result.text = response.output.text + return resolve(result) + } catch (err) { + return reject(err) + } + + } + ).then(async (message) => { + return Promise.all([ + this._upsertMessage(latestQuestion), + this._upsertMessage(message) + ]).then(() => message) + }) + + if (timeoutMs) { + if (abortController) { + // This will be called when a timeout occurs in order for us to forcibly + // ensure that the underlying HTTP request is aborted. + ;(responseP as any).cancel = () => { + abortController.abort() + } + } + + return pTimeout(responseP, { + milliseconds: timeoutMs, + message: 'Qwen timed out waiting for response' + }) + } else { + return responseP + } + } + + get apiKey(): string { + return this._apiKey + } + + set apiKey(apiKey: string) { + this._apiKey = apiKey + } + + + protected async _buildMessages(text: string, role: Role, opts: types.SendMessageOptions, completionParams: Partial< + Omit + >) { + const { systemMessage = this._systemMessage } = opts + let { parentMessageId } = opts + + const userLabel = USER_LABEL_DEFAULT + const assistantLabel = ASSISTANT_LABEL_DEFAULT + + // fix number of qwen + const maxNumTokens = 6000 + let messages: types.qwen.ChatCompletionRequestMessage[] = [] + + if (systemMessage) { + messages.push({ + role: 'system', + content: systemMessage + }) + } + + const systemMessageOffset = messages.length + let nextMessages = text + ? messages.concat([ + { + role, + content: text + } + ]) + : messages + + let functionToken = 0 + + let numTokens = functionToken + + do { + const prompt = nextMessages + .reduce((prompt, message) => { + switch (message.role) { + case 'system': + return prompt.concat([`Instructions:\n${message.content}`]) + case 'user': + return prompt.concat([`${userLabel}:\n${message.content}`]) + default: + return message.content ? prompt.concat([`${assistantLabel}:\n${message.content}`]) : prompt + } + }, [] as string[]) + .join('\n\n') + + let nextNumTokensEstimate = await this._getTokenCount(prompt) + + for (const m1 of nextMessages) { + nextNumTokensEstimate += await this._getTokenCount('') + } + + const isValidPrompt = nextNumTokensEstimate + functionToken <= maxNumTokens + + if (prompt && !isValidPrompt) { + break + } + messages = nextMessages + numTokens = nextNumTokensEstimate + functionToken + + if (!isValidPrompt) { + break + } + + if (!parentMessageId) { + break + } + + const parentMessage = await this._getMessageById(parentMessageId) + if (!parentMessage) { + break + } + + const parentMessageRole = parentMessage.role || 'user' + + nextMessages = nextMessages.slice(0, systemMessageOffset).concat([ + { + role: parentMessageRole, + content: parentMessage.text + }, + ...nextMessages.slice(systemMessageOffset) + ]) + + parentMessageId = parentMessage.parentMessageId + + } while (true) + + // Use up to 4096 tokens (prompt + response), but try to leave 1000 tokens + // for the response. + const maxTokens = Math.max( + 1, + Math.min(this._maxModelTokens - numTokens, this._maxResponseTokens) + ) + + return { messages, maxTokens, numTokens } + } + + protected async _getTokenCount(text: string) { + if (!text) { + return 0 + } + // TODO: use a better fix in the tokenizer + text = text.replace(/<\|endoftext\|>/g, '') + + return tokenizer.encode(text).length + } + + protected async _defaultGetMessageById( + id: string + ): Promise { + const res = await this._messageStore.get(id) + return res + } + + protected async _defaultUpsertMessage( + message: types.ChatMessage + ): Promise { + await this._messageStore.set(message.request_id, message) + } +} diff --git a/utils/alibaba/tokenizer.js b/utils/alibaba/tokenizer.js new file mode 100644 index 0000000..93d5aba --- /dev/null +++ b/utils/alibaba/tokenizer.js @@ -0,0 +1,6 @@ +import { getEncoding } from 'js-tiktoken'; +// TODO: make this configurable +var tokenizer = getEncoding('cl100k_base'); +export function encode(input) { + return new Uint32Array(tokenizer.encode(input)); +} diff --git a/utils/alibaba/tokenizer.ts b/utils/alibaba/tokenizer.ts new file mode 100644 index 0000000..7b2b23d --- /dev/null +++ b/utils/alibaba/tokenizer.ts @@ -0,0 +1,8 @@ +import { getEncoding } from 'js-tiktoken' + +// TODO: make this configurable +const tokenizer = getEncoding('cl100k_base') + +export function encode(input: string): Uint32Array { + return new Uint32Array(tokenizer.encode(input)) +} \ No newline at end of file diff --git a/utils/alibaba/tsconfig.json b/utils/alibaba/tsconfig.json new file mode 100644 index 0000000..14154d5 --- /dev/null +++ b/utils/alibaba/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "module": "es2020" + } +} \ No newline at end of file diff --git a/utils/alibaba/types.js b/utils/alibaba/types.js new file mode 100644 index 0000000..7bdb059 --- /dev/null +++ b/utils/alibaba/types.js @@ -0,0 +1,26 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var ChatGPTError = /** @class */ (function (_super) { + __extends(ChatGPTError, _super); + function ChatGPTError() { + return _super !== null && _super.apply(this, arguments) || this; + } + return ChatGPTError; +}(Error)); +export { ChatGPTError }; +export var qwen; +(function (qwen) { +})(qwen || (qwen = {})); diff --git a/utils/alibaba/types.ts b/utils/alibaba/types.ts new file mode 100644 index 0000000..188269e --- /dev/null +++ b/utils/alibaba/types.ts @@ -0,0 +1,313 @@ +import Keyv from 'keyv' + +export type Role = 'user' | 'assistant' | 'system' + +export type FetchFn = typeof fetch + +export type QWenAPIOptions = { + apiKey: string + + /** @defaultValue `'https://dashscope.aliyuncs.com/api/v1'` **/ + apiBaseUrl?: string + + apiOrg?: string + + /** @defaultValue `false` **/ + debug?: boolean + + completionParams?: Partial< + Omit + > + parameters?: qwen.QWenParameters, + + systemMessage?: string + + messageStore?: Keyv + getMessageById?: GetMessageByIdFunction + upsertMessage?: UpsertMessageFunction + + fetch?: FetchFn +} + +export type SendMessageOptions = { + /** + * function role name + */ + name?: string + messageId?: string + stream?: boolean + systemMessage?: string + parentMessageId?: string + conversationId?: string + timeoutMs?: number + onProgress?: (partialResponse: ChatMessage) => void + abortSignal?: AbortSignal + completionParams?: Partial< + Omit + > +} + +export type MessageActionType = 'next' | 'variant' + +export type SendMessageBrowserOptions = { + conversationId?: string + parentMessageId?: string + messageId?: string + action?: MessageActionType + timeoutMs?: number + onProgress?: (partialResponse: ChatMessage) => void + abortSignal?: AbortSignal +} + +export interface ChatMessage { + id: string + text: string + role: Role + parentMessageId?: string + conversationId?: string + detail?: + | qwen.CreateChatCompletionResponse + | CreateChatCompletionStreamResponse +} + +export class ChatGPTError extends Error { + statusCode?: number + statusText?: string + isFinal?: boolean + accountId?: string +} + +/** Returns a chat message from a store by it's ID (or null if not found). */ +export type GetMessageByIdFunction = (id: string) => Promise + +/** Upserts a chat message to a store. */ +export type UpsertMessageFunction = (message: ChatMessage) => Promise + +export interface CreateChatCompletionStreamResponse + extends openai.CreateChatCompletionDeltaResponse { + usage: CreateCompletionStreamResponseUsage +} + +export interface CreateCompletionStreamResponseUsage + extends openai.CreateCompletionResponseUsage { + estimated: true +} + +/** + * https://chat.openapi.com/backend-api/conversation + */ +export type ConversationJSONBody = { + /** + * The action to take + */ + action: string + + /** + * The ID of the conversation + */ + conversation_id?: string + + /** + * Prompts to provide + */ + messages: Prompt[] + + /** + * The model to use + */ + model: string + + /** + * The parent message ID + */ + parent_message_id: string +} + +export type Prompt = { + /** + * The content of the prompt + */ + content: PromptContent + + /** + * The ID of the prompt + */ + id: string + + /** + * The role played in the prompt + */ + role: Role +} + +export type ContentType = 'text' + +export type PromptContent = { + /** + * The content type of the prompt + */ + content_type: ContentType + + /** + * The parts to the prompt + */ + parts: string[] +} + +export type ConversationResponseEvent = { + message?: Message + conversation_id?: string + error?: string | null +} + +export type Message = { + id: string + content: MessageContent + role: Role + user: string | null + create_time: string | null + update_time: string | null + end_turn: null + weight: number + recipient: string + metadata: MessageMetadata +} + +export type MessageContent = { + content_type: string + parts: string[] +} + +export type MessageMetadata = any + +export namespace qwen { + export interface CreateChatCompletionDeltaResponse { + id: string + object: 'chat.completion.chunk' + created: number + model: string + choices: [ + { + delta: { + role: Role + content?: string, + function_call?: {name: string, arguments: string} + } + index: number + finish_reason: string | null + } + ] + } + + /** + * + * @export + * @interface ChatCompletionRequestMessage + */ + export interface ChatCompletionRequestMessage { + /** + * The role of the author of this message. + * @type {string} + * @memberof ChatCompletionRequestMessage + */ + role: ChatCompletionRequestMessageRoleEnum + /** + * The contents of the message + * @type {string} + * @memberof ChatCompletionRequestMessage + */ + content: string + } + + export declare const ChatCompletionRequestMessageRoleEnum: { + readonly System: 'system' + readonly User: 'user' + readonly Assistant: 'assistant' + } + export declare type ChatCompletionRequestMessageRoleEnum = + (typeof ChatCompletionRequestMessageRoleEnum)[keyof typeof ChatCompletionRequestMessageRoleEnum] + + + export interface QWenInput { + messages: Array + } + + export interface QWenParameters { + result_format: string + top_p: number + top_k: number + seed: number + temperature: number + enable_search: boolean + incremental_output: boolean + } + /** + * + * @export + * @interface CreateChatCompletionRequest + */ + export interface CreateChatCompletionRequest { + /** + * ID of the model to use. Currently, only `gpt-3.5-turbo` and `gpt-3.5-turbo-0301` are supported. + * @type {string} + * @memberof CreateChatCompletionRequest + */ + model: string + /** + * The messages to generate chat completions for, in the [chat format](/docs/guides/chat/introduction). + * @type {Array} + * @memberof CreateChatCompletionRequest + */ + input?: QWenInput + + parameters: QWenParameters + } + /** + * + * @export + * @interface CreateChatCompletionResponse + */ + export interface CreateChatCompletionResponse { + /** + * + * @type {string} + * @memberof CreateChatCompletionResponse + */ + request_id: string + /** + * + * @type {QWenOutput} + * @memberof CreateChatCompletionResponse + */ + output: QWenOutput + /** + * + * @type {CreateCompletionResponseUsage} + * @memberof CreateChatCompletionResponse + */ + usage?: CreateCompletionResponseUsage + } + export interface QWenOutput { + finish_reason: string + text: string + } + /** + * + * @export + * @interface CreateCompletionResponseUsage + */ + export interface CreateCompletionResponseUsage { + /** + * + * @type {number} + * @memberof CreateCompletionResponseUsage + */ + input_tokens: number + /** + * + * @type {number} + * @memberof CreateCompletionResponseUsage + */ + output_tokens: number + } +} diff --git a/utils/common.js b/utils/common.js index 2b166e7..098c34c 100644 --- a/utils/common.js +++ b/utils/common.js @@ -73,12 +73,18 @@ export function randomString (length = 5) { return str.substr(0, length) } -export async function upsertMessage (message) { - await redis.set(`CHATGPT:MESSAGE:${message.id}`, JSON.stringify(message)) +export async function upsertMessage (message, suffix = '') { + if (suffix) { + suffix = '_' + suffix + } + await redis.set(`CHATGPT:MESSAGE${suffix}:${message.id}`, JSON.stringify(message)) } -export async function getMessageById (id) { - let messageStr = await redis.get(`CHATGPT:MESSAGE:${id}`) +export async function getMessageById (id, suffix = '') { + if (suffix) { + suffix = '_' + suffix + } + let messageStr = await redis.get(`CHATGPT:MESSAGE${suffix}:${id}`) return JSON.parse(messageStr) } diff --git a/utils/config.js b/utils/config.js index fb651f9..f63cde2 100644 --- a/utils/config.js +++ b/utils/config.js @@ -154,7 +154,15 @@ const defaultConfig = { claudeAIUA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36', // trss配置 trssBotUin: '', - version: 'v2.7.6' + // 同义千问 + qwenApiKey: '', + qwenModel: 'qwen-turbo', + qwenTopP: 0.5, + qwenTopK: 50, + qwenSeed: 0, + qwenTemperature: 1, + qwenEnableSearch: true, + version: 'v2.7.7' } const _path = process.cwd() let config = {} From b7376407af8fdbc2ff6f55975c4f953ea4d27df0 Mon Sep 17 00:00:00 2001 From: HalcyonAlcedo <41666148+HalcyonAlcedo@users.noreply.github.com> Date: Wed, 25 Oct 2023 23:06:10 +0800 Subject: [PATCH 28/47] =?UTF-8?q?=E9=80=82=E9=85=8D=E6=98=9F=E7=81=ABv3=20?= =?UTF-8?q?(#598)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复星火api上下文 * 将无星火ck的情况降低为warn * feat: 添加星火设定自定义代码功能 * 修复星火api模式的一些问题 * 修复导出配置问题 * feat:添加工具箱快捷登录接口 * 添加工具箱快捷登录指令 * 阻止群聊使用快捷登录 * 添加Azure配置支持,修复重复的配置项冲突 * 移除旧版本渲染和新版本帮助 * 添加工具箱 * 更新工具箱替换原有后台 * 更新工具箱适配代码 * 后台适配Trss * 修复trss不支持sendPrivateMsg的问题 * 优化路由 * 修复路由 * 适配其他uin * 添加bing第三方绘图 * 修复bing绘图第三方调用错误 * 添加bing第三方绘图采样配置 * 修复错误 * 添加bing第三方绘图图片大小配置 * 修复视图错误 * 使用ap替换第三方绘图 * 适配trss * server 适配trss * 修复错误的后台版本更新 * 添加锅巴用户数据 * 修复server初始化消息错误 * 添加锅巴插件适配 * 更新后台页面 * 添加锅巴代理接口 * 优化锅巴接口代理 * 修复锅巴代理参数 * 删除调试信息 * 修复headers * 更新后台锅巴插件支持 * 适配星火v3 * 适配星火v3 * 修复星火domain错误 --- resources/view/setting_view.json | 4 ++++ utils/xinghuo/xinghuo.js | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/resources/view/setting_view.json b/resources/view/setting_view.json index 78ebca4..c3d7c0d 100644 --- a/resources/view/setting_view.json +++ b/resources/view/setting_view.json @@ -718,6 +718,10 @@ "label": "讯飞星火认知大模型V2.0", "value": "apiv2" }, + { + "label": "讯飞星火认知大模型V3.0", + "value": "apiv3" + }, { "label": "讯飞星火助手", "value": "assistants" diff --git a/utils/xinghuo/xinghuo.js b/utils/xinghuo/xinghuo.js index 6ee1bf0..04aa728 100644 --- a/utils/xinghuo/xinghuo.js +++ b/utils/xinghuo/xinghuo.js @@ -90,6 +90,8 @@ export default class XinghuoClient { let APILink = '/v1.1/chat' if (Config.xhmode == 'apiv2') { APILink = '/v2.1/chat' + } else if (Config.xhmode == 'apiv3') { + APILink = '/v3.1/chat' } const date = new Date().toGMTString() const algorithm = 'hmac-sha256' @@ -179,7 +181,11 @@ export default class XinghuoClient { // 获取ws链接 const wsUrl = Config.xhmode == 'assistants' ? Config.xhAssistants : await this.getWsUrl() if (!wsUrl) throw new Error('缺少依赖:crypto。请安装依赖后重试') - + let domain = 'general' + if (Config.xhmode == 'apiv2') + domain = "generalv2" + else if (Config.xhmode == 'apiv3') + domain = "generalv3" // 编写消息内容 const wsSendData = { header: { @@ -188,7 +194,7 @@ export default class XinghuoClient { }, parameter: { chat: { - domain: Config.xhmode == 'api' ? "general" : "generalv2", + domain: domain, temperature: Config.xhTemperature, // 核采样阈值 max_tokens: Config.xhMaxTokens, // tokens最大长度 chat_id: chatId, @@ -378,7 +384,7 @@ export default class XinghuoClient { let chatId = option?.chatId let image = option?.image - if (Config.xhmode == 'api' || Config.xhmode == 'apiv2' || Config.xhmode == 'assistants') { + if (Config.xhmode == 'api' || Config.xhmode == 'apiv2' || Config.xhmode == 'apiv3' || Config.xhmode == 'assistants') { if (!Config.xhAppId || !Config.xhAPISecret || !Config.xhAPIKey) throw new Error('未配置api') let Prompt = [] // 设定 From 2a713ca15822dce52a1da36b55b70e34d2f38c30 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sun, 29 Oct 2023 15:59:03 +0800 Subject: [PATCH 29/47] fix: reconstruction clients --- client/BaseClient.js | 101 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 client/BaseClient.js diff --git a/client/BaseClient.js b/client/BaseClient.js new file mode 100644 index 0000000..46232df --- /dev/null +++ b/client/BaseClient.js @@ -0,0 +1,101 @@ +/** + * Base LLM Chat Client \ + * All the Chat Models should extend this class + * + * @since 2023-10-26 + * @author ikechan8370 + */ +export class BaseClient { + /** + * create a new client + * + * @param props required fields: e, getMessageById, upsertMessage + */ + constructor (props = {}) { + this.supportFunction = false + this.maxToken = 4096 + this.tools = [] + const { + e, getMessageById, upsertMessage + } = props + this.e = e + this.getMessageById = getMessageById + this.upsertMessage = upsertMessage + } + + /** + * get a message according to the id. note that conversationId is not needed + * + * @type function + * @param {string} id + * @return {Promise} message + */ + getMessageById + + /** + * insert or update a message with the id + * + * @type function + * @param {string} id + * @param {object} message + * @return {Promise} + */ + upsertMessage + + /** + * Send prompt message with history and return response message \ + * if function called, handled internally \ + * override this method to implement logic of sending and receiving message + * + * @param msg + * @param opt other options, optional fields: [conversationId, parentMessageId], if not set, random uuid instead + * @returns {Promise} required fields: [text, conversationId, parentMessageId, id] + */ + async sendMessage (msg, opt = {}) { + throw new Error('not implemented in abstract client') + } + + /** + * Get chat history between user and assistant + * override this method to implement logic of getting history + * keyv with local file or redis recommended + * + * @param userId such as qq number + * @param opt other options + * @returns {Promise} + */ + async getHistory (userId, opt = {}) { + throw new Error('not implemented in abstract client') + } + + /** + * Destroy a chat history + * @param conversationId conversationId of the chat history + * @param opt other options + * @returns {Promise} + */ + async destroyHistory (conversationId, opt = {}) { + throw new Error('not implemented in abstract client') + } + + addTools (...tools) { + if (!this.isSupportFunction) { + throw new Error('function not supported') + } + if (!this.tools) { + this.tools = [] + } + this.tools.push(tools) + } + + getTools () { + if (!this.isSupportFunction) { + throw new Error('function not supported') + } + return this.tools || [] + } + + get isSupportFunction () { + return this.supportFunction + } +} From 5cecea07834b3c001770e426c99d1c048801df62 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sun, 29 Oct 2023 20:19:31 +0800 Subject: [PATCH 30/47] =?UTF-8?q?fix:=20=E5=8D=83=E9=97=AE=E7=BB=93?= =?UTF-8?q?=E6=9D=9F=E5=85=A8=E9=83=A8=E5=AF=B9=E8=AF=9Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/chat.js b/apps/chat.js index d6f65c3..fb14c7a 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -565,6 +565,18 @@ export class chatgpt extends plugin { } break } + case 'qwen': { + let qcs = await redis.keys('CHATGPT:CONVERSATIONS_QWEN:*') + for (let i = 0; i < qcs.length; i++) { + await redis.del(qcs[i]) + // todo clean last message id + if (Config.debug) { + logger.info('delete qwen conversation bind: ' + qcs[i]) + } + deleted++ + } + break + } } await this.reply(`结束了${deleted}个用户的对话。`, true) } From efa7fff57439685a6db426e546e5d53b7765dc38 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sun, 29 Oct 2023 20:48:15 +0800 Subject: [PATCH 31/47] =?UTF-8?q?fix:=20=E5=A4=8D=E7=94=A8API=E5=92=8C?= =?UTF-8?q?=E5=8D=83=E9=97=AE=E6=A8=A1=E5=BC=8F=E7=9A=84=E8=AE=BE=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/prompts.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/prompts.js b/apps/prompts.js index 3b5098c..a2b2809 100644 --- a/apps/prompts.js +++ b/apps/prompts.js @@ -157,7 +157,8 @@ export class help extends plugin { const keyMap = { api: 'promptPrefixOverride', Custom: 'sydney', - claude: 'slackClaudeGlobalPreset' + claude: 'slackClaudeGlobalPreset', + qwen: 'promptPrefixOverride' } if (keyMap[use]) { From e5959b01906f9a8217c57ee801a36f3515deb8ee Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Mon, 30 Oct 2023 11:49:46 +0800 Subject: [PATCH 32/47] docs: Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c682394..d3c5388 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ ### 推荐的相关文档和参考资料 本README -[手册](https://chatgptplugin.ikechan8370.com/) +[手册](https://yunzai.chat) [文档1(建设中)](https://chatgpt-docs.err0r.top/) [插件常见问题(鹤望兰版)](https://chatgptplugin.ikechan8370.com/guide/) [Yunzai常见问题(LUCK小运版)](https://www.wolai.com/oA43vuW71aBnv7UsEysn4T) From ea687296a51083f4902e0f267e8fe22e8280e75d Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Mon, 30 Oct 2023 15:35:05 +0800 Subject: [PATCH 33/47] =?UTF-8?q?fix:=20=E6=95=B4=E7=90=86=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=95=BF=E6=9C=9F=E9=81=97=E7=95=99=E6=87=92=E5=BE=97?= =?UTF-8?q?=E4=BF=AE=E7=9A=84=E5=B0=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 13 ++++++++----- utils/SydneyAIClient.js | 6 +++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index fb14c7a..b7c635f 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -1102,9 +1102,7 @@ export class chatgpt extends plugin { logger.mark({ conversation }) } let chatMessage = await this.sendMessage(prompt, conversation, use, e) - if (chatMessage.image) { - this.setContext('solveBingCaptcha', false, 60) - await e.reply([chatMessage.text, segment.image(`base64://${chatMessage.image}`)]) + if (chatMessage?.noMsg) { return false } // 处理星火和bard图片 @@ -1869,10 +1867,10 @@ export class chatgpt extends plugin { text: errorMessage, error: true } - } else { + } else if (response?.response) { return { text: response?.response, - quote: response.quote, + quote: response?.quote, suggestedResponses: response.suggestedResponses, conversationId: response.conversationId, clientId: response.clientId, @@ -1881,6 +1879,11 @@ export class chatgpt extends plugin { parentMessageId: response.apology ? conversation.parentMessageId : response.messageId, bingToken } + } else { + logger.debug('no message') + return { + noMsg: true + } } } case 'api3': { diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index 701f2ec..c425f7c 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -138,7 +138,11 @@ export default class SydneyAIClient { agent = proxy(this.opts.proxy) } if (Config.sydneyWebsocketUseProxy) { - sydneyHost = Config.sydneyReverseProxy.replace('https://', 'wss://').replace('http://', 'ws://') + if (!Config.sydneyReverseProxy) { + logger.warn('用户开启了对话反代,但是没有配置反代,忽略反代配置') + } else { + sydneyHost = Config.sydneyReverseProxy.replace('https://', 'wss://').replace('http://', 'ws://') + } } logger.mark(`use sydney websocket host: ${sydneyHost}`) let host = sydneyHost + '/sydney/ChatHub' From 7289ae6f35270fe126a6721a9988c22ce3c05147 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Mon, 30 Oct 2023 17:00:26 +0800 Subject: [PATCH 34/47] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=A6=96?= =?UTF-8?q?=E6=AC=A1=E4=BD=BF=E7=94=A8=E6=8F=92=E4=BB=B6bing=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E4=B8=8B=E9=AA=8C=E8=AF=81=E7=A0=81=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E8=A2=AB=E9=98=BB=E6=8B=A6=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/chat.js b/apps/chat.js index b7c635f..875402c 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -1788,7 +1788,7 @@ export class chatgpt extends plugin { const { maxConv } = error if (message && typeof message === 'string' && message.indexOf('CaptchaChallenge') > -1) { if (bingToken) { - if (maxConv > 20) { + if (maxConv >= 20) { // maxConv为30说明token有效,可以通过解验证码码服务过码 await e.reply('出现必应验证码,尝试解决中') try { From 6c149265f0a02349f0f58a1afc1d1b500b33a536 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Mon, 30 Oct 2023 17:00:53 +0800 Subject: [PATCH 35/47] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E5=BF=85?= =?UTF-8?q?=E5=BA=94=E5=88=9D=E5=A7=8B=E5=AF=B9=E8=AF=9D=E6=AC=A1=E6=95=B0?= =?UTF-8?q?=E4=B8=BA30?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/config.js b/utils/config.js index f63cde2..308338d 100644 --- a/utils/config.js +++ b/utils/config.js @@ -93,7 +93,7 @@ const defaultConfig = { groupContextTip: '你看看我们群里的聊天记录吧,回答问题的时候要主动参考我们的聊天记录进行回答或提问。但要看清楚哦,不要把我和其他人弄混啦,也不要把自己看晕啦~~', groupContextLength: 50, enableRobotAt: true, - maxNumUserMessagesInConversation: 20, + maxNumUserMessagesInConversation: 30, sydneyApologyIgnored: true, enforceMaster: false, bingAPDraw: false, From 7cc22e487a7aef819d88df6ea3e793cf09808ec9 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Wed, 1 Nov 2023 10:54:58 +0800 Subject: [PATCH 36/47] Update README.md --- README.md | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d3c5388..6d0e971 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![chatgpt-plugin](https://user-images.githubusercontent.com/21212372/232115814-de9a0633-371f-4733-8da0-dd6e912c8a1e.png) -

云崽QQ机器人的ChatGPT插件

+

云崽系机器人的智能聊天插件

@@ -52,16 +52,6 @@ Node.js >= 18 / Node.js >= 14(with node-fetch) ## 安装与使用方法 ### 安装 - -在安装之前,请先判断自己需要使用哪种模式,本插件支持官方API/第三方API/~~浏览器~~/必应四种模式。也可以选择**我全都要**(通过qq发送命令`#chatgpt切换浏览器/API/API3/Bing`实时切换) - -> #### API模式和浏览器模式如何选择? -> -> * API模式会调用OpenAI官方提供的gpt-3.5-turbo API,ChatGPT官网同款模型,只需要提供API Key。一般情况下,该种方式响应速度更快,可配置项多,且不会像chatGPT官网一样总出现不可用的现象,但注意API调用是收费的,新用户有18美元试用金可用于支付,价格为`$0.0020/ 1K tokens`。(问题和回答**加起来**算token) -> * API3模式会调用第三方提供的官网反代API,他会帮你绕过CF防护,需要提供ChatGPT的Token。效果与官网和浏览器一致,但稳定性不一定。发送#chatgpt设置token来设置token。 -> * (Deprecated)浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站,使得获得和官方以及API2模式一模一样的回复质量,同时保证安全性。缺点是本方法对环境要求较高,需要提供桌面环境和一个可用的代理(能够访问ChatGPT的IP地址),且响应速度不如API,而且高峰期容易无法使用。一般作为API3的下位替代。 -> * 必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing登录Cookie方可使用。强烈推荐 - 1. 进入 Yunzai根目录 2. 请将 chatgpt-plugin 放置在 Yunzai-Bot 的 plugins 目录下 @@ -83,12 +73,8 @@ pnpm i 如果是手工下载的 zip 压缩包,请将解压后的 chatgpt-plugin 文件夹(请删除压缩自带的-master或版本号后缀)放置在 Yunzai-Bot 目录下的 plugins 文件夹内 -> ~~浏览器模式仅为备选,如您需要使用浏览器模式,您还需要有**桌面环境**,优先级建议:API≈必应>API3>浏览器~~\ -> ~~2.20更新:必应被大削,变得蠢了,建议还是API/API3优先~~\ -> 4.2更新:必应站起来了,必应天下第一。建议都用必应,别用API/API3了。浏览器模式除非极其特殊的需求否则强烈建议不使用,已经不维护了。 - 3. 修改配置 -**本插件配置项比较多,强烈建议使用后台面板或[锅巴面板](https://github.com/guoba-yunzai/Guoba-Plugin)修改** +**本插件配置项比较多,强烈建议使用后台工具箱或[锅巴面板](https://github.com/guoba-yunzai/Guoba-Plugin)修改** 或者创建和编辑config/config.json文件。 From 61d3b487810664006c183e1c25b2068e053d82d6 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sat, 4 Nov 2023 11:49:36 +0800 Subject: [PATCH 37/47] =?UTF-8?q?fix:=20=E5=88=9D=E6=AD=A5=E9=80=82?= =?UTF-8?q?=E9=85=8D=E9=93=83=E9=9F=B3=E8=AF=AD=E9=9F=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/common.js | 33 ++++++++++++++++++--------------- utils/uploadRecord.js | 5 ++++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/utils/common.js b/utils/common.js index 098c34c..1c63816 100644 --- a/utils/common.js +++ b/utils/common.js @@ -847,14 +847,13 @@ export function getMaxModelTokens (model = 'gpt-3.5-turbo') { export function getUin (e) { if (e?.bot?.uin) return e.bot.uin if (Array.isArray(Bot.uin)) { - if (Config.trssBotUin && Bot.uin.indexOf(Config.trssBotUin) > -1) {return Config.trssBotUin} - else { - Bot.uin.forEach((u) => { - if (Bot[u].self_id) { - return Bot[u].self_id - } - }) - return Bot.uin[Bot.uin.length - 1] + if (Config.trssBotUin && Bot.uin.indexOf(Config.trssBotUin) > -1) { return Config.trssBotUin } else { + Bot.uin.forEach((u) => { + if (Bot[u].self_id) { + return Bot[u].self_id + } + }) + return Bot.uin[Bot.uin.length - 1] } } else return Bot.uin } @@ -871,6 +870,7 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg if (!Config.ttsSpace && !Config.azureTTSKey && !Config.voicevoxSpace) return false let wav const speaker = getUserSpeaker(await getUserReplySetting(e)) + let ignoreEncode = getUin(e) === 88888 try { if (Config.ttsMode === 'vits-uma-genshin-honkai' && Config.ttsSpace) { if (Config.autoJapanese) { @@ -883,7 +883,7 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg } wav = await generateVitsAudio(pendingText, speaker, '中日混合(中文用[ZH][ZH]包裹起来,日文用[JA][JA]包裹起来)') } else if (Config.ttsMode === 'azure' && Config.azureTTSKey) { - return await generateAzureAudio(pendingText, speaker, speakingEmotion, emotionDegree) + return await generateAzureAudio(pendingText, speaker, speakingEmotion, emotionDegree, ignoreEncode) } else if (Config.ttsMode === 'voicevox' && Config.voicevoxSpace) { pendingText = (await translate(pendingText, '日')).replace('\n', '') wav = await VoiceVoxTTS.generateAudio(pendingText, { @@ -897,7 +897,7 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg let sendable try { try { - sendable = await uploadRecord(wav, Config.ttsMode) + sendable = await uploadRecord(wav, Config.ttsMode, ignoreEncode) if (!sendable) { // 如果合成失败,尝试使用ffmpeg合成 sendable = segment.record(wav) @@ -927,9 +927,10 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg * @param role - 发言人 * @param speakingEmotion - 发言人情绪 * @param emotionDegree - 发言人情绪强度 + * @param ignoreEncode - 不在客户端处理编码 * @returns {Promise<{file: string, type: string}|boolean>} */ -export async function generateAzureAudio (pendingText, role = '随机', speakingEmotion, emotionDegree = 1) { +export async function generateAzureAudio (pendingText, role = '随机', speakingEmotion, emotionDegree = 1, ignoreEncode = false) { if (!Config.azureTTSKey) return false let speaker try { @@ -970,11 +971,13 @@ export async function generateAzureAudio (pendingText, role = '随机', speaking pendingText, emotionDegree }) + let record = await AzureTTS.generateAudio(pendingText, { + speaker + }, await ssml) return await uploadRecord( - await AzureTTS.generateAudio(pendingText, { - speaker - }, await ssml) - , Config.ttsMode + record + , Config.ttsMode, + ignoreEncode ) } catch (err) { logger.error(err) diff --git a/utils/uploadRecord.js b/utils/uploadRecord.js index f689537..4e16bab 100644 --- a/utils/uploadRecord.js +++ b/utils/uploadRecord.js @@ -39,7 +39,7 @@ if (module) { // import { pcm2slk } from 'node-silk' let errors = {} -async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') { +async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai', ignoreEncode = false) { let recordType = 'url' let tmpFile = '' if (ttsMode === 'azure') { @@ -48,6 +48,9 @@ async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') { recordType = 'buffer' tmpFile = `data/chatgpt/tts/tmp/${crypto.randomUUID()}.wav` } + if (ignoreEncode) { + return segment.record(recordUrl) + } let result if (pcm2slk) { result = await getPttBuffer(recordUrl, Bot.config.ffmpeg_path) From 0bff8c85b096f786b59f6350bbffce9d0f2adc69 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 7 Nov 2023 18:54:58 +0800 Subject: [PATCH 38/47] =?UTF-8?q?feat:=20=E8=BF=9B=E4=B8=80=E6=AD=A5?= =?UTF-8?q?=E9=80=82=E9=85=8D=E9=93=83=E9=9F=B3+shamrock;=E8=AF=8D?= =?UTF-8?q?=E4=BA=91=E8=BF=9B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 40 +----------- apps/entertainment.js | 58 ++++++++++++++++- utils/SydneyAIClient.js | 2 +- utils/chat.js | 33 ++++++++++ utils/common.js | 2 +- utils/wordcloud/tokenizer.js | 117 ++++++++++++++++++++++++++++++----- utils/wordcloud/wordcloud.js | 22 ++++--- 7 files changed, 209 insertions(+), 65 deletions(-) create mode 100644 utils/chat.js diff --git a/apps/chat.js b/apps/chat.js index 875402c..58ea9b1 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -77,6 +77,7 @@ import {solveCaptchaOneShot} from '../utils/bingCaptcha.js' import {ClaudeAIClient} from '../utils/claude.ai/index.js' import {getProxy} from '../utils/proxy.js' import {QwenApi} from '../utils/alibaba/qwen-api.js' +import {getChatHistoryGroup} from '../utils/chat.js' try { await import('@azure/openai') @@ -1660,28 +1661,7 @@ export class chatgpt extends plugin { if (master && !e.group) { opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname } - let latestChats = await e.group.getChatHistory(0, 1) - if (latestChats.length > 0) { - let latestChat = latestChats[0] - if (latestChat) { - let seq = latestChat.seq - let chats = [] - while (chats.length < Config.groupContextLength) { - let chatHistory = await e.group.getChatHistory(seq, 20) - chats.push(...chatHistory) - } - chats = chats.slice(0, Config.groupContextLength) - let mm = await e.group.getMemberMap() - chats.forEach(chat => { - let sender = mm.get(chat.sender.user_id) - if (sender) { - chat.sender = sender - } - }) - // console.log(chats) - opt.chats = chats - } - } + opt.chats = await getChatHistoryGroup(e, Config.groupContextLength) } catch (err) { logger.warn('获取群聊聊天记录失败,本次对话不携带聊天记录', err) } @@ -2171,21 +2151,7 @@ export class chatgpt extends plugin { if (master && !e.group) { opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname } - let latestChat = await e.group.getChatHistory(0, 1) - let seq = latestChat[0].seq - let chats = [] - while (chats.length < Config.groupContextLength) { - let chatHistory = await e.group.getChatHistory(seq, 20) - chats.push(...chatHistory.reverse()) - } - chats = chats.slice(0, Config.groupContextLength) - // 太多可能会干扰AI对自身qq号和用户qq的判断,感觉gpt3.5也处理不了那么多信息 - chats = chats > 50 ? 50 : chats - let mm = await e.group.getMemberMap() - chats.forEach(chat => { - let sender = mm.get(chat.sender.user_id) - chat.sender = sender - }) + let chats = await getChatHistoryGroup(e, Config.groupContextLength) opt.chats = chats const namePlaceholder = '[name]' const defaultBotName = 'ChatGPT' diff --git a/apps/entertainment.js b/apps/entertainment.js index fb8ff7f..eb6e9d8 100644 --- a/apps/entertainment.js +++ b/apps/entertainment.js @@ -50,6 +50,10 @@ export class Entertainment extends plugin { reg: '^#(|最新)词云(\\d{1,2}h{0,1}|)$', fnc: 'wordcloud_latest' }, + { + reg: '^#(我的)?(本月|本周|今日)?词云$', + fnc: 'wordcloud_new' + }, { reg: '^#((寄批踢|gpt|GPT)?翻.*|chatgpt翻译帮助)', fnc: 'translate' @@ -215,10 +219,10 @@ ${translateLangLabels} const regExp = /词云(\d{0,2})(|h)/ const match = e.msg.trim().match(regExp) - const duration = !match[1] ? 12 : parseInt(match[1]) // default 12h + const duration = !match[1] ? 12 : parseInt(match[1]) // default 12h if (duration > 24) { - await e.reply('最多只能统计24小时内的记录哦') + await e.reply('最多只能统计24小时内的记录哦,你可以使用#本周词云和#本月词云获取更长时间的统计~') return false } await e.reply('在统计啦,请稍等...') @@ -236,6 +240,56 @@ ${translateLangLabels} } } + async wordcloud_new (e) { + if (e.isGroup) { + let groupId = e.group_id + let userId + if (e.msg.includes('我的')) { + userId = e.sender.user_id + } + let at = e.message.find(m => m.type === 'at') + if (at) { + userId = at.qq + } + let lock = await redis.get(`CHATGPT:WORDCLOUD_NEW:${groupId}_${userId}`) + if (lock) { + await e.reply('别着急,上次统计还没完呢') + return true + } + await e.reply('在统计啦,请稍等...') + let duration = 24 + if (e.msg.includes('本周')) { + const now = new Date() // Get the current date and time + let day = now.getDay() + let diff = now.getDate() - day + (day === 0 ? -6 : 1) + const startOfWeek = new Date(new Date().setDate(diff)) + startOfWeek.setHours(0, 0, 0, 0) // Set the time to midnight (start of the day) + duration = (now - startOfWeek) / 1000 / 60 / 60 + } else if (e.msg.includes('本月')) { + const now = new Date() // Get the current date and time + const startOfMonth = new Date(new Date().setDate(0)) + startOfMonth.setHours(0, 0, 0, 0) // Set the time to midnight (start of the day) + duration = (now - startOfMonth) / 1000 / 60 / 60 + } else { + // 默认今天 + const now = new Date() + const startOfToday = new Date() // Get the current date and time + startOfToday.setHours(0, 0, 0, 0) // Set the time to midnight (start of the day) + duration = (now - startOfToday) / 1000 / 60 / 60 + } + await redis.set(`CHATGPT:WORDCLOUD_NEW:${groupId}_${userId}`, '1', { EX: 600 }) + try { + await makeWordcloud(e, e.group_id, duration, userId) + } catch (err) { + logger.error(err) + await e.reply(err) + } + await redis.del(`CHATGPT:WORDCLOUD_NEW:${groupId}_${userId}`) + } else { + await e.reply('请在群里发送此命令') + } + } + async combineEmoj (e) { let left = e.msg.codePointAt(0).toString(16).toLowerCase() let right = e.msg.codePointAt(2).toString(16).toLowerCase() diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index c425f7c..7f2e315 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -476,7 +476,7 @@ export default class SydneyAIClient { context += chats .map(chat => { let sender = chat.sender || chat || {} - if (chat.raw_message.startsWith('建议的回复')) { + if (chat.raw_message?.startsWith('建议的回复')) { // 建议的回复太容易污染设定导致对话太固定跑偏了 return '' } diff --git a/utils/chat.js b/utils/chat.js new file mode 100644 index 0000000..3263c6c --- /dev/null +++ b/utils/chat.js @@ -0,0 +1,33 @@ +export async function getChatHistoryGroup (e, num) { + if (e.adapter === 'shamrock') { + return await e.group.getChatHistory(0, num) + } else { + let latestChats = await e.group.getChatHistory(0, 1) + if (latestChats.length > 0) { + let latestChat = latestChats[0] + if (latestChat) { + let seq = latestChat.seq + let chats = [] + while (chats.length < num) { + let chatHistory = await e.group.getChatHistory(seq, 20) + chats.push(...chatHistory) + } + chats = chats.slice(0, num) + try { + let mm = await e.group.getMemberMap() + chats.forEach(chat => { + let sender = mm.get(chat.sender.user_id) + if (sender) { + chat.sender = sender + } + }) + } catch (err) { + logger.warn(err) + } + // console.log(chats) + return chats + } + } + } + return [] +} diff --git a/utils/common.js b/utils/common.js index 1c63816..03c5271 100644 --- a/utils/common.js +++ b/utils/common.js @@ -870,7 +870,7 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg if (!Config.ttsSpace && !Config.azureTTSKey && !Config.voicevoxSpace) return false let wav const speaker = getUserSpeaker(await getUserReplySetting(e)) - let ignoreEncode = getUin(e) === 88888 + let ignoreEncode = e.adapter === 'shamrock' try { if (Config.ttsMode === 'vits-uma-genshin-honkai' && Config.ttsSpace) { if (Config.autoJapanese) { diff --git a/utils/wordcloud/tokenizer.js b/utils/wordcloud/tokenizer.js index dec121a..7ec06c3 100644 --- a/utils/wordcloud/tokenizer.js +++ b/utils/wordcloud/tokenizer.js @@ -10,11 +10,11 @@ try { } export class Tokenizer { - async getHistory (groupId, date = new Date(), duration = 0) { + async getHistory (e, groupId, date = new Date(), duration = 0, userId) { if (!groupId) { throw new Error('no valid group id') } - let group = Bot.pickGroup(groupId, true) + let group = e.bot.pickGroup(groupId, true) let latestChat = await group.getChatHistory(0, 1) let seq = latestChat[0].seq let chats = latestChat @@ -41,14 +41,15 @@ export class Tokenizer { let startOfSpecifiedDate = date.getTime() // if duration > 0, go back to the specified number of hours if (duration > 0) { - // duration should be in range [0, 24] - duration = Math.min(duration, 24) - startOfSpecifiedDate = currentTime - (duration * 60 * 60 * 1000) + // duration should be in range [0, 24] + // duration = Math.min(duration, 24) + startOfSpecifiedDate = currentTime - (duration * 60 * 60 * 1000) } - // Step 4: Get the end of the specified date by adding 24 hours (in milliseconds) - const endOfSpecifiedDate = startOfSpecifiedDate + (24 * 60 * 60 * 1000) - while (isTimestampInDateRange(chats[0]?.time, startOfSpecifiedDate, endOfSpecifiedDate) && isTimestampInDateRange(chats[chats.length - 1]?.time, startOfSpecifiedDate, endOfSpecifiedDate)) { + // Step 4: Get the end of the specified date by current time + const endOfSpecifiedDate = currentTime + while (isTimestampInDateRange(chats[0]?.time, startOfSpecifiedDate, endOfSpecifiedDate) && + isTimestampInDateRange(chats[chats.length - 1]?.time, startOfSpecifiedDate, endOfSpecifiedDate)) { let chatHistory = await group.getChatHistory(seq, 20) if (chatHistory.length === 1) { if (chats[0].seq === chatHistory[0].seq) { @@ -64,28 +65,31 @@ export class Tokenizer { } } chats = chats.filter(chat => isTimestampInDateRange(chat.time, startOfSpecifiedDate, endOfSpecifiedDate)) + if (userId) { + chats = chats.filter(chat => chat.sender.user_id === userId) + } return chats } - async getKeywordTopK (groupId, topK = 100, duration = 0) { + async getKeywordTopK (e, groupId, topK = 100, duration = 0, userId) { if (!nodejieba) { throw new Error('未安装node-rs/jieba,娱乐功能-词云统计不可用') } // duration represents the number of hours to go back, should in range [0, 24] - let chats = await this.getHistory(groupId, new Date(), duration) - let duration_str = duration > 0 ? `${duration}小时` : '今日' - logger.mark(`聊天记录拉取完成,获取到${duration_str}内${chats.length}条聊天记录,准备分词中`) - + let chats = await this.getHistory(e, groupId, new Date(), duration, userId) + let durationStr = duration > 0 ? `${duration}小时` : '今日' + logger.mark(`聊天记录拉取完成,获取到${durationStr}内${chats.length}条聊天记录,准备分词中`) + const _path = process.cwd() let stopWordsPath = `${_path}/plugins/chatgpt-plugin/utils/wordcloud/cn_stopwords.txt` const data = fs.readFileSync(stopWordsPath) const stopWords = String(data)?.split('\n') || [] let chatContent = chats .map(c => c.message - //只统计文本内容 - .filter(item => item.type == 'text') - .map(textItem => `${textItem.text}`) - .join("").trim() + // 只统计文本内容 + .filter(item => item.type == 'text') + .map(textItem => `${textItem.text}`) + .join('').trim() ) .map(c => { let length = c.length @@ -132,6 +136,85 @@ export class Tokenizer { } } +export class ShamrockTokenizer extends Tokenizer { + async getHistory (e, groupId, date = new Date(), duration = 0, userId) { + logger.mark('当前使用Shamrock适配器') + if (!groupId) { + throw new Error('no valid group id') + } + let group = e.bot.pickGroup(groupId, true) + // 直接加大力度 + let pageSize = 500 + let chats = (await group.getChatHistory(0, pageSize, false)) || [] + // Get the current timestamp + let currentTime = date.getTime() + + // Step 2: Set the hours, minutes, seconds, and milliseconds to 0 + date.setHours(0, 0, 0, 0) + + // Step 3: Calculate the timestamp representing the start of the specified date + // duration represents the number of hours to go back + // if duration is 0, keeping the original date (start of today) + let startOfSpecifiedDate = date.getTime() + // if duration > 0, go back to the specified number of hours + if (duration > 0) { + // duration should be in range [0, 24] + // duration = Math.min(duration, 24) + startOfSpecifiedDate = currentTime - (duration * 60 * 60 * 1000) + } + + // Step 4: Get the end of the specified date by currentTime + const endOfSpecifiedDate = currentTime + let cursor = chats.length + // ------------------------------------------------------- + // | | | + // ------------------------------------------------------- + // ^ ^ + // long ago cursor+pageSize cursor current + while (isTimestampInDateRange(chats[0]?.time, startOfSpecifiedDate, endOfSpecifiedDate)) { + // 由于Shamrock消息是从最新的开始拉,结束时由于动态更新,一旦有人发送消息就会立刻停止,所以不判断结束时间 + // 拉到后面会巨卡,所以增大page减少次数 + pageSize = Math.floor(Math.max(cursor / 2, pageSize)) + cursor = cursor + pageSize + let retries = 3 + let chatHistory + while (retries >= 0) { + try { + chatHistory = await group.getChatHistory(0, cursor, false) + break + } catch (err) { + if (retries === 0) { + logger.error(err) + } + retries-- + } + } + if (retries < 0) { + logger.warn('拉不动了,就这样吧') + break + } + if (chatHistory.length === 1) { + break + } + if (chatHistory.length === chats.length) { + // 没有了!再拉也没有了 + break + } + let oldLength = chats.length + chats = chatHistory + // chats.sort(compareByTime) + if (Config.debug) { + logger.info(`拉取到${chats.length - oldLength}条聊天记录,当前已累计获取${chats.length}条聊天记录,继续拉...`) + } + } + chats = chats.filter(chat => isTimestampInDateRange(chat.time, startOfSpecifiedDate, endOfSpecifiedDate)) + if (userId) { + chats = chats.filter(chat => chat.sender.user_id === userId) + } + return chats + } +} + function isTimestampInDateRange (timestamp, startOfSpecifiedDate, endOfSpecifiedDate) { if (!timestamp) { return false diff --git a/utils/wordcloud/wordcloud.js b/utils/wordcloud/wordcloud.js index 08b1392..09d7614 100644 --- a/utils/wordcloud/wordcloud.js +++ b/utils/wordcloud/wordcloud.js @@ -1,11 +1,19 @@ -import { Tokenizer } from './tokenizer.js' +import { ShamrockTokenizer, Tokenizer } from './tokenizer.js' import { render } from '../common.js' -export async function makeWordcloud (e, groupId, duration = 0) { - let tokenizer = new Tokenizer() - let topK = await tokenizer.getKeywordTopK(groupId, 100, duration) +export async function makeWordcloud (e, groupId, duration = 0, userId) { + let tokenizer = getTokenizer(e) + let topK = await tokenizer.getKeywordTopK(e, groupId, 100, duration, userId) let list = JSON.stringify(topK) - // let list = topK - console.log(list) - await render(e, 'chatgpt-plugin', 'wordcloud/index', { list }) + logger.info(list) + let img = await render(e, 'chatgpt-plugin', 'wordcloud/index', { list }, { retType: 'base64' }) + await e.reply(img, true) +} + +function getTokenizer (e) { + if (e.adapter === 'shamrock') { + return new ShamrockTokenizer() + } else { + return new Tokenizer() + } } From e43b490edb903b8e62f941ff5ad08ed2f439db0e Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 7 Nov 2023 19:47:49 +0800 Subject: [PATCH 39/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dmicrosoft-cognit?= =?UTF-8?q?iveservices-speech-sdk=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dbd3040..b593ce4 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "js-tiktoken": "^1.0.5", "keyv": "^4.5.3", "keyv-file": "^0.2.0", - "microsoft-cognitiveservices-speech-sdk": "^1.30.1", + "microsoft-cognitiveservices-speech-sdk": "1.32.0", "node-fetch": "^3.3.1", "openai": "^3.2.1", "p-timeout": "^6.1.2", From ce65cc862f63a03049e80c391fdb66f68c3ab083 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 7 Nov 2023 19:59:10 +0800 Subject: [PATCH 40/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dlain=E4=B8=8B?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=B7=A5=E5=85=B7=E5=A4=B1=E6=95=88=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/tools/SendAudioMessageTool.js | 7 ++++++- utils/tools/SendAvatarTool.js | 8 ++++++-- utils/tools/SendDiceTool.js | 7 ++++++- utils/tools/SendMessageToSpecificGroupOrUserTool.js | 7 ++++++- utils/tools/SendPictureTool.js | 7 ++++++- utils/tools/SendRPSTool.js | 7 ++++++- 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/utils/tools/SendAudioMessageTool.js b/utils/tools/SendAudioMessageTool.js index 99b1d49..65945a0 100644 --- a/utils/tools/SendAudioMessageTool.js +++ b/utils/tools/SendAudioMessageTool.js @@ -102,7 +102,12 @@ export class SendAudioMessageTool extends AbstractTool { return `audio generation failed, error: ${JSON.stringify(err)}` } if (sendable) { - let groupList = await e.bot.getGroupList() + let groupList + try { + groupList = await e.bot.getGroupList() + } catch (err) { + groupList = e.bot.gl + } try { if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/utils/tools/SendAvatarTool.js b/utils/tools/SendAvatarTool.js index 5853b0a..ed6fde4 100644 --- a/utils/tools/SendAvatarTool.js +++ b/utils/tools/SendAvatarTool.js @@ -27,8 +27,12 @@ export class SendAvatarTool extends AbstractTool { const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber ? defaultTarget : parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber) - - let groupList = await e.bot.getGroupList() + let groupList + try { + groupList = await e.bot.getGroupList() + } catch (err) { + groupList = e.bot.gl + } console.log('sendAvatar', target, pictures) if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/utils/tools/SendDiceTool.js b/utils/tools/SendDiceTool.js index 4ba82a1..ae3df91 100644 --- a/utils/tools/SendDiceTool.js +++ b/utils/tools/SendDiceTool.js @@ -24,7 +24,12 @@ export class SendDiceTool extends AbstractTool { const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber ? defaultTarget : parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber) - let groupList = await e.bot.getGroupList() + let groupList + try { + groupList = await e.bot.getGroupList() + } catch (err) { + groupList = e.bot.gl + } num = isNaN(num) || !num ? 1 : num > 5 ? 5 : num if (groupList.get(target)) { let group = await e.bot.pickGroup(target, true) diff --git a/utils/tools/SendMessageToSpecificGroupOrUserTool.js b/utils/tools/SendMessageToSpecificGroupOrUserTool.js index c194c5e..6c71310 100644 --- a/utils/tools/SendMessageToSpecificGroupOrUserTool.js +++ b/utils/tools/SendMessageToSpecificGroupOrUserTool.js @@ -25,7 +25,12 @@ export class SendMessageToSpecificGroupOrUserTool extends AbstractTool { ? defaultTarget : parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber) - let groupList = await e.bot.getGroupList() + let groupList + try { + groupList = await e.bot.getGroupList() + } catch (err) { + groupList = e.bot.gl + } try { if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/utils/tools/SendPictureTool.js b/utils/tools/SendPictureTool.js index 89653e8..d3d81cc 100644 --- a/utils/tools/SendPictureTool.js +++ b/utils/tools/SendPictureTool.js @@ -32,7 +32,12 @@ export class SendPictureTool extends AbstractTool { let pictures = urlOfPicture.trim().split(' ') logger.mark('pictures to send: ', pictures) pictures = pictures.map(img => segment.image(img)) - let groupList = await e.bot.getGroupList() + let groupList + try { + groupList = await e.bot.getGroupList() + } catch (err) { + groupList = e.bot.gl + } try { if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/utils/tools/SendRPSTool.js b/utils/tools/SendRPSTool.js index 73f87d0..0481ba3 100644 --- a/utils/tools/SendRPSTool.js +++ b/utils/tools/SendRPSTool.js @@ -20,7 +20,12 @@ export class SendRPSTool extends AbstractTool { const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber ? defaultTarget : parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber) - let groupList = await e.bot.getGroupList() + let groupList + try { + groupList = await e.bot.getGroupList() + } catch (err) { + groupList = e.bot.gl + } if (groupList.get(target)) { let group = await e.bot.pickGroup(target, true) await group.sendMsg(segment.rps(num)) From e29e370f25cae33b053253af00652e0bdc4b075c Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 7 Nov 2023 21:37:38 +0800 Subject: [PATCH 41/47] =?UTF-8?q?fix:=20=E6=A8=A1=E5=9E=8BmaxToken?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20gpt4=E5=90=8E=E7=BB=AD=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/common.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/common.js b/utils/common.js index 03c5271..5f45572 100644 --- a/utils/common.js +++ b/utils/common.js @@ -832,8 +832,10 @@ export function getMaxModelTokens (model = 'gpt-3.5-turbo') { if (model.startsWith('gpt-3.5-turbo')) { if (model.includes('16k')) { return 16000 - } else { + } else if (model.includes('0613') || model.includes('0314')) { return 4000 + } else { + return 16000 } } else { if (model.includes('32k')) { From 0d8ef840d46585fafe315a0da01ce014e3679d85 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 7 Nov 2023 21:59:34 +0800 Subject: [PATCH 42/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=BE=A4?= =?UTF-8?q?=E5=90=8D=E6=8B=BF=E4=B8=8D=E5=88=B0=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 2 +- utils/chat.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index 58ea9b1..b407296 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -2142,7 +2142,7 @@ export class chatgpt extends plugin { opt.groupId = e.group_id opt.qq = e.sender.user_id opt.nickname = e.sender.card - opt.groupName = e.group.name + opt.groupName = e.group.name || e.group_name opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname let master = (await getMasterQQ())[0] if (master && e.group) { diff --git a/utils/chat.js b/utils/chat.js index 3263c6c..31102dd 100644 --- a/utils/chat.js +++ b/utils/chat.js @@ -1,6 +1,6 @@ export async function getChatHistoryGroup (e, num) { if (e.adapter === 'shamrock') { - return await e.group.getChatHistory(0, num) + return await e.group.getChatHistory(0, num, false) } else { let latestChats = await e.group.getChatHistory(0, 1) if (latestChats.length > 0) { From a45be2e2112e770159d3971ab887f10aa872f822 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 7 Nov 2023 22:11:09 +0800 Subject: [PATCH 43/47] =?UTF-8?q?fix:=20=E8=AF=8D=E4=BA=91bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/wordcloud/tokenizer.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/wordcloud/tokenizer.js b/utils/wordcloud/tokenizer.js index 7ec06c3..5f8e7be 100644 --- a/utils/wordcloud/tokenizer.js +++ b/utils/wordcloud/tokenizer.js @@ -59,7 +59,10 @@ export class Tokenizer { } chats.push(...chatHistory) chats.sort(compareByTime) - seq = chatHistory[0].seq + seq = chatHistory?.[0]?.seq + if (!seq) { + break + } if (Config.debug) { logger.info(`拉取到${chatHistory.length}条聊天记录,当前已累计获取${chats.length}条聊天记录,继续拉...`) } From 56a893734cd623c81efa79bbec44180b4747525a Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 7 Nov 2023 22:13:21 +0800 Subject: [PATCH 44/47] =?UTF-8?q?fix:=20=E9=99=8D=E4=BD=8E=E8=AF=8D?= =?UTF-8?q?=E4=BA=91=E9=98=88=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/wordcloud/tokenizer.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/utils/wordcloud/tokenizer.js b/utils/wordcloud/tokenizer.js index 5f8e7be..8593e11 100644 --- a/utils/wordcloud/tokenizer.js +++ b/utils/wordcloud/tokenizer.js @@ -95,15 +95,15 @@ export class Tokenizer { .join('').trim() ) .map(c => { - let length = c.length - let threshold = 10 - if (length < 100 && length > 50) { - threshold = 6 - } else if (length <= 50 && length > 25) { - threshold = 3 - } else if (length <= 25) { - threshold = 2 - } + // let length = c.length + let threshold = 2 + // if (length < 100 && length > 50) { + // threshold = 6 + // } else if (length <= 50 && length > 25) { + // threshold = 3 + // } else if (length <= 25) { + // threshold = 2 + // } return nodejieba.extract(c, threshold) }) .reduce((acc, curr) => acc.concat(curr), []) From c99019cd91f5993ad4de8edfd58dd3b9e668fcf2 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sun, 12 Nov 2023 13:50:02 +0800 Subject: [PATCH 45/47] =?UTF-8?q?fix:=20=E8=B7=9F=E8=BF=9Bshamrock?= =?UTF-8?q?=E5=92=8Clain=E7=9A=84=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/chat.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utils/chat.js b/utils/chat.js index 31102dd..8c27bad 100644 --- a/utils/chat.js +++ b/utils/chat.js @@ -1,16 +1,17 @@ export async function getChatHistoryGroup (e, num) { - if (e.adapter === 'shamrock') { - return await e.group.getChatHistory(0, num, false) - } else { + //if (e.adapter === 'shamrock') { + // return await e.group.getChatHistory(0, num, false) + //} else { let latestChats = await e.group.getChatHistory(0, 1) if (latestChats.length > 0) { let latestChat = latestChats[0] if (latestChat) { - let seq = latestChat.seq + let seq = latestChat.seq || latestChat.message_id let chats = [] while (chats.length < num) { let chatHistory = await e.group.getChatHistory(seq, 20) chats.push(...chatHistory) + seq = chatHistory[0].seq || chatHistory[0].message_id } chats = chats.slice(0, num) try { @@ -28,6 +29,6 @@ export async function getChatHistoryGroup (e, num) { return chats } } - } + // } return [] } From f246e842ec558bd691fb2a7e3498d713ea55f1ba Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 21 Nov 2023 15:41:59 +0800 Subject: [PATCH 46/47] fix: gl --- package-lock.json | 868 +++++++++++++++++- utils/common.js | 1 + utils/tools/SendAudioMessageTool.js | 2 +- utils/tools/SendAvatarTool.js | 2 +- utils/tools/SendDiceTool.js | 2 +- .../SendMessageToSpecificGroupOrUserTool.js | 2 +- utils/tools/SendPictureTool.js | 2 +- yarn.lock | 612 +++++++++++- 8 files changed, 1471 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index f09a229..c29e27c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,11 +45,15 @@ "@node-rs/jieba": "^1.6.2", "cycletls": "^1.0.21", "jimp": "^0.22.7", + "mammoth": "^1.6.0", "node-silk": "^0.1.0", + "nodejs-pptx": "^1.2.4", + "pdfjs-dist": "^3.11.174", "puppeteer-extra": "^3.3.6", "puppeteer-extra-plugin-recaptcha": "^3.6.8", "puppeteer-extra-plugin-stealth": "^2.11.2", - "sharp": "^0.32.3" + "sharp": "^0.32.3", + "xlsx": "^0.18.5" } }, "../../node_modules/.pnpm/axios@1.4.0/node_modules/axios": { @@ -1209,6 +1213,56 @@ "node": ">= 10" } }, + "node_modules/@postman/form-data": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", + "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@postman/tough-cookie": { + "version": "4.1.3-postman.1", + "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", + "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", + "optional": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@postman/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@postman/tunnel-agent": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", + "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/@slack/bolt": { "version": "3.13.2", "resolved": "https://registry.npmjs.org/@slack/bolt/-/bolt-3.13.2.tgz", @@ -1615,6 +1669,15 @@ "node": ">=16.15" } }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", @@ -1670,6 +1733,15 @@ "node": ">=0.4.0" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", @@ -1845,6 +1917,15 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "optional": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/arr-union": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/arr-union/-/arr-union-3.1.0.tgz", @@ -1883,6 +1964,15 @@ "node": ">= 0.4" } }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "optional": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, "node_modules/asn1.js": { "version": "5.4.1", "resolved": "https://registry.npmmirror.com/asn1.js/-/asn1.js-5.4.1.tgz", @@ -1894,6 +1984,24 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "optional": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", @@ -1955,6 +2063,21 @@ "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "optional": true + }, "node_modules/axios": { "version": "0.27.2", "resolved": "https://registry.npmmirror.com/axios/-/axios-0.27.2.tgz", @@ -1980,6 +2103,15 @@ "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, "node_modules/bent": { "version": "7.3.12", "resolved": "https://registry.npmmirror.com/bent/-/bent-7.3.12.tgz", @@ -2021,6 +2153,12 @@ "node": ">= 6" } }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "optional": true + }, "node_modules/bmp-js": { "version": "0.1.0", "resolved": "https://registry.npmmirror.com/bmp-js/-/bmp-js-0.1.0.tgz", @@ -2095,6 +2233,15 @@ "balanced-match": "^1.0.0" } }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "optional": true, + "dependencies": { + "base64-js": "^1.1.2" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz", @@ -2167,11 +2314,74 @@ "node": ">=14.16" } }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/canvas/node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/canvas/node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/canvas/node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "optional": true, + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chalk": { "version": "5.2.0", "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.2.0.tgz", @@ -2288,6 +2498,15 @@ "node": ">=0.10.0" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmmirror.com/color/-/color-4.2.3.tgz", @@ -2409,6 +2628,24 @@ "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "optional": true + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "optional": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz", @@ -2471,6 +2708,18 @@ } } }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -2607,6 +2856,12 @@ "node": ">=0.3.1" } }, + "node_modules/dingbat-to-unicode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz", + "integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==", + "optional": true + }, "node_modules/dom-walk": { "version": "0.1.2", "resolved": "https://registry.npmmirror.com/dom-walk/-/dom-walk-0.1.2.tgz", @@ -2632,11 +2887,30 @@ "node": ">=12" } }, + "node_modules/duck": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz", + "integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==", + "optional": true, + "dependencies": { + "underscore": "^1.13.1" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "optional": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -2933,6 +3207,12 @@ "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/external-editor/-/external-editor-3.1.0.tgz", @@ -2946,6 +3226,15 @@ "node": ">=4" } }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ], + "optional": true + }, "node_modules/fast-content-type-parse": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/fast-content-type-parse/-/fast-content-type-parse-1.0.0.tgz", @@ -2966,6 +3255,12 @@ "resolved": "https://registry.npmmirror.com/fast-fifo/-/fast-fifo-1.2.0.tgz", "integrity": "sha512-NcvQXt7Cky1cNau15FWy64IjuO8X0JijhTBBrJj1YlxlDfRkJXNaK9RFUjwpfDPzMdv7wB38jr53l9tkNLxnWg==" }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "optional": true + }, "node_modules/fast-json-stringify": { "version": "5.7.0", "resolved": "https://registry.npmmirror.com/fast-json-stringify/-/fast-json-stringify-5.7.0.tgz", @@ -3174,6 +3469,15 @@ "node": ">=0.10.0" } }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "optional": true, + "engines": { + "node": "*" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", @@ -3206,6 +3510,15 @@ "node": ">= 0.6" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", @@ -3359,6 +3672,15 @@ "node": ">= 0.4" } }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/gifwrap": { "version": "0.9.4", "resolved": "https://registry.npmmirror.com/gifwrap/-/gifwrap-0.9.4.tgz", @@ -3424,6 +3746,51 @@ "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "optional": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "optional": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", @@ -3549,6 +3916,20 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", @@ -3632,6 +4013,24 @@ "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==", "optional": true }, + "node_modules/image-size": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz", + "integrity": "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "optional": true + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", @@ -4140,6 +4539,12 @@ "node": ">= 0.4" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "optional": true + }, "node_modules/is-unicode-supported": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", @@ -4216,6 +4621,12 @@ } } }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "optional": true + }, "node_modules/it-pushable": { "version": "1.4.2", "resolved": "https://registry.npmmirror.com/it-pushable/-/it-pushable-1.4.2.tgz", @@ -4295,6 +4706,12 @@ "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "optional": true + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", @@ -4305,6 +4722,12 @@ "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "optional": true + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -4315,6 +4738,12 @@ "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.1.tgz", "integrity": "sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg==" }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "optional": true + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz", @@ -4343,6 +4772,69 @@ "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "optional": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "optional": true + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/jwa": { "version": "1.4.1", "resolved": "https://registry.npmmirror.com/jwa/-/jwa-1.4.1.tgz", @@ -4422,6 +4914,15 @@ "node": ">=0.10.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "optional": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/light-my-request": { "version": "5.10.0", "resolved": "https://registry.npmmirror.com/light-my-request/-/light-my-request-5.10.0.tgz", @@ -4498,6 +4999,17 @@ "node": ">=12" } }, + "node_modules/lop": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/lop/-/lop-0.4.1.tgz", + "integrity": "sha512-9xyho9why2A2tzm5aIcMWKvzqKsnxrf9B5I+8O30olh6lQU8PH978LqZoI4++37RBgS1Em5i54v1TFs/3wnmXQ==", + "optional": true, + "dependencies": { + "duck": "^0.1.12", + "option": "~0.2.1", + "underscore": "^1.13.1" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4536,6 +5048,39 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/mammoth": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.6.0.tgz", + "integrity": "sha512-jOwbj6BwJzxCf6jr2l1zmSemniIkLnchvELXnDJCANlJawhzyIKObIq48B8kWEPLgUUh57k7FtEO3DHFQMnjMg==", + "optional": true, + "dependencies": { + "@xmldom/xmldom": "^0.8.6", + "argparse": "~1.0.3", + "base64-js": "^1.5.1", + "bluebird": "~3.4.0", + "dingbat-to-unicode": "^1.0.1", + "jszip": "^3.7.1", + "lop": "^0.4.1", + "path-is-absolute": "^1.0.0", + "underscore": "^1.13.1", + "xmlbuilder": "^10.0.0" + }, + "bin": { + "mammoth": "bin/mammoth" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/mammoth/node_modules/xmlbuilder": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz", + "integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==", + "optional": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", @@ -4892,6 +5437,44 @@ "nan": "^2.15.0" } }, + "node_modules/nodejs-pptx": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/nodejs-pptx/-/nodejs-pptx-1.2.4.tgz", + "integrity": "sha512-qoDCsizXiIq2Slzi8cwN2M6P1iSuKAprF/vUWAVI6ZElAWKtebcqb6HAbFPy/7z1bLpGk+JtkvzP3uqdbWDizg==", + "optional": true, + "dependencies": { + "async": "^2.6.4", + "image-size": "^0.6.2", + "jszip": "^3.1.5", + "postman-request": "^2.88.1-postman.33", + "uuid": "^8.3.0", + "xml-js": "^1.5.2", + "xml2js": "^0.4.19", + "xmlbuilder": "~09.0.1", + "yarn": "^1.22.10" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodejs-pptx/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/nodejs-pptx/node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==", + "optional": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz", @@ -4944,6 +5527,15 @@ "set-blocking": "^2.0.0" } }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "optional": true, + "engines": { + "node": "*" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", @@ -5051,6 +5643,12 @@ "follow-redirects": "^1.14.8" } }, + "node_modules/option": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz", + "integrity": "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==", + "optional": true + }, "node_modules/ora": { "version": "6.3.1", "resolved": "https://registry.npmmirror.com/ora/-/ora-6.3.1.tgz", @@ -5311,6 +5909,28 @@ "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz", "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pdfjs-dist": { + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "optional": true, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" + } + }, "node_modules/peek-readable": { "version": "4.1.0", "resolved": "https://registry.npmmirror.com/peek-readable/-/peek-readable-4.1.0.tgz", @@ -5320,6 +5940,12 @@ "node": ">=8" } }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "optional": true + }, "node_modules/phin": { "version": "2.9.3", "resolved": "https://registry.npmmirror.com/phin/-/phin-2.9.3.tgz", @@ -5404,6 +6030,57 @@ "node": ">=12.13.0" } }, + "node_modules/postman-request": { + "version": "2.88.1-postman.33", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz", + "integrity": "sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==", + "optional": true, + "dependencies": { + "@postman/form-data": "~3.1.1", + "@postman/tough-cookie": "~4.1.3-postman.1", + "@postman/tunnel-agent": "^0.6.3", + "aws-sign2": "~0.7.0", + "aws4": "^1.12.0", + "brotli": "^1.3.3", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "har-validator": "~5.1.3", + "http-signature": "~1.3.1", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "^2.1.35", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.3", + "safe-buffer": "^5.1.2", + "stream-length": "^1.0.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postman-request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "optional": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/postman-request/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/prebuild-install": { "version": "7.1.1", "resolved": "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.1.tgz", @@ -5438,6 +6115,12 @@ "node": ">= 0.6.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "optional": true + }, "node_modules/process-warning": { "version": "2.2.0", "resolved": "https://registry.npmmirror.com/process-warning/-/process-warning-2.2.0.tgz", @@ -5471,6 +6154,12 @@ "node": ">= 0.10" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "optional": true + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz", @@ -5835,6 +6524,12 @@ "node": ">=0.6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, "node_modules/queue-tick": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", @@ -6004,6 +6699,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "optional": true + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -6253,6 +6954,12 @@ "resolved": "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "optional": true + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -6449,6 +7156,49 @@ "node": ">= 10.x" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "optional": true + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "optional": true, + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "optional": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", @@ -6479,6 +7229,21 @@ "node": ">= 0.4" } }, + "node_modules/stream-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz", + "integrity": "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg==", + "optional": true, + "dependencies": { + "bluebird": "^2.6.2" + } + }, + "node_modules/stream-length/node_modules/bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==", + "optional": true + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz", @@ -6887,6 +7652,12 @@ "node": "*" } }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "optional": true + }, "node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-2.19.0.tgz", @@ -6942,6 +7713,12 @@ "which-boxed-primitive": "^1.0.2" } }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "optional": true + }, "node_modules/undici": { "version": "5.22.1", "resolved": "https://registry.npmmirror.com/undici/-/undici-5.22.1.tgz", @@ -6977,6 +7754,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/utif2": { "version": "4.1.0", "resolved": "https://registry.npmmirror.com/utif2/-/utif2-4.1.0.tgz", @@ -7030,6 +7817,20 @@ "node": ">= 0.8" } }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", @@ -7155,6 +7956,24 @@ "node": ">=12" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -7224,6 +8043,39 @@ "xtend": "^4.0.0" } }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "optional": true, + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "optional": true, + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/xml-parse-from-string": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", @@ -7266,6 +8118,20 @@ "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/yarn": { + "version": "1.22.19", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.19.tgz", + "integrity": "sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ==", + "hasInstallScript": true, + "optional": true, + "bin": { + "yarn": "bin/yarn.js", + "yarnpkg": "bin/yarn.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz", diff --git a/utils/common.js b/utils/common.js index 1c63816..5493bc4 100644 --- a/utils/common.js +++ b/utils/common.js @@ -1049,6 +1049,7 @@ export function isPureText (filename) { /** * 从文件中提取文本内容 * @param fileMsgElem MessageElem + * @param e * @returns {Promise<{}>} 提取的文本内容和文件名 */ export async function extractContentFromFile (fileMsgElem, e) { diff --git a/utils/tools/SendAudioMessageTool.js b/utils/tools/SendAudioMessageTool.js index 99b1d49..cdfdef7 100644 --- a/utils/tools/SendAudioMessageTool.js +++ b/utils/tools/SendAudioMessageTool.js @@ -102,7 +102,7 @@ export class SendAudioMessageTool extends AbstractTool { return `audio generation failed, error: ${JSON.stringify(err)}` } if (sendable) { - let groupList = await e.bot.getGroupList() + let groupList = e.bot.gl || new Map() try { if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/utils/tools/SendAvatarTool.js b/utils/tools/SendAvatarTool.js index 5853b0a..2973db9 100644 --- a/utils/tools/SendAvatarTool.js +++ b/utils/tools/SendAvatarTool.js @@ -28,7 +28,7 @@ export class SendAvatarTool extends AbstractTool { ? defaultTarget : parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber) - let groupList = await e.bot.getGroupList() + let groupList = e.bot.gl || new Map() console.log('sendAvatar', target, pictures) if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/utils/tools/SendDiceTool.js b/utils/tools/SendDiceTool.js index 4ba82a1..ec34dd1 100644 --- a/utils/tools/SendDiceTool.js +++ b/utils/tools/SendDiceTool.js @@ -24,7 +24,7 @@ export class SendDiceTool extends AbstractTool { const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber ? defaultTarget : parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber) - let groupList = await e.bot.getGroupList() + let groupList = e.bot.gl || new Map() num = isNaN(num) || !num ? 1 : num > 5 ? 5 : num if (groupList.get(target)) { let group = await e.bot.pickGroup(target, true) diff --git a/utils/tools/SendMessageToSpecificGroupOrUserTool.js b/utils/tools/SendMessageToSpecificGroupOrUserTool.js index c194c5e..bdb5cb8 100644 --- a/utils/tools/SendMessageToSpecificGroupOrUserTool.js +++ b/utils/tools/SendMessageToSpecificGroupOrUserTool.js @@ -25,7 +25,7 @@ export class SendMessageToSpecificGroupOrUserTool extends AbstractTool { ? defaultTarget : parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber) - let groupList = await e.bot.getGroupList() + let groupList = e.bot.gl || new Map() try { if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/utils/tools/SendPictureTool.js b/utils/tools/SendPictureTool.js index 89653e8..da46c5c 100644 --- a/utils/tools/SendPictureTool.js +++ b/utils/tools/SendPictureTool.js @@ -32,7 +32,7 @@ export class SendPictureTool extends AbstractTool { let pictures = urlOfPicture.trim().split(' ') logger.mark('pictures to send: ', pictures) pictures = pictures.map(img => segment.image(img)) - let groupList = await e.bot.getGroupList() + let groupList = e.bot.gl || new Map() try { if (groupList.get(target)) { let group = await e.bot.pickGroup(target) diff --git a/yarn.lock b/yarn.lock index 0391f81..431261d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -482,7 +482,7 @@ resolved "https://registry.npmmirror.com/@lukeed/ms/-/ms-2.0.1.tgz" integrity sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA== -"@mapbox/node-pre-gyp@^1.0.9": +"@mapbox/node-pre-gyp@^1.0.0", "@mapbox/node-pre-gyp@^1.0.9": version "1.0.10" resolved "https://registry.npmmirror.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz" integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA== @@ -521,6 +521,32 @@ "@node-rs/jieba-win32-ia32-msvc" "1.7.0" "@node-rs/jieba-win32-x64-msvc" "1.7.0" +"@postman/form-data@~3.1.1": + version "3.1.1" + resolved "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz" + integrity sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +"@postman/tough-cookie@~4.1.3-postman.1": + version "4.1.3-postman.1" + resolved "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz" + integrity sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +"@postman/tunnel-agent@^0.6.3": + version "0.6.3" + resolved "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz" + integrity sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg== + dependencies: + safe-buffer "^5.0.1" + "@slack/bolt@^3.13.2": version "3.13.2" resolved "https://registry.npmjs.org/@slack/bolt/-/bolt-3.13.2.tgz" @@ -814,6 +840,11 @@ resolved "https://registry.npmmirror.com/@waylaidwanderer/fetch-event-source/-/fetch-event-source-3.0.1.tgz" integrity sha512-gkc7vmBW9uulRj7tY30/1D8iBrpcgphBpI+e7LP744x/hAzaQxUuyF+n4O5dctKx+dE3i4BFuCWMEz9fAx2jlQ== +"@xmldom/xmldom@^0.8.6": + version "0.8.10" + resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz" + integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== + abbrev@1: version "1.1.1" resolved "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz" @@ -849,6 +880,11 @@ acorn@^8.4.1: resolved "https://registry.npmmirror.com/acorn/-/acorn-8.9.0.tgz" integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ== +adler-32@~1.3.0: + version "1.3.1" + resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz" + integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A== + agent-base@^6.0.1, agent-base@6: version "6.0.2" resolved "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz" @@ -875,6 +911,16 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" +ajv@^6.12.3: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@^8.0.0, ajv@^8.10.0, ajv@^8.11.0, ajv@^8.12.0: version "8.12.0" resolved "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz" @@ -968,6 +1014,13 @@ arg@^4.1.0: resolved "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +argparse@~1.0.3: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + arr-union@^3.1.0: version "3.1.0" resolved "https://registry.npmmirror.com/arr-union/-/arr-union-3.1.0.tgz" @@ -1007,6 +1060,25 @@ asn1.js@^5.0.0: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@^1.0.0, assert-plus@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + +async@^2.6.4: + version "2.6.4" + resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz" @@ -1039,6 +1111,16 @@ avvio@^8.2.1: debug "^4.0.0" fastq "^1.6.1" +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.12.0: + version "1.12.0" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz" + integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== + axios@^0.26.0: version "0.26.1" resolved "https://registry.npmmirror.com/axios/-/axios-0.26.1.tgz" @@ -1064,11 +1146,18 @@ balanced-match@^1.0.0: resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.1.2, base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + bent@^7.3.12: version "7.3.12" resolved "https://registry.npmmirror.com/bent/-/bent-7.3.12.tgz" @@ -1105,6 +1194,16 @@ bl@^5.0.0: inherits "^2.0.4" readable-stream "^3.4.0" +bluebird@^2.6.2: + version "2.11.0" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz" + integrity sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ== + +bluebird@~3.4.0: + version "3.4.7" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz" + integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== + bmp-js@^0.1.0: version "0.1.0" resolved "https://registry.npmmirror.com/bmp-js/-/bmp-js-0.1.0.tgz" @@ -1162,6 +1261,13 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" +brotli@^1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz" + integrity sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg== + dependencies: + base64-js "^1.1.2" + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" @@ -1231,11 +1337,28 @@ camelcase@^7.0.1: resolved "https://registry.npmmirror.com/camelcase/-/camelcase-7.0.1.tgz" integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== +canvas@^2.11.2: + version "2.11.2" + resolved "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz" + integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + nan "^2.17.0" + simple-get "^3.0.3" + caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== +cfb@~1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz" + integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== + dependencies: + adler-32 "~1.3.0" + crc-32 "~1.2.0" + chalk@^2.0.0: version "2.4.2" resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz" @@ -1342,6 +1465,11 @@ clone@^1.0.2: resolved "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== +codepage@~1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz" + integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz" @@ -1387,7 +1515,7 @@ color@^4.2.3: color-convert "^2.0.1" color-string "^1.9.0" -combined-stream@^1.0.6, combined-stream@^1.0.8: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -1440,6 +1568,16 @@ cookie@^0.5.0, cookie@0.5.0: resolved "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +core-util-is@~1.0.0, core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +crc-32@~1.2.0, crc-32@~1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + create-require@^1.1.0: version "1.1.1" resolved "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz" @@ -1467,6 +1605,13 @@ cycletls@^1.0.21: "@types/node" "^17.0.24" ws "^7.5.7" +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + data-uri-to-buffer@^4.0.0: version "4.0.1" resolved "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz" @@ -1507,6 +1652,13 @@ debug@2.6.9: dependencies: ms "2.0.0" +decompress-response@^4.2.0: + version "4.2.1" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz" + integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== + dependencies: + mimic-response "^2.0.0" + decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz" @@ -1579,6 +1731,11 @@ diff@^5.1.0: resolved "https://registry.npmmirror.com/diff/-/diff-5.1.0.tgz" integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== +dingbat-to-unicode@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz" + integrity sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w== + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.npmmirror.com/dom-walk/-/dom-walk-0.1.2.tgz" @@ -1596,11 +1753,26 @@ dotenv@^16.0.3: resolved "https://registry.npmmirror.com/dotenv/-/dotenv-16.3.0.tgz" integrity sha512-tHB+hmf8MRCkT3VVivGiG8kq9HiGTmQ3FzOKgztfpJQH1IWuZTOvKSJmHNnQPowecAmkCJhLrxdPhOr06LLqIQ== +duck@^0.1.12: + version "0.1.12" + resolved "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz" + integrity sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg== + dependencies: + underscore "^1.13.1" + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + ecdsa-sig-formatter@1.0.11: version "1.0.11" resolved "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" @@ -1849,6 +2021,11 @@ express@^4.16.4: utils-merge "1.0.1" vary "~1.1.2" +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + external-editor@^3.0.3: version "3.1.0" resolved "https://registry.npmmirror.com/external-editor/-/external-editor-3.1.0.tgz" @@ -1858,6 +2035,11 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" +extsprintf@^1.2.0, extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + fast-content-type-parse@^1.0.0: version "1.0.0" resolved "https://registry.npmmirror.com/fast-content-type-parse/-/fast-content-type-parse-1.0.0.tgz" @@ -1878,6 +2060,11 @@ fast-fifo@^1.0.0, fast-fifo@^1.1.0, fast-fifo@^1.2.0: resolved "https://registry.npmmirror.com/fast-fifo/-/fast-fifo-1.2.0.tgz" integrity sha512-NcvQXt7Cky1cNau15FWy64IjuO8X0JijhTBBrJj1YlxlDfRkJXNaK9RFUjwpfDPzMdv7wB38jr53l9tkNLxnWg== +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + fast-json-stringify@^5.7.0: version "5.7.0" resolved "https://registry.npmmirror.com/fast-json-stringify/-/fast-json-stringify-5.7.0.tgz" @@ -2037,6 +2224,11 @@ for-own@^0.1.3: dependencies: for-in "^1.0.1" +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + form-data@^2.5.0: version "2.5.1" resolved "https://registry.npmmirror.com/form-data/-/form-data-2.5.1.tgz" @@ -2067,6 +2259,11 @@ forwarded@0.2.0: resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== +frac@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz" + integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== + fresh@0.5.2: version "0.5.2" resolved "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz" @@ -2170,6 +2367,13 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + gifwrap@^0.9.2: version "0.9.4" resolved "https://registry.npmmirror.com/gifwrap/-/gifwrap-0.9.4.tgz" @@ -2233,6 +2437,19 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz" @@ -2311,6 +2528,15 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +http-signature@~1.3.1: + version "1.3.6" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz" + integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== + dependencies: + assert-plus "^1.0.0" + jsprim "^2.0.2" + sshpk "^1.14.1" + https-proxy-agent@^4.0.0: version "4.0.0" resolved "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz" @@ -2359,6 +2585,16 @@ image-q@^4.0.0: dependencies: "@types/node" "16.9.1" +image-size@^0.6.2: + version "0.6.3" + resolved "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz" + integrity sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz" @@ -2367,7 +2603,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@2, inherits@2.0.4: +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2, inherits@2.0.4: version "2.0.4" resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2603,6 +2839,11 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" @@ -2632,6 +2873,11 @@ isarray@^2.0.5: resolved "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz" @@ -2650,6 +2896,11 @@ isomorphic-fetch@^3.0.0: node-fetch "^2.6.1" whatwg-fetch "^3.4.1" +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + it-pushable@^1.4.2: version "1.4.2" resolved "https://registry.npmmirror.com/it-pushable/-/it-pushable-1.4.2.tgz" @@ -2709,6 +2960,11 @@ js-tokens@^4.0.0: resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz" @@ -2719,6 +2975,11 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + json-schema-traverse@^1.0.0: version "1.0.0" resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" @@ -2729,6 +2990,16 @@ json-schema-typed@^8.0.1: resolved "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.1.tgz" integrity sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg== +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz" @@ -2755,6 +3026,26 @@ jsonwebtoken@^9.0.0: ms "^2.1.1" semver "^7.3.8" +jsprim@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz" + integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +jszip@^3.1.5, jszip@^3.7.1: + version "3.10.1" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + jwa@^1.4.1: version "1.4.1" resolved "https://registry.npmmirror.com/jwa/-/jwa-1.4.1.tgz" @@ -2812,6 +3103,13 @@ lazy-cache@^1.0.3: resolved "https://registry.npmmirror.com/lazy-cache/-/lazy-cache-1.0.4.tgz" integrity sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ== +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + light-my-request@^5.9.1: version "5.10.0" resolved "https://registry.npmmirror.com/light-my-request/-/light-my-request-5.10.0.tgz" @@ -2852,7 +3150,7 @@ lodash.isstring@^4.0.1: resolved "https://registry.npmmirror.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== -lodash@^4.17.21: +lodash@^4.17.14, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -2873,6 +3171,15 @@ log-symbols@^5.1.0: chalk "^5.0.0" is-unicode-supported "^1.1.0" +lop@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/lop/-/lop-0.4.1.tgz" + integrity sha512-9xyho9why2A2tzm5aIcMWKvzqKsnxrf9B5I+8O30olh6lQU8PH978LqZoI4++37RBgS1Em5i54v1TFs/3wnmXQ== + dependencies: + duck "^0.1.12" + option "~0.2.1" + underscore "^1.13.1" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz" @@ -2892,6 +3199,22 @@ make-error@^1.1.1: resolved "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +mammoth@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mammoth/-/mammoth-1.6.0.tgz" + integrity sha512-jOwbj6BwJzxCf6jr2l1zmSemniIkLnchvELXnDJCANlJawhzyIKObIq48B8kWEPLgUUh57k7FtEO3DHFQMnjMg== + dependencies: + "@xmldom/xmldom" "^0.8.6" + argparse "~1.0.3" + base64-js "^1.5.1" + bluebird "~3.4.0" + dingbat-to-unicode "^1.0.1" + jszip "^3.7.1" + lop "^0.4.1" + path-is-absolute "^1.0.0" + underscore "^1.13.1" + xmlbuilder "^10.0.0" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz" @@ -2937,7 +3260,7 @@ mime-db@1.52.0: resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -2969,6 +3292,11 @@ mimic-fn@^4.0.0: resolved "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-4.0.0.tgz" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +mimic-response@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz" + integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz" @@ -3080,7 +3408,7 @@ mute-stream@1.0.0: resolved "https://registry.npmmirror.com/mute-stream/-/mute-stream-1.0.0.tgz" integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== -nan@^2.15.0: +nan@^2.15.0, nan@^2.17.0: version "2.17.0" resolved "https://registry.npmmirror.com/nan/-/nan-2.17.0.tgz" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== @@ -3143,6 +3471,21 @@ node-silk@^0.1.0: "@mapbox/node-pre-gyp" "^1.0.9" nan "^2.15.0" +nodejs-pptx@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/nodejs-pptx/-/nodejs-pptx-1.2.4.tgz" + integrity sha512-qoDCsizXiIq2Slzi8cwN2M6P1iSuKAprF/vUWAVI6ZElAWKtebcqb6HAbFPy/7z1bLpGk+JtkvzP3uqdbWDizg== + dependencies: + async "^2.6.4" + image-size "^0.6.2" + jszip "^3.1.5" + postman-request "^2.88.1-postman.33" + uuid "^8.3.0" + xml-js "^1.5.2" + xml2js "^0.4.19" + xmlbuilder "~09.0.1" + yarn "^1.22.10" + nopt@^5.0.0: version "5.0.0" resolved "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz" @@ -3177,6 +3520,11 @@ npmlog@^5.0.1: gauge "^3.0.0" set-blocking "^2.0.0" +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz" @@ -3246,6 +3594,11 @@ openai@^3.2.1: axios "^0.26.0" form-data "^4.0.0" +option@~0.2.1: + version "0.2.4" + resolved "https://registry.npmjs.org/option/-/option-0.2.4.tgz" + integrity sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A== + ora@^5.4.1: version "5.4.1" resolved "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz" @@ -3358,7 +3711,7 @@ p-timeout@^6.1.1, p-timeout@^6.1.2: resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz" integrity sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ== -pako@^1.0.11: +pako@^1.0.11, pako@~1.0.2: version "1.0.11" resolved "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -3426,11 +3779,29 @@ path-to-regexp@0.1.7: resolved "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path2d-polyfill@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz" + integrity sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA== + +pdfjs-dist@^3.11.174: + version "3.11.174" + resolved "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz" + integrity sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA== + optionalDependencies: + canvas "^2.11.2" + path2d-polyfill "^2.0.1" + peek-readable@^4.1.0: version "4.1.0" resolved "https://registry.npmmirror.com/peek-readable/-/peek-readable-4.1.0.tgz" integrity sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg== +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + phin@^2.9.1: version "2.9.3" resolved "https://registry.npmmirror.com/phin/-/phin-2.9.3.tgz" @@ -3495,6 +3866,34 @@ pngjs@^6.0.0: resolved "https://registry.npmmirror.com/pngjs/-/pngjs-6.0.0.tgz" integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== +postman-request@^2.88.1-postman.33: + version "2.88.1-postman.33" + resolved "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz" + integrity sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA== + dependencies: + "@postman/form-data" "~3.1.1" + "@postman/tough-cookie" "~4.1.3-postman.1" + "@postman/tunnel-agent" "^0.6.3" + aws-sign2 "~0.7.0" + aws4 "^1.12.0" + brotli "^1.3.3" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + har-validator "~5.1.3" + http-signature "~1.3.1" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "^2.1.35" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.3" + safe-buffer "^5.1.2" + stream-length "^1.0.2" + uuid "^8.3.2" + prebuild-install@^7.1.1: version "7.1.1" resolved "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.1.tgz" @@ -3513,6 +3912,11 @@ prebuild-install@^7.1.1: tar-fs "^2.0.0" tunnel-agent "^0.6.0" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + process-warning@^2.0.0, process-warning@^2.2.0: version "2.2.0" resolved "https://registry.npmmirror.com/process-warning/-/process-warning-2.2.0.tgz" @@ -3543,6 +3947,11 @@ proxy-addr@^2.0.7, proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + pump@^3.0.0: version "3.0.0" resolved "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz" @@ -3551,7 +3960,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.3.0" resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== @@ -3612,6 +4021,11 @@ puppeteer-extra@*, puppeteer-extra@^3.3.6: debug "^4.1.1" deepmerge "^4.2.2" +qs@~6.5.3: + version "6.5.3" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + qs@6.11.0: version "6.11.0" resolved "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz" @@ -3619,6 +4033,11 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + queue-tick@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz" @@ -3723,6 +4142,19 @@ readable-stream@^4.0.0: events "^3.3.0" process "^0.11.10" +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readable-web-to-node-stream@^3.0.0: version "3.0.2" resolved "https://registry.npmmirror.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz" @@ -3754,6 +4186,11 @@ require-from-string@^2.0.2: resolved "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz" @@ -3814,11 +4251,16 @@ rxjs@^7.5.6, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-buffer@^5.0.1, safe-buffer@~5.2.0, safe-buffer@5.2.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0, safe-buffer@5.2.1: version "5.2.1" resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz" @@ -3840,12 +4282,12 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.npmmirror.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== -safer-buffer@^2.1.0, "safer-buffer@>= 2.1.2 < 3": +safer-buffer@^2.0.2, safer-buffer@^2.1.0, "safer-buffer@>= 2.1.2 < 3", safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@>=0.6.0: +sax@^1.2.4, sax@>=0.6.0: version "1.2.4" resolved "https://registry.npmmirror.com/sax/-/sax-1.2.4.tgz" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -3916,6 +4358,11 @@ set-cookie-parser@^2.4.1: resolved "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz" integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz" @@ -3976,6 +4423,15 @@ simple-concat@^1.0.0: resolved "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== +simple-get@^3.0.3: + version "3.1.1" + resolved "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz" + integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== + dependencies: + decompress-response "^4.2.0" + once "^1.3.1" + simple-concat "^1.0.0" + simple-get@^4.0.0, simple-get@^4.0.1: version "4.0.1" resolved "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz" @@ -4030,6 +4486,33 @@ split2@^4.0.0: resolved "https://registry.npmmirror.com/split2/-/split2-4.2.0.tgz" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +ssf@~0.11.2: + version "0.11.2" + resolved "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz" + integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== + dependencies: + frac "~1.1.2" + +sshpk@^1.14.1: + version "1.18.0" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + statuses@2.0.1: version "2.0.1" resolved "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz" @@ -4049,6 +4532,13 @@ stop-iteration-iterator@^1.0.0: dependencies: internal-slot "^1.0.4" +stream-length@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz" + integrity sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg== + dependencies: + bluebird "^2.6.2" + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz" @@ -4069,6 +4559,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + "string-width@^1.0.2 || 2 || 3 || 4": version "4.2.3" resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz" @@ -4335,6 +4832,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + type-fest@^0.21.3: version "0.21.3" resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz" @@ -4382,6 +4884,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +underscore@^1.13.1: + version "1.13.6" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz" + integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== + undici@^5.0.0, undici@^5.20.0, undici@^5.21.0, undici@^5.22.1: version "5.22.1" resolved "https://registry.npmmirror.com/undici/-/undici-5.22.1.tgz" @@ -4394,6 +4901,11 @@ universalify@^0.1.0: resolved "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^2.0.0: version "2.0.0" resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz" @@ -4411,6 +4923,14 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + utif2@^4.0.1: version "4.1.0" resolved "https://registry.npmmirror.com/utif2/-/utif2-4.1.0.tgz" @@ -4418,7 +4938,7 @@ utif2@^4.0.1: dependencies: pako "^1.0.11" -util-deprecate@^1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -4428,6 +4948,16 @@ utils-merge@1.0.1: resolved "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^9.0.0: version "9.0.0" resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.0.tgz" @@ -4451,6 +4981,15 @@ vary@~1.1.2: resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz" @@ -4530,6 +5069,16 @@ widest-line@^4.0.1: dependencies: string-width "^5.0.1" +wmf@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" + integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== + +word@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/word/-/word-0.3.0.tgz" + integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== + wrap-ansi@^6.0.1: version "6.2.0" resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz" @@ -4583,12 +5132,32 @@ xhr@^2.0.1: parse-headers "^2.0.0" xtend "^4.0.0" +xlsx@^0.18.5: + version "0.18.5" + resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz" + integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ== + dependencies: + adler-32 "~1.3.0" + cfb "~1.2.1" + codepage "~1.15.0" + crc-32 "~1.2.1" + ssf "~0.11.2" + wmf "~1.0.1" + word "~0.3.0" + +xml-js@^1.5.2: + version "1.6.11" + resolved "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + xml-parse-from-string@^1.0.0: version "1.0.1" resolved "https://registry.npmmirror.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz" integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== -xml2js@^0.4.5: +xml2js@^0.4.19, xml2js@^0.4.5: version "0.4.23" resolved "https://registry.npmmirror.com/xml2js/-/xml2js-0.4.23.tgz" integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== @@ -4596,6 +5165,16 @@ xml2js@^0.4.5: sax ">=0.6.0" xmlbuilder "~11.0.0" +xmlbuilder@^10.0.0: + version "10.1.1" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz" + integrity sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg== + +xmlbuilder@~09.0.1: + version "9.0.7" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz" + integrity sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ== + xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz" @@ -4611,6 +5190,11 @@ yallist@^4.0.0: resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yarn@^1.22.10: + version "1.22.19" + resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.19.tgz" + integrity sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ== + yn@3.1.1: version "3.1.1" resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz" From 46d88c266930d563c6cb480155e8ba2824cbe936 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Tue, 21 Nov 2023 16:31:29 +0800 Subject: [PATCH 47/47] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=96=B5?= =?UTF-8?q?=E5=B4=BD=E5=A4=9A=E9=80=82=E9=85=8D=E5=99=A8=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=AE=B1=E7=99=BB=E5=BD=95=EF=BC=9B=E7=A7=BB=E9=99=A4crypto?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- guoba.support.js | 49 +----- server/modules/user.js | 340 ++++++++++++++++++++------------------- utils/common.js | 1 + utils/config.js | 2 +- utils/xinghuo/xinghuo.js | 79 ++++----- 5 files changed, 216 insertions(+), 255 deletions(-) diff --git a/guoba.support.js b/guoba.support.js index 7ca1260..4e85cd6 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -315,7 +315,7 @@ export function supportGuoba () { { field: 'model', label: 'OpenAI 模型', - bottomHelpMessage: 'gpt-4, gpt-4-0613, gpt-4-32k, gpt-4-32k-0613, gpt-3.5-turbo, gpt-3.5-turbo-0613, gpt-3.5-turbo-16k-0613。默认为gpt-3.5-turbo,gpt-4需账户支持', + bottomHelpMessage: 'gpt-4, gpt-4-0613, gpt-4-1106, gpt-4-32k, gpt-4-32k-0613, gpt-3.5-turbo, gpt-3.5-turbo-0613, gpt-3.5-turbo-1106, gpt-3.5-turbo-16k-0613。默认为gpt-3.5-turbo,gpt-4需账户支持', component: 'Input' }, { @@ -456,7 +456,7 @@ export function supportGuoba () { { field: 'sydneyWebsocketUseProxy', label: '对话使用sydney反代', - bottomHelpMessage: '【一般情况无需也不建议开启】默认情况下仅创建对话走反代,对话时仍然直连微软。开启本选项将使对话过程也走反,需反代支持', + bottomHelpMessage: '默认情况下仅创建对话走反代,对话时仍然直连微软。开启本选项将使对话过程也走反代,需反代支持。默认开启', component: 'Switch' }, { @@ -505,40 +505,6 @@ export function supportGuoba () { bottomHelpMessage: '使用GPT-4,注意试用配额较低,如果用不了就关掉', component: 'Switch' }, - { - label: '以下为浏览器方式的配置.(Deprecated)', - component: 'Divider' - }, - { - field: 'username', - label: '用户名', - bottomHelpMessage: 'OpenAI用户名。', - component: 'Input' - }, - { - field: 'password', - label: '密码', - bottomHelpMessage: 'OpenAI密码。', - component: 'InputPassword' - }, - { - field: 'UA', - label: '浏览器UA', - bottomHelpMessage: '模拟浏览器UA,无特殊需求保持默认即可', - component: 'InputTextArea' - }, - { - field: 'headless', - label: '无头模式', - bottomHelpMessage: '无界面的服务器可以开启,但遇到验证码时可能无法使用。(实测很容易卡住,几乎不可用)', - component: 'Switch' - }, - { - field: 'chromePath', - label: 'Chrome路径', - bottomHelpMessage: '为空使用默认puppeteer的chromium,也可以传递自己本机安装的Chrome可执行文件地址,提高通过率。windows可以是‘C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe’,linux通过which查找路径', - component: 'Input' - }, { label: '以下为Slack Claude方式的配置', component: 'Divider' @@ -625,16 +591,6 @@ export function supportGuoba () { bottomHelpMessage: '等待响应的超时时间,单位为秒,默认为120。如果不使用反代而是使用代理可以适当调低。', component: 'InputNumber' }, - { - label: '以下为ChatGLM方式的配置', - component: 'Divider' - }, - { - field: 'chatglmBaseUrl', - label: 'ChatGLM API地址', - bottomHelpMessage: '如 http://localhost:8080', - component: 'Input' - }, { label: '以下为星火方式的配置', component: 'Divider' @@ -649,6 +605,7 @@ export function supportGuoba () { { label: '体验版', value: 'web' }, { label: '讯飞星火认知大模型V1.5', value: 'api' }, { label: '讯飞星火认知大模型V2.0', value: 'apiv2' }, + { label: '讯飞星火认知大模型V3.0', value: 'apiv3' }, { label: '讯飞星火助手', value: 'assistants' } ] } diff --git a/server/modules/user.js b/server/modules/user.js index 1677c22..d5f41a4 100644 --- a/server/modules/user.js +++ b/server/modules/user.js @@ -2,170 +2,182 @@ import { UserInfo, AddUser } from './user_data.js' import { randomString, getUserData, getMasterQQ, getUin } from '../../utils/common.js' import fs from 'fs' -async function User(fastify, options) { - // 登录 - fastify.post('/login', async (request, reply) => { - const body = request.body || {} - let guobaLoginService - let guobaAPI = '' - try { - let { LoginService } = await import('../../../Guoba-Plugin/server/service/both/LoginService.js') - let { getAllWebAddress } = await import('../../../Guoba-Plugin/utils/common.js') - guobaLoginService = new LoginService() - guobaAPI = await getAllWebAddress() - } - catch (err) { - console.error(err) - guobaLoginService = { - signToken: () => {return null} - } - } - if (body.qq && body.passwd) { - const token = randomString(32) - if (body.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) { - const guobaToken = await guobaLoginService.signToken(body.qq) - AddUser({ user: body.qq, token: token, autho: 'admin' }) - reply.setCookie('token', token, { path: '/' }) - reply.send({ login: true, autho: 'admin', token: token, guobaToken: guobaToken, guoba: guobaAPI }) - } else { - const user = await getUserData(body.qq) - if (user.passwd != '' && user.passwd === body.passwd) { - AddUser({ user: body.qq, token: token, autho: 'user' }) - reply.setCookie('token', token, { path: '/' }) - reply.send({ login: true, autho: 'user', token: token }) - } else { - reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改` }) - } - } - } else if (body.otp) { - const token = randomString(32) - const opt = await redis.get(`CHATGPT:SERVER_QUICK`) - if (opt && body.otp == opt) { - const guobaToken = await guobaLoginService.signToken(getUin()) - AddUser({ user: getUin(), token: token, autho: 'admin' }) - reply.setCookie('token', token, { path: '/' }) - reply.send({ login: true, autho: 'admin', token: token, user: getUin(), guobaToken: guobaToken, guoba: guobaAPI }) - } else { - reply.send({ login: false, err: `快捷登录代码错误,请检查后重试` }) - } - } else { - reply.send({ login: false, err: '未输入用户名或密码' }) - } - return reply - }) - // 快速登录 - fastify.post('/quick', async (request, reply) => { - const otp = randomString(6) - await redis.set( - `CHATGPT:SERVER_QUICK`, - otp, - { EX: 60000 } - ) - const master = (await getMasterQQ())[0] - if (Array.isArray(Bot.uin)) { - Bot.pickFriend(master).sendMsg(`收到工具箱快捷登录请求,1分钟内有效:${otp}`) - } else { - Bot.sendPrivateMsg(master, `收到工具箱快捷登录请求,1分钟内有效:${otp}`, false) - } - reply.send({ state: true }) - return reply - }) - // 检查用户是否存在 - fastify.post('/verify', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - const user = UserInfo(token) - if (!user || token === 'unknown') { - reply.send({ - verify: false, - }) - return - } - reply.send({ - verify: true, - user: user.user, - autho: user.autho, - version: 10016, - }) - return reply - }) - // 获取用户数据 - fastify.post('/userData', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - let user = UserInfo(token) - if (!user) user = { user: '' } - const userData = await getUserData(user.user) - reply.send({ - chat: userData.chat || [], - mode: userData.mode || '', - cast: userData.cast || { - api: '', //API设定 - bing: '', //必应设定 - bing_resource: '', //必应扩展资料 - slack: '', //Slack设定 - } - }) - return reply - }) - // 删除用户 - fastify.post('/deleteUser', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - const user = UserInfo(token) - if (!user || user === 'unknown') { - reply.send({ state: false, error: '无效token' }) - return - } - const filepath = `resources/ChatGPTCache/user/${user.user}.json` - fs.unlinkSync(filepath) - reply.send({ state: true }) - return reply - }) - // 修改密码 - fastify.post('/changePassword', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - const user = UserInfo(token) - if (!user || user === 'unknown') { - reply.send({ state: false, error: '无效的用户信息' }) - return - } - const userData = await getUserData(user.user) - const body = request.body || {} - if (!body.newPasswd) { - reply.send({ state: false, error: '无效参数' }) - return - } - if (body.passwd && body.passwd != userData.passwd) { - reply.send({ state: false, error: '原始密码错误' }) - return - } - if (user.autho === 'admin') { - await redis.set('CHATGPT:ADMIN_PASSWD', body.newPasswd) - } else if (user.autho === 'user') { - const dir = 'resources/ChatGPTCache/user' - const filename = `${user.user}.json` - const filepath = path.join(dir, filename) - fs.mkdirSync(dir, { recursive: true }) - if (fs.existsSync(filepath)) { - fs.readFile(filepath, 'utf8', (err, data) => { - if (err) { - console.error(err) - return - } - const config = JSON.parse(data) - config.passwd = body.newPasswd - fs.writeFile(filepath, JSON.stringify(config), 'utf8', (err) => { - if (err) { - console.error(err) - } - }) - }) - } else { - reply.send({ state: false, error: '错误的用户数据' }) - return - } - } - reply.send({ state: true }) - return reply +function getBots () { + if (Bot.uin === 88888) { + // 找适配器 + let adapters = Bot.adapter + return adapters?.map(uin => Bot[uin]) + } else if (Bot.adapter && Bot.adapter.length > 0) { + let bots = [Bot] + Bot.adapter.forEach(uin => { + bots.push(Bot[uin]) }) + return bots + } } -export default User \ No newline at end of file +async function User (fastify, options) { + // 登录 + fastify.post('/login', async (request, reply) => { + const body = request.body || {} + let guobaLoginService + let guobaAPI = '' + try { + let { LoginService } = await import('../../../Guoba-Plugin/server/service/both/LoginService.js') + let { getAllWebAddress } = await import('../../../Guoba-Plugin/utils/common.js') + guobaLoginService = new LoginService() + guobaAPI = await getAllWebAddress() + } catch (err) { + console.error(err) + guobaLoginService = { + signToken: () => { return null } + } + } + if (body.qq && body.passwd) { + const token = randomString(32) + if (body.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) { + const guobaToken = await guobaLoginService.signToken(body.qq) + AddUser({ user: body.qq, token, autho: 'admin' }) + reply.setCookie('token', token, { path: '/' }) + reply.send({ login: true, autho: 'admin', token, guobaToken, guoba: guobaAPI }) + } else { + const user = await getUserData(body.qq) + if (user.passwd != '' && user.passwd === body.passwd) { + AddUser({ user: body.qq, token, autho: 'user' }) + reply.setCookie('token', token, { path: '/' }) + reply.send({ login: true, autho: 'user', token }) + } else { + reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改` }) + } + } + } else if (body.otp) { + const token = randomString(32) + const opt = await redis.get('CHATGPT:SERVER_QUICK') + if (opt && body.otp == opt) { + const guobaToken = await guobaLoginService.signToken(getUin()) + AddUser({ user: getUin(), token, autho: 'admin' }) + reply.setCookie('token', token, { path: '/' }) + reply.send({ login: true, autho: 'admin', token, user: getUin(), guobaToken, guoba: guobaAPI }) + } else { + reply.send({ login: false, err: '快捷登录代码错误,请检查后重试' }) + } + } else { + reply.send({ login: false, err: '未输入用户名或密码' }) + } + return reply + }) + // 快速登录 + fastify.post('/quick', async (request, reply) => { + const otp = randomString(6) + await redis.set( + 'CHATGPT:SERVER_QUICK', + otp, + { EX: 60000 } + ) + const master = (await getMasterQQ())[0] + let bots = getBots() + for (let bot of bots) { + bot.pickUser(master).sendMsg(`收到工具箱快捷登录请求,1分钟内有效:${otp}`) + } + reply.send({ state: true }) + return reply + }) + // 检查用户是否存在 + fastify.post('/verify', async (request, reply) => { + const token = request.cookies.token || request.body?.token || 'unknown' + const user = UserInfo(token) + if (!user || token === 'unknown') { + reply.send({ + verify: false + }) + return + } + reply.send({ + verify: true, + user: user.user, + autho: user.autho, + version: 10016 + }) + return reply + }) + // 获取用户数据 + fastify.post('/userData', async (request, reply) => { + const token = request.cookies.token || request.body?.token || 'unknown' + let user = UserInfo(token) + if (!user) user = { user: '' } + const userData = await getUserData(user.user) + reply.send({ + chat: userData.chat || [], + mode: userData.mode || '', + cast: userData.cast || { + api: '', // API设定 + bing: '', // 必应设定 + bing_resource: '', // 必应扩展资料 + slack: '' // Slack设定 + } + }) + return reply + }) + // 删除用户 + fastify.post('/deleteUser', async (request, reply) => { + const token = request.cookies.token || request.body?.token || 'unknown' + const user = UserInfo(token) + if (!user || user === 'unknown') { + reply.send({ state: false, error: '无效token' }) + return + } + const filepath = `resources/ChatGPTCache/user/${user.user}.json` + fs.unlinkSync(filepath) + reply.send({ state: true }) + return reply + }) + // 修改密码 + fastify.post('/changePassword', async (request, reply) => { + const token = request.cookies.token || request.body?.token || 'unknown' + const user = UserInfo(token) + if (!user || user === 'unknown') { + reply.send({ state: false, error: '无效的用户信息' }) + return + } + const userData = await getUserData(user.user) + const body = request.body || {} + if (!body.newPasswd) { + reply.send({ state: false, error: '无效参数' }) + return + } + if (body.passwd && body.passwd != userData.passwd) { + reply.send({ state: false, error: '原始密码错误' }) + return + } + if (user.autho === 'admin') { + await redis.set('CHATGPT:ADMIN_PASSWD', body.newPasswd) + } else if (user.autho === 'user') { + const dir = 'resources/ChatGPTCache/user' + const filename = `${user.user}.json` + const filepath = path.join(dir, filename) + fs.mkdirSync(dir, { recursive: true }) + if (fs.existsSync(filepath)) { + fs.readFile(filepath, 'utf8', (err, data) => { + if (err) { + console.error(err) + return + } + const config = JSON.parse(data) + config.passwd = body.newPasswd + fs.writeFile(filepath, JSON.stringify(config), 'utf8', (err) => { + if (err) { + console.error(err) + } + }) + }) + } else { + reply.send({ state: false, error: '错误的用户数据' }) + return + } + } + reply.send({ state: true }) + return reply + }) +} + +export default User diff --git a/utils/common.js b/utils/common.js index b3feb7f..66e6b6a 100644 --- a/utils/common.js +++ b/utils/common.js @@ -820,6 +820,7 @@ export async function getImageOcrText (e) { // logger.warn('resultArr', resultArr) return resultArr } catch (err) { + logger.warn('OCR失败,可能使用的适配器不支持OCR') return false // logger.error(err) } diff --git a/utils/config.js b/utils/config.js index 308338d..9b145e6 100644 --- a/utils/config.js +++ b/utils/config.js @@ -144,7 +144,7 @@ const defaultConfig = { serpSource: 'ikechan8370', extraUrl: 'https://cpe.ikechan8370.com', smartMode: false, - bingCaptchaOneShotUrl: 'http://bingcaptcha.ikechan8370.com/bing', + bingCaptchaOneShotUrl: '', // claude2 claudeAIOrganizationId: '', claudeAISessionKey: '', diff --git a/utils/xinghuo/xinghuo.js b/utils/xinghuo/xinghuo.js index 04aa728..b090410 100644 --- a/utils/xinghuo/xinghuo.js +++ b/utils/xinghuo/xinghuo.js @@ -3,6 +3,7 @@ import { Config } from '../config.js' import { createParser } from 'eventsource-parser' import https from 'https' import WebSocket from 'ws' +import { createHmac } from 'crypto' const referer = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNuL2NoYXQ/aWQ9') const origin = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNu') @@ -14,13 +15,7 @@ try { } catch (err) { logger.warn('未安装form-data,无法使用星火模式') } -let crypto -try { - crypto = (await import('crypto')).default -} catch (err) { - logger.warn('未安装crypto,无法使用星火api模式') -} -async function getKeyv() { +async function getKeyv () { let Keyv try { Keyv = (await import('keyv')).default @@ -30,7 +25,7 @@ async function getKeyv() { return Keyv } export default class XinghuoClient { - constructor(opts) { + constructor (opts) { this.cache = opts.cache this.ssoSessionId = opts.ssoSessionId this.headers = { @@ -41,7 +36,7 @@ export default class XinghuoClient { } } - apiErrorInfo(code) { + apiErrorInfo (code) { switch (code) { case 10000: return '升级为ws出现错误' case 10001: return '通过ws读取用户的消息出错' @@ -74,7 +69,7 @@ export default class XinghuoClient { } } - async initCache() { + async initCache () { if (!this.conversationsCache) { const cacheOptions = this.cache || {} cacheOptions.namespace = cacheOptions.namespace || 'xh' @@ -83,38 +78,37 @@ export default class XinghuoClient { } } - async getWsUrl() { - if (!crypto) return false + async getWsUrl () { const APISecret = Config.xhAPISecret const APIKey = Config.xhAPIKey let APILink = '/v1.1/chat' - if (Config.xhmode == 'apiv2') { + if (Config.xhmode === 'apiv2') { APILink = '/v2.1/chat' - } else if (Config.xhmode == 'apiv3') { + } else if (Config.xhmode === 'apiv3') { APILink = '/v3.1/chat' } const date = new Date().toGMTString() const algorithm = 'hmac-sha256' const headers = 'host date request-line' const signatureOrigin = `host: spark-api.xf-yun.com\ndate: ${date}\nGET ${APILink} HTTP/1.1` - const hmac = crypto.createHmac('sha256', APISecret) + const hmac = createHmac('sha256', APISecret) hmac.update(signatureOrigin) const signature = hmac.digest('base64') const authorizationOrigin = `api_key="${APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"` const authorization = Buffer.from(authorizationOrigin).toString('base64') const v = { - authorization: authorization, - date: date, - host: "spark-api.xf-yun.com" + authorization, + date, + host: 'spark-api.xf-yun.com' } const url = `wss://spark-api.xf-yun.com${APILink}?${Object.keys(v).map(key => `${key}=${v[key]}`).join('&')}` return url } - async uploadImage(url) { + async uploadImage (url) { // 获取图片 let response = await fetch(url, { - method: 'GET', + method: 'GET' }) const blob = await response.blob() const arrayBuffer = await blob.arrayBuffer() @@ -125,7 +119,7 @@ export default class XinghuoClient { const respOss = await fetch('https://xinghuo.xfyun.cn/iflygpt/oss/sign', { method: 'POST', headers: { - Cookie: 'ssoSessionId=' + this.ssoSessionId + ';', + Cookie: 'ssoSessionId=' + this.ssoSessionId + ';' }, body: formData }) @@ -167,7 +161,7 @@ export default class XinghuoClient { } } - async apiMessage(prompt, chatId, ePrompt = []) { + async apiMessage (prompt, chatId, ePrompt = []) { if (!chatId) chatId = (Math.floor(Math.random() * 1000000) + 100000).toString() // 初始化缓存 @@ -180,12 +174,9 @@ export default class XinghuoClient { // 获取ws链接 const wsUrl = Config.xhmode == 'assistants' ? Config.xhAssistants : await this.getWsUrl() - if (!wsUrl) throw new Error('缺少依赖:crypto。请安装依赖后重试') + if (!wsUrl) throw new Error('获取ws链接失败') let domain = 'general' - if (Config.xhmode == 'apiv2') - domain = "generalv2" - else if (Config.xhmode == 'apiv3') - domain = "generalv3" + if (Config.xhmode == 'apiv2') { domain = 'generalv2' } else if (Config.xhmode == 'apiv3') { domain = 'generalv3' } // 编写消息内容 const wsSendData = { header: { @@ -194,7 +185,7 @@ export default class XinghuoClient { }, parameter: { chat: { - domain: domain, + domain, temperature: Config.xhTemperature, // 核采样阈值 max_tokens: Config.xhMaxTokens, // tokens最大长度 chat_id: chatId, @@ -203,10 +194,10 @@ export default class XinghuoClient { }, payload: { message: { - "text": [ + text: [ ...ePrompt, ...conversation.messages, - { "role": "user", "content": prompt } + { role: 'user', content: prompt } ] } } @@ -229,8 +220,8 @@ export default class XinghuoClient { const half = Math.floor(conversation.messages.length / 2) conversation.messages.splice(0, half) await this.conversationsCache.set(conversationKey, conversation) - resolve({ - id: (Math.floor(Math.random() * 1000000) + 100000).toString() , + resolve({ + id: (Math.floor(Math.random() * 1000000) + 100000).toString(), response: '对话以达到上限,已自动清理对话,请重试' }) } else { @@ -256,8 +247,8 @@ export default class XinghuoClient { conversation.messages.splice(0, half) } await this.conversationsCache.set(conversationKey, conversation) - resolve({ - id: chatId , + resolve({ + id: chatId, response: resMessage }) } @@ -271,7 +262,7 @@ export default class XinghuoClient { }) } - async webMessage(prompt, chatId, botId) { + async webMessage (prompt, chatId, botId) { if (!FormData) { throw new Error('缺少依赖:form-data。请安装依赖后重试') } @@ -281,7 +272,7 @@ export default class XinghuoClient { formData.append('clientType', '2') formData.append('chatId', chatId) if (prompt.image) { - prompt.text = prompt.text.replace("[图片]", "") // 清理消息中中首个被使用的图片 + prompt.text = prompt.text.replace('[图片]', '') // 清理消息中中首个被使用的图片 const imgdata = await this.uploadImage(prompt.image) if (imgdata) { formData.append('fileUrl', imgdata.url) @@ -313,7 +304,7 @@ export default class XinghuoClient { logger.error('星火statusCode:' + statusCode) } let response = '' - function onMessage(data) { + function onMessage (data) { // console.log(data) if (data === '') { return resolve({ @@ -380,7 +371,7 @@ export default class XinghuoClient { }) } - async sendMessage(prompt, option) { + async sendMessage (prompt, option) { let chatId = option?.chatId let image = option?.image @@ -396,9 +387,9 @@ export default class XinghuoClient { logger.warn('星火设定序列化失败,本次对话不附带设定') } } else { - Prompt = Config.xhPrompt ? [{ "role": "user", "content": Config.xhPrompt }] : [] + Prompt = Config.xhPrompt ? [{ role: 'user', content: Config.xhPrompt }] : [] } - if(Config.xhPromptEval) { + if (Config.xhPromptEval) { Prompt.forEach(obj => { try { obj.content = obj.content.replace(/{{(.*?)}}/g, (match, variable) => { @@ -427,7 +418,7 @@ export default class XinghuoClient { if (!chatId) { chatId = (await this.createChatList()).chatListId } - let { response } = await this.webMessage({ text: prompt, image: image }, chatId, botId) + let { response } = await this.webMessage({ text: prompt, image }, chatId, botId) // logger.info(response) // let responseText = atob(response) // 处理图片 @@ -451,14 +442,14 @@ export default class XinghuoClient { return { conversationId: chatId, text: response, - images: images + images } } else { throw new Error('星火模式错误') } } - async createChatList(bot = false) { + async createChatList (bot = false) { let createChatListRes = await fetch(createChatUrl, { method: 'POST', headers: Object.assign(this.headers, { @@ -487,6 +478,6 @@ export default class XinghuoClient { } } -function atob(s) { +function atob (s) { return Buffer.from(s, 'base64').toString() }