mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 22:07:10 +00:00
* 修复引用转发,默认bing模式并发 * 开启stream增加稳定性 * fix: remove queue element only in non-bing mode * 使用chatgpt-api自带的超时逻辑,文字过多时启动切换到图片输出防止被吞 * Update chat.js * 添加Bing专用的图片输出样式 * 添加chatgpt的新图片模式,临时处理切换api导致的对话异常 * 修改bing样式表 * 为图片添加外部页面缓存 * 为图片模式添加MathJax * feat: add switch for qrcode * 防止script攻击 * 修复网页模板错误 * 修复bing页面引用错误 * 缓存服务器异常时处理 * 添加默认配置加载 * 修复配置文件路径错误 * 删除重复的模板文件,修复二维码地址错误 * 修正图片渲染错误 * 修复引用渲染错误 * 二维码网址统一改为使用本地配置 * 添加关闭思考提示的配置项 * 修复在Windows上无法载入配置文件的问题 * 修复关闭qr的情况下渲染错误 * 改为使用base64传递返回数据 * 当异常过多时使用图片输出 * 添加锅巴面板配置支持 * 补充遗漏的默认配置 * 修复qr模式下引用未被传递的问题 * 修复未将引用数据传输给缓存服务器的问题 * 删除无用的bingTimeoutMs配置项 * 添加消息队列超时弹出 * 优化图片模式处理,解决对话队列卡住的问题 --------- Co-authored-by: ikechan8370 <geyinchibuaa@gmail.com>
207 lines
4.9 KiB
JavaScript
207 lines
4.9 KiB
JavaScript
// import { remark } from 'remark'
|
|
// import stripMarkdown from 'strip-markdown'
|
|
import { exec } from 'child_process'
|
|
import lodash from 'lodash'
|
|
// export function markdownToText (markdown) {
|
|
// return remark()
|
|
// .use(stripMarkdown)
|
|
// .processSync(markdown ?? '')
|
|
// .toString()
|
|
// }
|
|
export function escapeHtml (str) {
|
|
const htmlEntities = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": ''',
|
|
'/': '/'
|
|
}
|
|
return str.replace(/[&<>"'/]/g, (match) => htmlEntities[match])
|
|
}
|
|
|
|
export function randomString(length = 5) {
|
|
let str = ''
|
|
for (let i = 0; i < length; i++) {
|
|
str += lodash.random(36).toString(36)
|
|
}
|
|
return str.substr(0, length)
|
|
}
|
|
|
|
export async function upsertMessage (message) {
|
|
await redis.set(`CHATGPT:MESSAGE:${message.id}`, JSON.stringify(message))
|
|
}
|
|
|
|
export async function getMessageById (id) {
|
|
let messageStr = await redis.get(`CHATGPT:MESSAGE:${id}`)
|
|
return JSON.parse(messageStr)
|
|
}
|
|
|
|
export async function tryTimes (promiseFn, maxTries = 10) {
|
|
try {
|
|
return await promiseFn()
|
|
} catch (e) {
|
|
if (maxTries > 0) {
|
|
logger.warn('Failed, retry ' + maxTries)
|
|
return tryTimes(promiseFn, maxTries - 1)
|
|
}
|
|
throw e
|
|
}
|
|
}
|
|
|
|
export async function makeForwardMsg (e, msg = [], dec = '') {
|
|
let nickname = Bot.nickname
|
|
if (e.isGroup) {
|
|
let info = await Bot.getGroupMemberInfo(e.group_id, Bot.uin)
|
|
nickname = info.card || info.nickname
|
|
}
|
|
let userInfo = {
|
|
user_id: Bot.uin,
|
|
nickname
|
|
}
|
|
|
|
let forwardMsg = []
|
|
msg.forEach(v => {
|
|
forwardMsg.push({
|
|
...userInfo,
|
|
message: v
|
|
})
|
|
})
|
|
|
|
/** 制作转发内容 */
|
|
if (e.isGroup) {
|
|
forwardMsg = await e.group.makeForwardMsg(forwardMsg)
|
|
} else if (e.friend) {
|
|
forwardMsg = await e.friend.makeForwardMsg(forwardMsg)
|
|
} else {
|
|
return false
|
|
}
|
|
|
|
if (dec) {
|
|
/** 处理描述 */
|
|
forwardMsg.data = forwardMsg.data
|
|
.replace(/\n/g, '')
|
|
.replace(/<title color="#777777" size="26">(.+?)<\/title>/g, '___')
|
|
.replace(/___+/, `<title color="#777777" size="26">${dec}</title>`)
|
|
}
|
|
|
|
return forwardMsg
|
|
}
|
|
|
|
// @see https://github.com/sindresorhus/p-timeout
|
|
export async function pTimeout (
|
|
promise,
|
|
options
|
|
) {
|
|
const {
|
|
milliseconds,
|
|
fallback,
|
|
message,
|
|
customTimers = { setTimeout, clearTimeout }
|
|
} = options
|
|
|
|
let timer
|
|
|
|
const cancelablePromise = new Promise((resolve, reject) => {
|
|
if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {
|
|
throw new TypeError(
|
|
`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``
|
|
)
|
|
}
|
|
|
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
resolve(promise)
|
|
return
|
|
}
|
|
|
|
if (options.signal) {
|
|
const { signal } = options
|
|
if (signal.aborted) {
|
|
reject(getAbortedReason(signal))
|
|
}
|
|
|
|
signal.addEventListener('abort', () => {
|
|
reject(getAbortedReason(signal))
|
|
})
|
|
}
|
|
|
|
timer = customTimers.setTimeout.call(
|
|
undefined,
|
|
() => {
|
|
if (fallback) {
|
|
try {
|
|
resolve(fallback())
|
|
} catch (error) {
|
|
reject(error)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
const errorMessage =
|
|
typeof message === 'string'
|
|
? message
|
|
: `Promise timed out after ${milliseconds} milliseconds`
|
|
const timeoutError =
|
|
message instanceof Error ? message : new Error(errorMessage)
|
|
|
|
if (typeof promise.cancel === 'function') {
|
|
promise.cancel()
|
|
}
|
|
|
|
reject(timeoutError)
|
|
},
|
|
milliseconds
|
|
)
|
|
;(async () => {
|
|
try {
|
|
resolve(await promise)
|
|
} catch (error) {
|
|
reject(error)
|
|
} finally {
|
|
customTimers.clearTimeout.call(undefined, timer)
|
|
}
|
|
})()
|
|
})
|
|
|
|
cancelablePromise.clear = () => {
|
|
customTimers.clearTimeout.call(undefined, timer)
|
|
timer = undefined
|
|
}
|
|
|
|
return cancelablePromise
|
|
}
|
|
/**
|
|
TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18.
|
|
*/
|
|
function getAbortedReason (signal) {
|
|
const reason =
|
|
signal.reason === undefined
|
|
? getDOMException('This operation was aborted.')
|
|
: signal.reason
|
|
|
|
return reason instanceof Error ? reason : getDOMException(reason)
|
|
}
|
|
/**
|
|
TODO: Remove AbortError and just throw DOMException when targeting Node 18.
|
|
*/
|
|
function getDOMException (errorMessage) {
|
|
return globalThis.DOMException === undefined
|
|
? new Error(errorMessage)
|
|
: new DOMException(errorMessage)
|
|
}
|
|
|
|
export async function checkPnpm () {
|
|
let npm = 'npm'
|
|
let ret = await execSync('pnpm -v')
|
|
if (ret.stdout) npm = 'pnpm'
|
|
return npm
|
|
}
|
|
|
|
async function execSync (cmd) {
|
|
return new Promise((resolve, reject) => {
|
|
exec(cmd, { windowsHide: true }, (error, stdout, stderr) => {
|
|
resolve({ error, stdout, stderr })
|
|
})
|
|
})
|
|
}
|