fix: 修复喵崽多适配器工具箱登录;移除crypto依赖

This commit is contained in:
ikechan8370 2023-11-21 16:31:29 +08:00
parent 2b19302b87
commit 46d88c2669
5 changed files with 216 additions and 255 deletions

View file

@ -315,7 +315,7 @@ export function supportGuoba () {
{ {
field: 'model', field: 'model',
label: 'OpenAI 模型', 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-turbogpt-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-turbogpt-4需账户支持',
component: 'Input' component: 'Input'
}, },
{ {
@ -456,7 +456,7 @@ export function supportGuoba () {
{ {
field: 'sydneyWebsocketUseProxy', field: 'sydneyWebsocketUseProxy',
label: '对话使用sydney反代', label: '对话使用sydney反代',
bottomHelpMessage: '【一般情况无需也不建议开启】默认情况下仅创建对话走反代,对话时仍然直连微软。开启本选项将使对话过程也走反,需反代支持', bottomHelpMessage: '默认情况下仅创建对话走反代,对话时仍然直连微软。开启本选项将使对话过程也走反,需反代支持。默认开启',
component: 'Switch' component: 'Switch'
}, },
{ {
@ -505,40 +505,6 @@ export function supportGuoba () {
bottomHelpMessage: '使用GPT-4注意试用配额较低如果用不了就关掉', bottomHelpMessage: '使用GPT-4注意试用配额较低如果用不了就关掉',
component: 'Switch' 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.exelinux通过which查找路径',
component: 'Input'
},
{ {
label: '以下为Slack Claude方式的配置', label: '以下为Slack Claude方式的配置',
component: 'Divider' component: 'Divider'
@ -625,16 +591,6 @@ export function supportGuoba () {
bottomHelpMessage: '等待响应的超时时间单位为秒默认为120。如果不使用反代而是使用代理可以适当调低。', bottomHelpMessage: '等待响应的超时时间单位为秒默认为120。如果不使用反代而是使用代理可以适当调低。',
component: 'InputNumber' component: 'InputNumber'
}, },
{
label: '以下为ChatGLM方式的配置',
component: 'Divider'
},
{
field: 'chatglmBaseUrl',
label: 'ChatGLM API地址',
bottomHelpMessage: '如 http://localhost:8080',
component: 'Input'
},
{ {
label: '以下为星火方式的配置', label: '以下为星火方式的配置',
component: 'Divider' component: 'Divider'
@ -649,6 +605,7 @@ export function supportGuoba () {
{ label: '体验版', value: 'web' }, { label: '体验版', value: 'web' },
{ label: '讯飞星火认知大模型V1.5', value: 'api' }, { label: '讯飞星火认知大模型V1.5', value: 'api' },
{ label: '讯飞星火认知大模型V2.0', value: 'apiv2' }, { label: '讯飞星火认知大模型V2.0', value: 'apiv2' },
{ label: '讯飞星火认知大模型V3.0', value: 'apiv3' },
{ label: '讯飞星火助手', value: 'assistants' } { label: '讯飞星火助手', value: 'assistants' }
] ]
} }

View file

@ -2,6 +2,20 @@ import { UserInfo, AddUser } from './user_data.js'
import { randomString, getUserData, getMasterQQ, getUin } from '../../utils/common.js' import { randomString, getUserData, getMasterQQ, getUin } from '../../utils/common.js'
import fs from 'fs' import fs from 'fs'
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
}
}
async function User (fastify, options) { async function User (fastify, options) {
// 登录 // 登录
fastify.post('/login', async (request, reply) => { fastify.post('/login', async (request, reply) => {
@ -13,8 +27,7 @@ async function User(fastify, options) {
let { getAllWebAddress } = await import('../../../Guoba-Plugin/utils/common.js') let { getAllWebAddress } = await import('../../../Guoba-Plugin/utils/common.js')
guobaLoginService = new LoginService() guobaLoginService = new LoginService()
guobaAPI = await getAllWebAddress() guobaAPI = await getAllWebAddress()
} } catch (err) {
catch (err) {
console.error(err) console.error(err)
guobaLoginService = { guobaLoginService = {
signToken: () => { return null } signToken: () => { return null }
@ -24,29 +37,29 @@ async function User(fastify, options) {
const token = randomString(32) const token = randomString(32)
if (body.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) { if (body.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) {
const guobaToken = await guobaLoginService.signToken(body.qq) const guobaToken = await guobaLoginService.signToken(body.qq)
AddUser({ user: body.qq, token: token, autho: 'admin' }) AddUser({ user: body.qq, token, autho: 'admin' })
reply.setCookie('token', token, { path: '/' }) reply.setCookie('token', token, { path: '/' })
reply.send({ login: true, autho: 'admin', token: token, guobaToken: guobaToken, guoba: guobaAPI }) reply.send({ login: true, autho: 'admin', token, guobaToken, guoba: guobaAPI })
} else { } else {
const user = await getUserData(body.qq) const user = await getUserData(body.qq)
if (user.passwd != '' && user.passwd === body.passwd) { if (user.passwd != '' && user.passwd === body.passwd) {
AddUser({ user: body.qq, token: token, autho: 'user' }) AddUser({ user: body.qq, token, autho: 'user' })
reply.setCookie('token', token, { path: '/' }) reply.setCookie('token', token, { path: '/' })
reply.send({ login: true, autho: 'user', token: token }) reply.send({ login: true, autho: 'user', token })
} else { } else {
reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改` }) reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改` })
} }
} }
} else if (body.otp) { } else if (body.otp) {
const token = randomString(32) const token = randomString(32)
const opt = await redis.get(`CHATGPT:SERVER_QUICK`) const opt = await redis.get('CHATGPT:SERVER_QUICK')
if (opt && body.otp == opt) { if (opt && body.otp == opt) {
const guobaToken = await guobaLoginService.signToken(getUin()) const guobaToken = await guobaLoginService.signToken(getUin())
AddUser({ user: getUin(), token: token, autho: 'admin' }) AddUser({ user: getUin(), token, autho: 'admin' })
reply.setCookie('token', token, { path: '/' }) reply.setCookie('token', token, { path: '/' })
reply.send({ login: true, autho: 'admin', token: token, user: getUin(), guobaToken: guobaToken, guoba: guobaAPI }) reply.send({ login: true, autho: 'admin', token, user: getUin(), guobaToken, guoba: guobaAPI })
} else { } else {
reply.send({ login: false, err: `快捷登录代码错误,请检查后重试` }) reply.send({ login: false, err: '快捷登录代码错误,请检查后重试' })
} }
} else { } else {
reply.send({ login: false, err: '未输入用户名或密码' }) reply.send({ login: false, err: '未输入用户名或密码' })
@ -57,15 +70,14 @@ async function User(fastify, options) {
fastify.post('/quick', async (request, reply) => { fastify.post('/quick', async (request, reply) => {
const otp = randomString(6) const otp = randomString(6)
await redis.set( await redis.set(
`CHATGPT:SERVER_QUICK`, 'CHATGPT:SERVER_QUICK',
otp, otp,
{ EX: 60000 } { EX: 60000 }
) )
const master = (await getMasterQQ())[0] const master = (await getMasterQQ())[0]
if (Array.isArray(Bot.uin)) { let bots = getBots()
Bot.pickFriend(master).sendMsg(`收到工具箱快捷登录请求1分钟内有效${otp}`) for (let bot of bots) {
} else { bot.pickUser(master).sendMsg(`收到工具箱快捷登录请求1分钟内有效${otp}`)
Bot.sendPrivateMsg(master, `收到工具箱快捷登录请求1分钟内有效${otp}`, false)
} }
reply.send({ state: true }) reply.send({ state: true })
return reply return reply
@ -76,7 +88,7 @@ async function User(fastify, options) {
const user = UserInfo(token) const user = UserInfo(token)
if (!user || token === 'unknown') { if (!user || token === 'unknown') {
reply.send({ reply.send({
verify: false, verify: false
}) })
return return
} }
@ -84,7 +96,7 @@ async function User(fastify, options) {
verify: true, verify: true,
user: user.user, user: user.user,
autho: user.autho, autho: user.autho,
version: 10016, version: 10016
}) })
return reply return reply
}) })
@ -101,7 +113,7 @@ async function User(fastify, options) {
api: '', // API设定 api: '', // API设定
bing: '', // 必应设定 bing: '', // 必应设定
bing_resource: '', // 必应扩展资料 bing_resource: '', // 必应扩展资料
slack: '', //Slack设定 slack: '' // Slack设定
} }
}) })
return reply return reply

View file

@ -820,6 +820,7 @@ export async function getImageOcrText (e) {
// logger.warn('resultArr', resultArr) // logger.warn('resultArr', resultArr)
return resultArr return resultArr
} catch (err) { } catch (err) {
logger.warn('OCR失败可能使用的适配器不支持OCR')
return false return false
// logger.error(err) // logger.error(err)
} }

View file

@ -144,7 +144,7 @@ const defaultConfig = {
serpSource: 'ikechan8370', serpSource: 'ikechan8370',
extraUrl: 'https://cpe.ikechan8370.com', extraUrl: 'https://cpe.ikechan8370.com',
smartMode: false, smartMode: false,
bingCaptchaOneShotUrl: 'http://bingcaptcha.ikechan8370.com/bing', bingCaptchaOneShotUrl: '',
// claude2 // claude2
claudeAIOrganizationId: '', claudeAIOrganizationId: '',
claudeAISessionKey: '', claudeAISessionKey: '',

View file

@ -3,6 +3,7 @@ import { Config } from '../config.js'
import { createParser } from 'eventsource-parser' import { createParser } from 'eventsource-parser'
import https from 'https' import https from 'https'
import WebSocket from 'ws' import WebSocket from 'ws'
import { createHmac } from 'crypto'
const referer = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNuL2NoYXQ/aWQ9') const referer = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNuL2NoYXQ/aWQ9')
const origin = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNu') const origin = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNu')
@ -14,12 +15,6 @@ try {
} catch (err) { } catch (err) {
logger.warn('未安装form-data无法使用星火模式') 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 let Keyv
try { try {
@ -84,28 +79,27 @@ export default class XinghuoClient {
} }
async getWsUrl () { async getWsUrl () {
if (!crypto) return false
const APISecret = Config.xhAPISecret const APISecret = Config.xhAPISecret
const APIKey = Config.xhAPIKey const APIKey = Config.xhAPIKey
let APILink = '/v1.1/chat' let APILink = '/v1.1/chat'
if (Config.xhmode == 'apiv2') { if (Config.xhmode === 'apiv2') {
APILink = '/v2.1/chat' APILink = '/v2.1/chat'
} else if (Config.xhmode == 'apiv3') { } else if (Config.xhmode === 'apiv3') {
APILink = '/v3.1/chat' APILink = '/v3.1/chat'
} }
const date = new Date().toGMTString() const date = new Date().toGMTString()
const algorithm = 'hmac-sha256' const algorithm = 'hmac-sha256'
const headers = 'host date request-line' const headers = 'host date request-line'
const signatureOrigin = `host: spark-api.xf-yun.com\ndate: ${date}\nGET ${APILink} HTTP/1.1` 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) hmac.update(signatureOrigin)
const signature = hmac.digest('base64') const signature = hmac.digest('base64')
const authorizationOrigin = `api_key="${APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"` const authorizationOrigin = `api_key="${APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
const authorization = Buffer.from(authorizationOrigin).toString('base64') const authorization = Buffer.from(authorizationOrigin).toString('base64')
const v = { const v = {
authorization: authorization, authorization,
date: date, date,
host: "spark-api.xf-yun.com" host: 'spark-api.xf-yun.com'
} }
const url = `wss://spark-api.xf-yun.com${APILink}?${Object.keys(v).map(key => `${key}=${v[key]}`).join('&')}` const url = `wss://spark-api.xf-yun.com${APILink}?${Object.keys(v).map(key => `${key}=${v[key]}`).join('&')}`
return url return url
@ -114,7 +108,7 @@ export default class XinghuoClient {
async uploadImage (url) { async uploadImage (url) {
// 获取图片 // 获取图片
let response = await fetch(url, { let response = await fetch(url, {
method: 'GET', method: 'GET'
}) })
const blob = await response.blob() const blob = await response.blob()
const arrayBuffer = await blob.arrayBuffer() const arrayBuffer = await blob.arrayBuffer()
@ -125,7 +119,7 @@ export default class XinghuoClient {
const respOss = await fetch('https://xinghuo.xfyun.cn/iflygpt/oss/sign', { const respOss = await fetch('https://xinghuo.xfyun.cn/iflygpt/oss/sign', {
method: 'POST', method: 'POST',
headers: { headers: {
Cookie: 'ssoSessionId=' + this.ssoSessionId + ';', Cookie: 'ssoSessionId=' + this.ssoSessionId + ';'
}, },
body: formData body: formData
}) })
@ -180,12 +174,9 @@ export default class XinghuoClient {
// 获取ws链接 // 获取ws链接
const wsUrl = Config.xhmode == 'assistants' ? Config.xhAssistants : await this.getWsUrl() 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' let domain = 'general'
if (Config.xhmode == 'apiv2') if (Config.xhmode == 'apiv2') { domain = 'generalv2' } else if (Config.xhmode == 'apiv3') { domain = 'generalv3' }
domain = "generalv2"
else if (Config.xhmode == 'apiv3')
domain = "generalv3"
// 编写消息内容 // 编写消息内容
const wsSendData = { const wsSendData = {
header: { header: {
@ -194,7 +185,7 @@ export default class XinghuoClient {
}, },
parameter: { parameter: {
chat: { chat: {
domain: domain, domain,
temperature: Config.xhTemperature, // 核采样阈值 temperature: Config.xhTemperature, // 核采样阈值
max_tokens: Config.xhMaxTokens, // tokens最大长度 max_tokens: Config.xhMaxTokens, // tokens最大长度
chat_id: chatId, chat_id: chatId,
@ -203,10 +194,10 @@ export default class XinghuoClient {
}, },
payload: { payload: {
message: { message: {
"text": [ text: [
...ePrompt, ...ePrompt,
...conversation.messages, ...conversation.messages,
{ "role": "user", "content": prompt } { role: 'user', content: prompt }
] ]
} }
} }
@ -281,7 +272,7 @@ export default class XinghuoClient {
formData.append('clientType', '2') formData.append('clientType', '2')
formData.append('chatId', chatId) formData.append('chatId', chatId)
if (prompt.image) { if (prompt.image) {
prompt.text = prompt.text.replace("[图片]", "") // 清理消息中中首个被使用的图片 prompt.text = prompt.text.replace('[图片]', '') // 清理消息中中首个被使用的图片
const imgdata = await this.uploadImage(prompt.image) const imgdata = await this.uploadImage(prompt.image)
if (imgdata) { if (imgdata) {
formData.append('fileUrl', imgdata.url) formData.append('fileUrl', imgdata.url)
@ -396,7 +387,7 @@ export default class XinghuoClient {
logger.warn('星火设定序列化失败,本次对话不附带设定') logger.warn('星火设定序列化失败,本次对话不附带设定')
} }
} else { } 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 => { Prompt.forEach(obj => {
@ -427,7 +418,7 @@ export default class XinghuoClient {
if (!chatId) { if (!chatId) {
chatId = (await this.createChatList()).chatListId 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) // logger.info(response)
// let responseText = atob(response) // let responseText = atob(response)
// 处理图片 // 处理图片
@ -451,7 +442,7 @@ export default class XinghuoClient {
return { return {
conversationId: chatId, conversationId: chatId,
text: response, text: response,
images: images images
} }
} else { } else {
throw new Error('星火模式错误') throw new Error('星火模式错误')