From a3fab7316fa1429e480447ffe7d7864cd06470f0 Mon Sep 17 00:00:00 2001 From: HalcyonAlcedo <41666148+HalcyonAlcedo@users.noreply.github.com> Date: Sun, 25 Jun 2023 00:58:41 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Ews=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=8C=E9=80=82=E9=85=8D=E5=B7=A5=E5=85=B7=20(#482)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修复后台API反代地址未能正确显示的问题 * 更新渲染页面配置 * 添加个人聊天模式配置 * 将用户数据获取改到common中 * 修复错误的渲染页面参数 * 修复bug * 添加Live2D * 修复渲染页面错误 * 修复渲染传入值 * 更新渲染 * 修复图表渲染bug * 调整live2d模型大小 * 修复live2d无法关闭问题 * 修复错误的传值 * 修复ai命名 * 更新渲染 * 添加用户独立设定 * 更新渲染配置适配个人设置 * 修复合并导致的渲染文件异常删除 * 修复用户数据缺失问题 * 修复旧版本数据缺失问题 * 修复bing参数不存在问题,兼容miao的截图 * 修复受限token重试时不被排除的问题 * 修复个人模式下结束对话的模式错误 * 更新渲染页面,将预览版转为正式版 * 修复传统渲染无法调用截图功能的问题 * 文字模式也进行一次缓存 * 更新README * Update README.md * 更新渲染 * 更新渲染页面 * 添加版本信息 * 遗漏参数 * 丢失引用 * 补充路由 * 添加云转码功能 * 判断node-silk是否正常合成 * 云转码提示 * 修复图片渲染出错 * 云转码支持发送Buffer * 添加云转码模式支持 * 更新描述 * 更新后台渲染页面 * 更新配置 * 更新渲染页面 * 添加云渲染 * 修复错误的接口调用 * 修复遗漏的数据转换 * 修复获取的图片数据异常问题 * 更新后台配置 * 更新渲染页面 * 修复云渲染访问地址错误 * 更新渲染页面 * 修复遗漏的模型文件 * 修复live2d问题 * 更新live2d以及相关配置 * 修复遗漏的数据参数 * 修复新live2d情况下云渲染错误的问题 * 适配云渲染1.1.2等待参数 * 添加云服务api检查 * 更新渲染页面 * 添加live2d加载检测 * 修复错误的属性判断 * 添加云渲染DPR * 更新sydney支持内容生成 * 修改文件模式语音转码接收模式 * 添加云转码时recordUrl检查 * 更新后台配置项 * 修复错误的文本描述 * 更新后台页面 * 添加全局对话模式设置,更新后台面板 * 添加第三方渲染服务适配 * 修复第三方服务器live2d加载导致的渲染失败问题 * 修复后台地址无法实时保存的问题 * 添加live2d模型透明度设置 * 合并更新 * 更新渲染页面 * 更新渲染页面 * 使dpr对本地渲染也生效 * 更新渲染页面 * 添加网页截图功能 * 添加后台配置项 * 添加配置导出和导入功能 * 运行通过参数传递用户token * 登录时将token作为参数返回 * 修复错误 * 添加密码修改和用户删除接口 * 修正密码比对 * 修复user错误 * 优化数据保存时的返回值 * 添加系统额外服务检查api * 添加AccessToken配置 * 修复错误的导入提示 * 添加ws连接 * 添加ws用户信息获取 * 修复错误的循环 * 修正ws参数 * 添加群消息获取权限 * 添加用户多端登录支持 * 修复错误的路径引用 * 修复错误的路径引用 * 修复错误 * 修复页面数据获取失败问题 --------- Co-authored-by: ikechan8370 --- apps/management.js | 2 +- server/index.js | 299 +++++++++++++++--------------------- server/modules/user.js | 127 +++++++++++++++ server/modules/user_data.js | 41 +++++ server/modules/web_route.js | 58 +++++++ 5 files changed, 352 insertions(+), 175 deletions(-) create mode 100644 server/modules/user.js create mode 100644 server/modules/user_data.js create mode 100644 server/modules/web_route.js diff --git a/apps/management.js b/apps/management.js index d581d3f..f6be28b 100644 --- a/apps/management.js +++ b/apps/management.js @@ -1454,7 +1454,7 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie }) await redis.set('CHATGPT:USE', redisConfig.useMode) } - await this.reply(await makeForwardMsg(this.e, changeConfig.map(msg => `修改项:${msg.item}\n旧数据\n\n${msg.url}\n\n新数据\n ${msg.url}`))) + await this.reply(await makeForwardMsg(this.e, changeConfig.map(msg => `修改项:${msg.item}\n旧数据\n\n${msg.old}\n\n新数据\n ${msg.value}`))) } catch (error) { console.error(error) await e.reply('配置文件错误') diff --git a/server/index.js b/server/index.js index 6326c10..2495b5b 100644 --- a/server/index.js +++ b/server/index.js @@ -2,6 +2,7 @@ import fastify from 'fastify' import fastifyCookie from '@fastify/cookie' import cors from '@fastify/cors' import fstatic from '@fastify/static' +import websocket from '@fastify/websocket' import fs from 'fs' import path from 'path' @@ -9,14 +10,17 @@ import os from 'os' import schedule from 'node-schedule' import { Config } from '../utils/config.js' -import { randomString, getPublicIP, getUserData } from '../utils/common.js' +import { UserInfo, GetUser } from './modules/user_data.js' +import { getPublicIP, getUserData } from '../utils/common.js' + +import webRoute from './modules/web_route.js' +import webUser from './modules/user.js' const __dirname = path.resolve() const server = fastify({ logger: Config.debug }) -let usertoken = [] let Statistics = { SystemAccess: { count: 0, @@ -60,99 +64,24 @@ async function setUserData(qq, data) { fs.writeFileSync(filepath, JSON.stringify(data)) } +server.register(cors, { + origin: '*' +}) +server.register(fstatic, { + root: path.join(__dirname, 'plugins/chatgpt-plugin/server/static/') +}) +server.register(websocket, { + cors: true, + options: { + maxPayload: 1048576 + } +}) +server.register(fastifyCookie) +server.register(webRoute) +server.register(webUser) + export async function createServer() { - await server.register(cors, { - origin: '*' - }) - await server.register(fstatic, { - root: path.join(__dirname, 'plugins/chatgpt-plugin/server/static/') - }) - await server.register(fastifyCookie) - await server.get('/page/*', (request, reply) => { - const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') - reply.type('text/html').send(stream) - }) - await server.get('/help/*', (request, reply) => { - const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') - reply.type('text/html').send(stream) - }) - await server.get('/version', (request, reply) => { - const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') - reply.type('text/html').send(stream) - }) - await server.get('/auth/*', (request, reply) => { - const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') - reply.type('text/html').send(stream) - }) - await server.get('/admin*', (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - const user = usertoken.find(user => user.token === token) - if (!user) { - reply.redirect(301, '/auth/login') - } - const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') - reply.type('text/html').send(stream) - }) - await server.get('/admin/dashboard', (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - const user = usertoken.find(user => user.token === token) - if (!user) { - reply.redirect(301, '/auth/login') - } - if (user.autho === 'admin') { - reply.redirect(301, '/admin/settings') - } - const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') - reply.type('text/html').send(stream) - }) - await server.get('/admin/settings', (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - const user = usertoken.find(user => user.token === token) - if (!user || user.autho != 'admin') { - reply.redirect(301, '/admin/') - } - const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') - reply.type('text/html').send(stream) - }) - // 登录 - server.post('/login', async (request, reply) => { - 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) { - usertoken.push({ user: body.qq, token, autho: 'admin' }) - reply.setCookie('token', token, { path: '/' }) - reply.send({ login: true, autho: 'admin', token: token }) - } else { - const user = await getUserData(body.qq) - if (user.passwd != '' && user.passwd === body.passwd) { - usertoken.push({ user: body.qq, token, autho: 'user' }) - reply.setCookie('token', token, { path: '/' }) - reply.send({ login: true, autho: 'user', token: token }) - } else { - reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == Bot.uin ? '#修改管理密码' : '#修改用户密码'} 进行修改` }) - } - } - } else { - reply.send({ login: false, err: '未输入用户名或密码' }) - } - }) - // 检查用户是否存在 - server.post('/verify', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - let user = usertoken.find(user => user.token === token) - if (!user || token === 'unknown') { - reply.send({ - verify: false, - }) - return - } - reply.send({ - verify: true, - user: user.user, - autho: user.autho - }) - }) + // 页面数据获取 server.post('/page', async (request, reply) => { const body = request.body || {} @@ -264,86 +193,11 @@ export async function createServer() { reply.send(Statistics) }) - // 获取用户数据 - server.post('/userData', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - let user = usertoken.find(user => user.token === 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设定 - } - }) - }) - // 删除用户 - server.post('/deleteUser', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - let user = usertoken.find(user => user.token === 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 }) - }) - // 修改密码 - server.post('/changePassword', async (request, reply) => { - const token = request.cookies.token || request.body?.token || 'unknown' - let user = usertoken.find(user => user.token === 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 }) - }) // 清除缓存数据 server.post('/cleanCache', async (request, reply) => { const token = request.cookies.token || request.body?.token || 'unknown' - let user = usertoken.find(user => user.token === token) + let user = UserInfo(token) if (!user) user = { user: '' } const userData = await getUserData(user.user) const dir = 'resources/ChatGPTCache/page' @@ -356,11 +210,98 @@ export async function createServer() { await setUserData(user.user, userData) reply.send({ state: true }) }) + let clients = [] + // 获取消息 + const wsFn = async (connection, request) => { + connection.socket.on('open', message => { + // 开始连接 + console.log(`Received message: ${message}`) + const response = { data: 'hello, client' } + connection.socket.send(JSON.stringify(response)) + }) + connection.socket.on('message', async (message) => { + try { + const data = JSON.parse(message) + + switch (data.command) { + case 'sendMsg': // 代理消息发送 + if (!connection.login) { + await connection.socket.send(JSON.stringify({ command: data.command, state: false, error: '请先登录账号' })) + return + } + if (data.id && data.message) { + if (data.group) { + Bot.sendGroupMsg(parseInt(data.id), data.message, data.quotable) + } else { + Bot.sendPrivateMsg(parseInt(data.id), data.message, data.quotable) + } + await connection.socket.send(JSON.stringify({ command: data.command, state: true, })) + } else { + await connection.socket.send(JSON.stringify({ command: data.command, state: false, error: '参数不足' })) + } + break + case 'userInfo': // 获取用户信息 + if (!connection.login) { + await connection.socket.send(JSON.stringify({ command: data.command, state: false, error: '请先登录账号' })) + } else { + await connection.socket.send(JSON.stringify({ command: data.command, state: true, user: { user: user.user, autho: user.autho } })) + } + break + case 'login': // 登录 + const user = UserInfo(data.token) + if (user) { + clients[user.user] = connection.socket + connection.login = true + await connection.socket.send(JSON.stringify({ command: data.command, state: true })) + } else { + await connection.socket.send(JSON.stringify({ command: data.command, state: false, error: '权限验证失败' })) + } + break + default: + await connection.socket.send(JSON.stringify({ "data": data })) + break + } + } catch (error) { + await connection.socket.send(JSON.stringify({ "error": error.message })) + } + }) + } + Bot.on("message", e => { + const messageData = { + notice: 'clientMessage', + message: e.message, + sender: e.sender, + group: { + isGroup: e.isGroup, + group_id: e.group_id, + group_name: e.group_name + }, + quotable: { + user_id: e.user_id, + time: e.time, + seq: e.seq, + rand: e.rand, + message: e.message, + user_name: e.sender.nickname, + } + } + if (clients) { + for (const index in clients) { + const user = GetUser(index) + if (user.autho == 'admin' || user.user == e.user_id) { + clients[index].send(JSON.stringify(messageData)) + } + } + } + }) + server.get('/ws', { + websocket: true + }, wsFn) // 获取系统参数 server.post('/sysconfig', async (request, reply) => { const token = request.cookies.token || request.body?.token || 'unknown' - const user = usertoken.find(user => user.token === token) + const user = UserInfo(token) if (!user) { reply.send({ err: '未登录' }) } else if (user.autho === 'admin') { @@ -405,7 +346,7 @@ export async function createServer() { // 设置系统参数 server.post('/saveconfig', async (request, reply) => { const token = request.cookies.token || request.body?.token || 'unknown' - const user = usertoken.find(user => user.token === token) + const user = UserInfo(token) const body = request.body || {} let changeConfig = [] if (!user) { @@ -457,8 +398,18 @@ export async function createServer() { if (redisConfig.openAiPlatformAccessToken != null) { await redis.set('CHATGPT:TOKEN', redisConfig.openAiPlatformAccessToken) } - reply.send({ change: changeConfig, state: true }) + // 通知所有WS客户端刷新数据 + if (clients) { + for (const index in clients) { + const user = GetUser(index) + if (user.autho == 'admin') { + clients[index].send(JSON.stringify({ + notice: 'updateConfig' + })) + } + } + } } else { if (body.userSetting) { await redis.set(`CHATGPT:USER:${user.user}`, JSON.stringify(body.userSetting)) @@ -490,7 +441,7 @@ export async function createServer() { } } if (Config.cloudTranscode) { - const checkCheckCloud= await fetch(Config.cloudTranscode, { method: 'GET' }) + const checkCheckCloud = await fetch(Config.cloudTranscode, { method: 'GET' }) if (checkCheckCloud.ok) { serverState.cloud = true } diff --git a/server/modules/user.js b/server/modules/user.js new file mode 100644 index 0000000..a964ea2 --- /dev/null +++ b/server/modules/user.js @@ -0,0 +1,127 @@ +import { UserInfo, AddUser } from './user_data.js' +import { randomString, getUserData } from '../../utils/common.js' +import fs from 'fs' + +async function User(fastify, options) { + // 登录 + fastify.post('/login', async (request, reply) => { + 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) { + AddUser({ user: body.qq, token: token, autho: 'admin' }) + reply.setCookie('token', token, { path: '/' }) + reply.send({ login: true, autho: 'admin', token: token }) + } 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 == Bot.uin ? '#修改管理密码' : '#修改用户密码'} 进行修改` }) + } + } + } else { + reply.send({ login: false, err: '未输入用户名或密码' }) + } + 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 + }) + 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 \ No newline at end of file diff --git a/server/modules/user_data.js b/server/modules/user_data.js new file mode 100644 index 0000000..51fb997 --- /dev/null +++ b/server/modules/user_data.js @@ -0,0 +1,41 @@ +let users = { + user: [] +} +export const UserData = new Proxy(users, { + set(target, property, value) { + target[property] = value + return true + } +}) +// 获取用户信息 +export function UserInfo(token) { + const userData = users.user.find(user => user.token.includes(token)) + if (userData) { + return { + user: userData.user, + autho: userData.autho, + label: userData.label + } + } else { + return undefined + } +} +// 获取用户数据 +export function GetUser(user) { + return users.user.find(user => user === user) +} +// 添加用户token +export function AddUser(data) { + const userIndex = users.user.findIndex(user => user === data.user) + if (userIndex >= 0) { + users.user[userIndex].token.push(data.token) + } else { + users.user.push({ + user: data.user, + autho: data.autho, + token: [data.token], + label: data.label || '', + tiem: new Date() + }) + } +} \ No newline at end of file diff --git a/server/modules/web_route.js b/server/modules/web_route.js new file mode 100644 index 0000000..7c627d5 --- /dev/null +++ b/server/modules/web_route.js @@ -0,0 +1,58 @@ +import { UserInfo } from './user_data.js' +import fs from 'fs' + +async function routes(fastify, options) { + fastify.get('/page/*', async (request, reply) => { + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + return reply + }) + fastify.get('/help/*', async (request, reply) => { + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + }) + fastify.get('/version', async (request, reply) => { + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + return reply + }) + fastify.get('/auth/*', async (request, reply) => { + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + }) + fastify.get('/admin*', async (request, reply) => { + const token = request.cookies.token || request.body?.token || 'unknown' + const user = UserInfo(token) + if (!user) { + reply.redirect(301, '/auth/login') + } + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + return reply + }) + fastify.get('/admin/dashboard', async (request, reply) => { + const token = request.cookies.token || request.body?.token || 'unknown' + const user = UserInfo(token) + if (!user) { + reply.redirect(301, '/auth/login') + } + if (user.autho === 'admin') { + reply.redirect(301, '/admin/settings') + } + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + return reply + }) + fastify.get('/admin/settings', async (request, reply) => { + const token = request.cookies.token || request.body?.token || 'unknown' + const user = UserInfo(token) + if (!user || user.autho != 'admin') { + reply.redirect(301, '/admin/') + } + const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html') + reply.type('text/html').send(stream) + return reply + }) +} + +export default routes \ No newline at end of file From 2c5b084b044474abb4cc355d18a2f7b1e4ecbe78 Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Sun, 25 Jun 2023 00:59:02 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9C=A8guoba=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E5=A1=AB=E5=86=99=E9=BB=91=E7=99=BD=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E4=B8=8D=E7=94=9F=E6=95=88=E7=9A=84bug=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dazure=E8=AF=AD=E9=9F=B3=E6=A8=A1=E5=BC=8F=E4=B8=8B?= =?UTF-8?q?=E6=97=A0=E5=8F=82=E6=95=B0=E6=9F=A5=E7=9C=8B=E8=AF=AD=E9=9F=B3?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=97=E8=A1=A8=E6=97=B6=E4=B8=8D=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=BB=93=E6=9E=9C=E7=9A=84bug=E3=80=82=20(#476)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add support for ‘greeting’ and ‘global reply mode’ commands, improve variable naming and remove unnecessary backend output. * feat: Add support for black and white lists, global reply mode and voice role settings, private chat switch, and active greeting configuration. Refactor some variable names and comment out redundant code for better readability and reduced backend output. * feat: 为新功能完善了帮助面板 * docs: 完善了‘打招呼’的帮助说明 * Commit Type: feat, bugfix Add functionality to view plugin command table, fix bug in blacklist/whitelist, and fix bug where chat mode can still be used in private messaging when disabled. * Commit Type: feat, bugfix Add functionality to view plugin command table, fix bug in blacklist/whitelist, and fix bug where chat mode can still be used in private messaging when disabled. * refactor: Remove redundant log output. * Refactor: optimize code logic * Fix: 修复绘图指令表被抢指令的bug。 * Refactor:1. Add support for automatically translating replies to Japanese and generating voice messages in VITS voice mode (please monitor remaining quota after enabling). 2. Add translation function. 3. Add emotion configuration for Azure voice mode, allowing the robot to select appropriate emotional styles for replies. * Refactor:Handle the issue of exceeding character setting limit caused by adding emotion configuration. * Fix: fix bugs * Refactor: Added error feedback to translation service * Refactor: Added support for viewing the list of supported roles for each language mode, and fixed some bugs in the emotion switching feature of the auzre mode. * Refactor: Optimized some command feedback and added owner restriction to chat record export function. * Refactor: Optimized feedback when viewing role list to avoid excessive messages. * Refactor: Optimized feedback when configuring multi-emotion mode. * Feature: Added help instructions for translation feature. * chore: Adjust help instructions for mood settings * Fix: Fixed issue where only first line of multi-line replies were being read and Azure voice was pronouncing punctuation marks. * Fix: Fixed bug where switching to Azure voice mode prompted for missing key and restricted ability to view voice role list to only when in voice mode. * Refactor: Add image OCR function and support translation for both quoted text and image. * fix: Fix issue with error caused by non-image input. * Refactor: Optimize code to filter emojis that cannot be displayed properly in claude mode. * Refactor: Optimize some code structures. * fix: Fix the bug of returning only one result when entering multiple lines of text on Windows system. * Refactor: Optimize code logic for better user experience * Refactor: Fix the conflict issue with other plugin translation commands * Refactor: Replace Baidu Translation with Youdao Translation to eliminate configuration steps; optimize translation experience; add missing dependency prompts instead of causing program errors.Optimize the experience of switching between voice mode and setting global reply mode. * Refactor: Remove unused files and dependencies in the project. * Feature: Add Youdao translation service to provide more comprehensive translation support. * Refactor: Optimize translation experience * Refactor: Optimize translation experience * Feature: Add functionality of keyword search command * Feature: Add functionality of keyword search command. * Refactor: Remove redundant code * Add: Add feature to support randomly selecting roles for Azure voice. Refactor the code to support existing voice services for the ‘greeting’ feature. Fix the display issue of Azure voice role selection on the Guoba panel. * Refactor: Remove redundant code * Refactor: Improve the function of setting global voice roles and viewing role lists. Now you can set default roles for each voice service separately or view the supported role list. * Refactor: Remove redundant code * Feature: Add new function to support random character dialogues in all voice modes, add the ability to view the current user’s reply settings, and improve related functions in the global settings. * Refactor: Add compatibility directive for viewing reply settings feature * Feature: support adding QQ number to blacklist/whitelist * fix: 处理全局设置指令被上下班指令占用的问题 * fix: 处理全局设置指令被上下班指令占用的问题 * Refactor: Preprocess dialogue blacklist/whitelist when filling in the form in Guoba panel * Fix: Fixed the issue where black and white lists were not effective when filled in the Guoba panel, and the issue where no results were returned when viewing the voice role list without parameters in azure tts mode. --------- Co-authored-by: Sean <1519059137@qq.com> Co-authored-by: ikechan8370 --- apps/chat.js | 4 ++-- apps/entertainment.js | 4 ++-- apps/management.js | 4 +--- guoba.support.js | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index 13ba2d3..90ae1c2 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -756,12 +756,12 @@ export class chatgpt extends plugin { } // 黑白名单过滤对话 let [whitelist, blacklist] = processList(Config.whitelist, Config.blacklist) - if (whitelist.length > 0) { + if (whitelist.join('').length > 0) { if (e.isGroup && !whitelist.includes(e.group_id.toString())) return false const list = whitelist.filter(elem => elem.startsWith('^')).map(elem => elem.slice(1)) if (!list.includes(e.sender.user_id.toString())) return false } - if (blacklist.length > 0) { + if (blacklist.join('').length > 0) { if (e.isGroup && blacklist.includes(e.group_id.toString())) return false const list = blacklist.filter(elem => elem.startsWith('^')).map(elem => elem.slice(1)) if (list.includes(e.sender.user_id.toString())) return false diff --git a/apps/entertainment.js b/apps/entertainment.js index 3d767b0..88fe1ee 100644 --- a/apps/entertainment.js +++ b/apps/entertainment.js @@ -215,13 +215,13 @@ ${translateLangLabels} const regExp = /词云(\d{0,2})(|h)/ const match = e.msg.trim().match(regExp) const duration = !match[1] ? 12 : parseInt(match[1]) // default 12h - + if(duration > 24) { await e.reply('最多只能统计24小时内的记录哦') return false } await e.reply('在统计啦,请稍等...') - + await redis.set(`CHATGPT:WORDCLOUD:${groupId}`, '1', {EX: 600}) try { await makeWordcloud(e, e.group_id, duration) diff --git a/apps/management.js b/apps/management.js index f6be28b..df7f1d5 100644 --- a/apps/management.js +++ b/apps/management.js @@ -313,9 +313,7 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务, roleList = getVoicevoxRoleList() break case 'azure': - if (matchCommand[2] === 'azure') { - roleList = getAzureRoleList() - } + roleList = getAzureRoleList() break default: break diff --git a/guoba.support.js b/guoba.support.js index 85e2fe1..ea4c1c0 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -798,7 +798,7 @@ export function supportGuoba () { setConfigData (data, { Result }) { for (let [keyPath, value] of Object.entries(data)) { // 处理黑名单 - if (keyPath === 'blockWords' || keyPath === 'promptBlockWords' || keyPath === 'initiativeChatGroups') { value = value.toString().split(/[,,;;\|]/) } + if (keyPath === 'blacklist' || keyPath === 'whitelist' || keyPath === 'blockWords' || keyPath === 'promptBlockWords' || keyPath === 'initiativeChatGroups') { value = value.toString().split(/[,,;;\|]/) } if (Config[keyPath] !== value) { Config[keyPath] = value } } // 正确储存azureRoleSelect结果