mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 22:07:10 +00:00
commit
04c6a5c8c7
7 changed files with 207 additions and 400 deletions
|
|
@ -357,6 +357,10 @@ export class ChatgptManagement extends plugin {
|
||||||
reg: '^#chatgpt(伪人|bym)切换',
|
reg: '^#chatgpt(伪人|bym)切换',
|
||||||
fnc: 'switchBYMModel',
|
fnc: 'switchBYMModel',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#(chatgpt)?(Copilot|Bing|必应)配置方法',
|
||||||
|
fnc: 'copilotSetting'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
@ -1880,6 +1884,25 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,
|
||||||
await this.reply('切换成功')
|
await this.reply('切换成功')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async copilotSetting (e) {
|
||||||
|
const code = 'let results = []\n' +
|
||||||
|
'Object.keys(localStorage).forEach(key => {\n' +
|
||||||
|
' try {\n' +
|
||||||
|
' let value = JSON.parse(localStorage[key])\n' +
|
||||||
|
' if (key.includes(\'accesstoken\') && value.target?.includes(\'ChatAI\')) {\n' +
|
||||||
|
' results[\'accessToken\'] = value.secret\n' +
|
||||||
|
' results[\'clientId\'] = value.clientId\n' +
|
||||||
|
' results[\'scope\'] = value.target + \' openid profile offline_access\'\n' +
|
||||||
|
' } else if (key.includes(\'refreshtoken\')) {\n' +
|
||||||
|
' results[\'oid\'] = value.homeAccountId\n' +
|
||||||
|
' results[\'refreshToken\'] = value.secret\n' +
|
||||||
|
' }\n' +
|
||||||
|
' } catch (err) {}\n' +
|
||||||
|
'})\n' +
|
||||||
|
'console.log(results)'
|
||||||
|
e.reply(`可以在浏览器控制台使用以下代码获取相关配置。\n\`\`\`javacript\n${code}\n\`\`\``)
|
||||||
|
}
|
||||||
|
|
||||||
async geminiOpenSearchCE (e) {
|
async geminiOpenSearchCE (e) {
|
||||||
let msg = e.msg
|
let msg = e.msg
|
||||||
let open = msg.includes('开启')
|
let open = msg.includes('开启')
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
import WebSocket from 'ws'
|
import WebSocket from 'ws'
|
||||||
import common from '../../../lib/common/common.js'
|
import common from '../../../lib/common/common.js'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { pTimeout } from '../utils/common.js'
|
||||||
|
|
||||||
export class BingAIClient {
|
export class BingAIClient {
|
||||||
constructor (accessToken, baseUrl = 'wss://copilot.microsoft.com/c/api/chat', debug, _2captchaKey, clientId, scope, refreshToken, oid) {
|
constructor (accessToken, baseUrl = 'wss://copilot.microsoft.com', debug, _2captchaKey, clientId, scope, refreshToken, oid, reasoning = false) {
|
||||||
this.accessToken = accessToken
|
this.accessToken = accessToken
|
||||||
this.baseUrl = baseUrl
|
this.baseUrl = baseUrl
|
||||||
|
if (this.baseUrl.endsWith('/')) {
|
||||||
|
this.baseUrl = _.trimEnd(baseUrl, '/')
|
||||||
|
}
|
||||||
this.ws = null
|
this.ws = null
|
||||||
this.conversationId = null
|
this.conversationId = null
|
||||||
this.partialMessages = new Map()
|
this.partialMessages = new Map()
|
||||||
|
|
@ -14,6 +19,7 @@ export class BingAIClient {
|
||||||
this.scope = scope
|
this.scope = scope
|
||||||
this.refreshToken = refreshToken
|
this.refreshToken = refreshToken
|
||||||
this.oid = oid
|
this.oid = oid
|
||||||
|
this.reasoning = reasoning
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage (text, options = {}) {
|
async sendMessage (text, options = {}) {
|
||||||
|
|
@ -21,7 +27,7 @@ export class BingAIClient {
|
||||||
if (options.conversationId) {
|
if (options.conversationId) {
|
||||||
this.conversationId = options.conversationId
|
this.conversationId = options.conversationId
|
||||||
} else {
|
} else {
|
||||||
this.conversationId = this._generateConversationId()
|
this.conversationId = await this._generateConversationId()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 建立 WebSocket 连接
|
// 建立 WebSocket 连接
|
||||||
|
|
@ -31,16 +37,32 @@ export class BingAIClient {
|
||||||
await this.sendInitialMessage(text)
|
await this.sendInitialMessage(text)
|
||||||
|
|
||||||
// 等待并收集服务器的回复
|
// 等待并收集服务器的回复
|
||||||
const responseText = await this.collectResponse()
|
try {
|
||||||
return responseText
|
const responseText = await pTimeout(await this.collectResponse(), {
|
||||||
|
milliseconds: 1000 * 60 * 5
|
||||||
|
})
|
||||||
|
return responseText
|
||||||
|
} catch (err) {
|
||||||
|
if (this.partialMessages.get(this.currentMessageId)) {
|
||||||
|
return this.partialMessages.get(this.currentMessageId).text
|
||||||
|
} else {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async connectWebSocket () {
|
async connectWebSocket () {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let url = `${this.baseUrl}?api-version=2`
|
let wsUrl = this.baseUrl
|
||||||
|
if (wsUrl.startsWith('http')) {
|
||||||
|
wsUrl = wsUrl.replace('https://', 'wss://')
|
||||||
|
.replace('http://', 'ws://')
|
||||||
|
}
|
||||||
|
let url = `${wsUrl}/c/api/chat?api-version=2`
|
||||||
if (this.accessToken) {
|
if (this.accessToken) {
|
||||||
url += '&accessToken=' + this.accessToken
|
url += '&accessToken=' + this.accessToken
|
||||||
}
|
}
|
||||||
|
logger.info('ws url: ' + url)
|
||||||
this.ws = new WebSocket(url)
|
this.ws = new WebSocket(url)
|
||||||
|
|
||||||
this.ws.on('open', () => {
|
this.ws.on('open', () => {
|
||||||
|
|
@ -50,13 +72,12 @@ export class BingAIClient {
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
this.ws.on('message', (message) => {
|
this.ws.on('message', (message) => {
|
||||||
logger.info(JSON.stringify(message))
|
logger.info('received message', String(message))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.ws.on('close', (code, reason) => {
|
this.ws.on('close', (code, reason) => {
|
||||||
console.log('WebSocket connection closed. Code:', code, 'Reason:', reason)
|
console.log('WebSocket connection closed. Code:', code, 'Reason:', reason)
|
||||||
|
|
||||||
// 401 错误码通常是未授权,可以根据实际情况修改
|
|
||||||
if (code === 401) {
|
if (code === 401) {
|
||||||
logger.error('token expired. try to refresh with refresh token')
|
logger.error('token expired. try to refresh with refresh token')
|
||||||
this.doRefreshToken(this.clientId, this.scope, this.refreshToken, this.oid)
|
this.doRefreshToken(this.clientId, this.scope, this.refreshToken, this.oid)
|
||||||
|
|
@ -71,33 +92,44 @@ export class BingAIClient {
|
||||||
|
|
||||||
async sendInitialMessage (text) {
|
async sendInitialMessage (text) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
const initMgs = { event: 'setOptions', supportedCards: ['image'], ads: null }
|
||||||
|
this.ws.send(JSON.stringify(initMgs))
|
||||||
|
if (this.debug) {
|
||||||
|
logger.info('send msg: ', JSON.stringify(initMgs))
|
||||||
|
}
|
||||||
const messagePayload = {
|
const messagePayload = {
|
||||||
event: 'send',
|
event: 'send',
|
||||||
conversationId: this.conversationId,
|
conversationId: this.conversationId,
|
||||||
content: [{ type: 'text', text }],
|
content: [{ type: 'text', text }],
|
||||||
mode: 'chat',
|
mode: this.reasoning ? 'reasoning' : 'chat',
|
||||||
context: { edge: 'NonContextual' }
|
context: { edge: 'NonContextual' }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接发送消息
|
// 直接发送消息
|
||||||
this.ws.send(JSON.stringify(messagePayload))
|
this.ws.send(JSON.stringify(messagePayload))
|
||||||
|
if (this.debug) {
|
||||||
|
logger.info('send msg: ', JSON.stringify(messagePayload))
|
||||||
|
}
|
||||||
|
let _this = this
|
||||||
// 设置超时机制,防止长时间未收到消息
|
// 设置超时机制,防止长时间未收到消息
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
reject(new Error('No response from server within timeout period.'))
|
reject(new Error('No response from server within timeout period.'))
|
||||||
}, 5000) // 设置 5 秒的超时时间
|
}, 5000) // 设置 5 秒的超时时间
|
||||||
|
|
||||||
// 一旦收到消息,处理逻辑
|
// 一旦收到消息,处理逻辑
|
||||||
this.ws.once('message', (data) => {
|
this.ws.once('message', (data) => {
|
||||||
clearTimeout(timeout) // 清除超时定时器
|
clearTimeout(timeout) // 清除超时定时器
|
||||||
const message = JSON.parse(data)
|
const message = JSON.parse(data)
|
||||||
|
logger.info(data)
|
||||||
if (message.event === 'challenge') {
|
if (message.event === 'challenge') {
|
||||||
logger.info(JSON.stringify(message))
|
|
||||||
logger.warn('遇到turnstile验证码,尝试使用2captcha解决')
|
logger.warn('遇到turnstile验证码,尝试使用2captcha解决')
|
||||||
// 如果收到 challenge,处理挑战
|
// 如果收到 challenge,处理挑战
|
||||||
this.handleChallenge(message)
|
this.handleChallenge(message)
|
||||||
.then(resolve)
|
.then(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
_this.ws.send(JSON.stringify(messagePayload))
|
||||||
|
resolve()
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
.catch(reject)
|
.catch(reject)
|
||||||
} else {
|
} else {
|
||||||
// 否则直接进入对话
|
// 否则直接进入对话
|
||||||
|
|
@ -152,14 +184,15 @@ export class BingAIClient {
|
||||||
this.partialMessages.get(message.messageId).text += message.text
|
this.partialMessages.get(message.messageId).text += message.text
|
||||||
|
|
||||||
// 如果是最后一部分,标记为完成
|
// 如果是最后一部分,标记为完成
|
||||||
if (message.partId === '0') {
|
// if (message.partId === '0') {
|
||||||
this.partialMessages.get(message.messageId).done = true
|
// this.partialMessages.get(message.messageId).done = true
|
||||||
}
|
// }
|
||||||
|
|
||||||
checkMessageComplete(message.messageId)
|
checkMessageComplete(message.messageId)
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'partCompleted':
|
case 'partCompleted':
|
||||||
|
this.partialMessages.get(message.messageId).done = true
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'done':
|
case 'done':
|
||||||
|
|
@ -167,7 +200,7 @@ export class BingAIClient {
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.warn('Unexpected event:', message.event)
|
// console.warn('Unexpected event:', message.event)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -203,6 +236,7 @@ export class BingAIClient {
|
||||||
taskId,
|
taskId,
|
||||||
clientKey: this._2captchaKey
|
clientKey: this._2captchaKey
|
||||||
})
|
})
|
||||||
|
|
||||||
async function getTaskResult () {
|
async function getTaskResult () {
|
||||||
const requestOptions2 = {
|
const requestOptions2 = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -213,12 +247,11 @@ export class BingAIClient {
|
||||||
|
|
||||||
const response2 = await fetch('https://api.2captcha.com/getTaskResult', requestOptions2)
|
const response2 = await fetch('https://api.2captcha.com/getTaskResult', requestOptions2)
|
||||||
const taskResponse = await response2.json()
|
const taskResponse = await response2.json()
|
||||||
if (this.debug) {
|
logger.info(JSON.stringify(taskResponse))
|
||||||
logger.info(JSON.stringify(taskResponse))
|
|
||||||
}
|
|
||||||
const token = taskResponse?.solution?.token
|
const token = taskResponse?.solution?.token
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
let retry = 90
|
let retry = 90
|
||||||
let token = await getTaskResult()
|
let token = await getTaskResult()
|
||||||
while (retry > 0 && !token) {
|
while (retry > 0 && !token) {
|
||||||
|
|
@ -232,8 +265,40 @@ export class BingAIClient {
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
_generateConversationId () {
|
async _generateConversationId () {
|
||||||
return 'conversation-' + Math.random().toString(36).substring(2, 15)
|
const url = `${this.baseUrl}/c/api/conversations`
|
||||||
|
const createConversationRsp = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${this.accessToken}`,
|
||||||
|
'content-type': 'application/json',
|
||||||
|
origin: 'https://copilot.microsoft.com',
|
||||||
|
referer: 'https://copilot.microsoft.com/',
|
||||||
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0'
|
||||||
|
},
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
const conversation = await createConversationRsp.json()
|
||||||
|
return conversation.id
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getCurrentConversationId () {
|
||||||
|
const url = `${this.baseUrl}/c/api/start`
|
||||||
|
const createConversationRsp = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${this.accessToken}`,
|
||||||
|
'content-type': 'application/json',
|
||||||
|
origin: 'https://copilot.microsoft.com',
|
||||||
|
referer: 'https://copilot.microsoft.com/',
|
||||||
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0'
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
timeZone: 'Asia/Shanghai',
|
||||||
|
teenSupportEnabled: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const conversation = await createConversationRsp.json()
|
||||||
|
return conversation.currentConversationId
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -270,7 +335,7 @@ export class BingAIClient {
|
||||||
urlencoded.append('x-ms-lib-capability', 'retry-after, h429')
|
urlencoded.append('x-ms-lib-capability', 'retry-after, h429')
|
||||||
urlencoded.append('x-client-current-telemetry', '5|61,0,,,|,')
|
urlencoded.append('x-client-current-telemetry', '5|61,0,,,|,')
|
||||||
urlencoded.append('x-client-last-telemetry', '5|3|||0,0')
|
urlencoded.append('x-client-last-telemetry', '5|3|||0,0')
|
||||||
urlencoded.append('client-request-id', '0193875c-0737-703c-a2e7-6730dd56aa4a')
|
urlencoded.append('client-request-id', crypto.randomUUID())
|
||||||
urlencoded.append('refresh_token', refreshToken)
|
urlencoded.append('refresh_token', refreshToken)
|
||||||
urlencoded.append('X-AnchorMailbox', 'Oid:' + oid)
|
urlencoded.append('X-AnchorMailbox', 'Oid:' + oid)
|
||||||
|
|
||||||
|
|
@ -286,6 +351,7 @@ export class BingAIClient {
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
logger.info(JSON.stringify(tokenJson))
|
logger.info(JSON.stringify(tokenJson))
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokenJson
|
return tokenJson
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
119
guoba.support.js
119
guoba.support.js
|
|
@ -190,28 +190,9 @@ export function supportGuoba () {
|
||||||
component: 'Divider'
|
component: 'Divider'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'toneStyle',
|
field: 'bingReasoning',
|
||||||
label: 'Bing模式',
|
label: 'Bing开启思考',
|
||||||
bottomHelpMessage: 'Copilot的应答风格。默认为创意,可切换为精准或均衡,均为GPT-turbo',
|
bottomHelpMessage: 'Copilot的思考功能。开启后无法搜索',
|
||||||
component: 'Select',
|
|
||||||
componentProps: {
|
|
||||||
options: [
|
|
||||||
{ label: '创意', value: 'Creative' },
|
|
||||||
{ label: '均衡', value: 'Balanced' },
|
|
||||||
{ label: '精准', value: 'Precise' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'sydneyEnableSearch',
|
|
||||||
label: '是否允许必应进行搜索',
|
|
||||||
bottomHelpMessage: '关闭后必应将禁用搜索',
|
|
||||||
component: 'Switch'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'enableSuggestedResponses',
|
|
||||||
label: '是否开启建议回复',
|
|
||||||
bottomHelpMessage: '开启了会像官网上一样,每个问题给出建议的用户问题',
|
|
||||||
component: 'Switch'
|
component: 'Switch'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -231,12 +212,6 @@ export function supportGuoba () {
|
||||||
bottomHelpMessage: '加强主人认知。希望机器人认清主人,避免NTR可开启。开启后可能会与自设定的内容有部分冲突。sydney模式可以放心开启',
|
bottomHelpMessage: '加强主人认知。希望机器人认清主人,避免NTR可开启。开启后可能会与自设定的内容有部分冲突。sydney模式可以放心开启',
|
||||||
component: 'Switch'
|
component: 'Switch'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: 'enableGenerateContents',
|
|
||||||
label: '允许生成图像等内容',
|
|
||||||
bottomHelpMessage: '开启后类似网页版能够发图。但是此选项会占用大量token,自设定等模式下容易爆token',
|
|
||||||
component: 'Switch'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: 'groupContextLength',
|
field: 'groupContextLength',
|
||||||
label: '允许机器人读取近期的最多群聊聊天记录条数。',
|
label: '允许机器人读取近期的最多群聊聊天记录条数。',
|
||||||
|
|
@ -255,18 +230,6 @@ export function supportGuoba () {
|
||||||
bottomHelpMessage: '你可以自己改写设定,让Copilot变成你希望的样子。可能存在不稳定的情况',
|
bottomHelpMessage: '你可以自己改写设定,让Copilot变成你希望的样子。可能存在不稳定的情况',
|
||||||
component: 'InputTextArea'
|
component: 'InputTextArea'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: 'sydneyApologyIgnored',
|
|
||||||
label: 'Bing抱歉是否不计入聊天记录',
|
|
||||||
bottomHelpMessage: '有时无限抱歉,就关掉这个再多问几次试试,可能有奇效',
|
|
||||||
component: 'Switch'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'sydneyContext',
|
|
||||||
label: 'Bing的扩展资料',
|
|
||||||
bottomHelpMessage: 'AI将会从你提供的扩展资料中学习到一些知识,帮助它更好地回答你的问题。实际相当于使用edge侧边栏Bing时读取的你当前浏览网页的内容。如果太长可能容易到达GPT-4的8192token上限',
|
|
||||||
component: 'InputTextArea'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
field: 'sydneyReverseProxy',
|
field: 'sydneyReverseProxy',
|
||||||
label: '必应反代',
|
label: '必应反代',
|
||||||
|
|
@ -274,70 +237,40 @@ export function supportGuoba () {
|
||||||
component: 'Input'
|
component: 'Input'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'sydneyForceUseReverse',
|
field: 'bingAiToken',
|
||||||
label: '强制使用sydney反代',
|
label: '必应AccessToken',
|
||||||
bottomHelpMessage: '即使配置了proxy,创建对话时依然使用必应反代',
|
bottomHelpMessage: 'Copilot的AccessToken,scope需为ChatAI.ReadWrite。可以发送`#Copilot配置方法`查看浏览器获取配置的方法。',
|
||||||
component: 'Switch'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'sydneyWebsocketUseProxy',
|
|
||||||
label: '对话使用必应反代',
|
|
||||||
bottomHelpMessage: '默认情况下仅创建对话走反代,对话时仍然直连微软。开启本选项将使对话过程也走反代,需反代支持。默认开启',
|
|
||||||
component: 'Switch'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'bingCaptchaOneShotUrl',
|
|
||||||
label: '必应验证码pass服务',
|
|
||||||
bottomHelpMessage: '必应出验证码会自动用该服务绕过',
|
|
||||||
component: 'Input'
|
component: 'Input'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'sydneyMood',
|
field: 'bingAiClientId',
|
||||||
label: '情感显示',
|
label: '必应ClientId',
|
||||||
bottomHelpMessage: '开启Sydney的情感显示,仅在图片模式下生效',
|
bottomHelpMessage: '配合RefreshToken刷新AccessToken',
|
||||||
component: 'Switch'
|
component: 'Input'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'sydneyImageRecognition',
|
field: 'bingAiScope',
|
||||||
label: '图片识别',
|
label: '必应Auth Scope',
|
||||||
bottomHelpMessage: '开启Sydney的图片识别功能,建议和OCR只保留一个开启',
|
bottomHelpMessage: '配合RefreshToken刷新AccessToken',
|
||||||
component: 'Switch'
|
component: 'Input'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'chatExampleUser1',
|
field: 'bingAiRefreshToken',
|
||||||
label: '前置对话第一轮(用户)',
|
label: '必应RefreshToken',
|
||||||
bottomHelpMessage: '会强行插入该轮对话,能有效抑制抱歉',
|
bottomHelpMessage: '配合RefreshToken刷新AccessToken',
|
||||||
component: 'InputTextArea'
|
component: 'Input'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'chatExampleBot1',
|
field: 'bingAiOid',
|
||||||
label: '前置对话第一轮(AI)',
|
label: '必应Oid',
|
||||||
bottomHelpMessage: '会强行插入该轮对话,能有效抑制抱歉',
|
bottomHelpMessage: '(homeAccountId)配合RefreshToken刷新AccessToken',
|
||||||
component: 'InputTextArea'
|
component: 'Input'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'chatExampleUser2',
|
field: '_2captchaKey',
|
||||||
label: '前置对话第二轮(用户)',
|
label: '2captcha API密钥',
|
||||||
bottomHelpMessage: '会强行插入该轮对话,能有效抑制抱歉',
|
bottomHelpMessage: '用于解除Copilot的验证码',
|
||||||
component: 'InputTextArea'
|
component: 'Input'
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'chatExampleBot2',
|
|
||||||
label: '前置对话第二轮(AI)',
|
|
||||||
bottomHelpMessage: '会强行插入该轮对话,能有效抑制抱歉',
|
|
||||||
component: 'InputTextArea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'chatExampleUser3',
|
|
||||||
label: '前置对话第三轮(用户)',
|
|
||||||
bottomHelpMessage: '会强行插入该轮对话,能有效抑制抱歉',
|
|
||||||
component: 'InputTextArea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'chatExampleBot3',
|
|
||||||
label: '前置对话第三轮(AI)',
|
|
||||||
bottomHelpMessage: '会强行插入该轮对话,能有效抑制抱歉',
|
|
||||||
component: 'InputTextArea'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '以下为API3方式的配置',
|
label: '以下为API3方式的配置',
|
||||||
|
|
|
||||||
340
model/core.js
340
model/core.js
|
|
@ -4,21 +4,15 @@ import {
|
||||||
formatDate,
|
formatDate,
|
||||||
getImg,
|
getImg,
|
||||||
getMasterQQ, getMaxModelTokens,
|
getMasterQQ, getMaxModelTokens,
|
||||||
getOrDownloadFile,
|
|
||||||
getUin,
|
getUin,
|
||||||
getUserData,
|
getUserData,
|
||||||
isCN
|
isCN
|
||||||
} from '../utils/common.js'
|
} from '../utils/common.js'
|
||||||
import { KeyvFile } from 'keyv-file'
|
import { KeyvFile } from 'keyv-file'
|
||||||
import SydneyAIClient from '../utils/SydneyAIClient.js'
|
import SydneyAIClient from '../utils/SydneyAIClient.js'
|
||||||
import _ from 'lodash'
|
|
||||||
import { getChatHistoryGroup } from '../utils/chat.js'
|
import { getChatHistoryGroup } from '../utils/chat.js'
|
||||||
import { APTool } from '../utils/tools/APTool.js'
|
import { APTool } from '../utils/tools/APTool.js'
|
||||||
import BingDrawClient from '../utils/BingDraw.js'
|
|
||||||
import BingSunoClient from '../utils/BingSuno.js'
|
|
||||||
import { solveCaptchaOneShot } from '../utils/bingCaptcha.js'
|
|
||||||
import { OfficialChatGPTClient } from '../utils/message.js'
|
import { OfficialChatGPTClient } from '../utils/message.js'
|
||||||
import ChatGLMClient from '../utils/chatglm.js'
|
|
||||||
import { ClaudeAPIClient } from '../client/ClaudeAPIClient.js'
|
import { ClaudeAPIClient } from '../client/ClaudeAPIClient.js'
|
||||||
import { ClaudeAIClient } from '../utils/claude.ai/index.js'
|
import { ClaudeAIClient } from '../utils/claude.ai/index.js'
|
||||||
import XinghuoClient from '../utils/xinghuo/xinghuo.js'
|
import XinghuoClient from '../utils/xinghuo/xinghuo.js'
|
||||||
|
|
@ -26,8 +20,6 @@ import { getMessageById, upsertMessage } from '../utils/history.js'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
import { CustomGoogleGeminiClient } from '../client/CustomGoogleGeminiClient.js'
|
import { CustomGoogleGeminiClient } from '../client/CustomGoogleGeminiClient.js'
|
||||||
import { resizeAndCropImage } from '../utils/dalle.js'
|
|
||||||
import fs from 'fs'
|
|
||||||
import { QueryStarRailTool } from '../utils/tools/QueryStarRailTool.js'
|
import { QueryStarRailTool } from '../utils/tools/QueryStarRailTool.js'
|
||||||
import { WebsiteTool } from '../utils/tools/WebsiteTool.js'
|
import { WebsiteTool } from '../utils/tools/WebsiteTool.js'
|
||||||
import { SendPictureTool } from '../utils/tools/SendPictureTool.js'
|
import { SendPictureTool } from '../utils/tools/SendPictureTool.js'
|
||||||
|
|
@ -59,6 +51,9 @@ import { ChatGPTAPI } from '../utils/openai/chatgpt-api.js'
|
||||||
import { newFetch } from '../utils/proxy.js'
|
import { newFetch } from '../utils/proxy.js'
|
||||||
import { ChatGLM4Client } from '../client/ChatGLM4Client.js'
|
import { ChatGLM4Client } from '../client/ChatGLM4Client.js'
|
||||||
import { QwenApi } from '../utils/alibaba/qwen-api.js'
|
import { QwenApi } from '../utils/alibaba/qwen-api.js'
|
||||||
|
import { BingAIClient } from '../client/CopilotAIClient.js'
|
||||||
|
import Keyv from 'keyv'
|
||||||
|
import crypto from 'crypto'
|
||||||
|
|
||||||
const roleMap = {
|
const roleMap = {
|
||||||
owner: 'group owner',
|
owner: 'group owner',
|
||||||
|
|
@ -145,287 +140,70 @@ class Core {
|
||||||
const userData = await getUserData(e.user_id)
|
const userData = await getUserData(e.user_id)
|
||||||
const useCast = userData.cast || {}
|
const useCast = userData.cast || {}
|
||||||
if (use === 'bing') {
|
if (use === 'bing') {
|
||||||
let throttledTokens = []
|
|
||||||
let {
|
|
||||||
bingToken,
|
|
||||||
allThrottled
|
|
||||||
} = await getAvailableBingToken(conversation, throttledTokens)
|
|
||||||
let cookies
|
|
||||||
if (bingToken?.indexOf('=') > -1) {
|
|
||||||
cookies = bingToken
|
|
||||||
}
|
|
||||||
let bingAIClient
|
|
||||||
const cacheOptions = {
|
const cacheOptions = {
|
||||||
namespace: Config.toneStyle,
|
namespace: Config.toneStyle,
|
||||||
store: new KeyvFile({ filename: 'cache.json' })
|
store: new KeyvFile({ filename: 'cache.json' })
|
||||||
}
|
}
|
||||||
bingAIClient = new SydneyAIClient({
|
const conversationsCache = new Keyv(cacheOptions)
|
||||||
userToken: bingToken, // "_U" cookie from bing.com
|
let client = new BingAIClient(Config.bingAiToken, Config.sydneyReverseProxy, Config.debug, Config._2captchaKey, Config.bingAiClientId, Config.bingAiScope, Config.bingAiRefreshToken, Config.bingAiOid, Config.bingReasoning)
|
||||||
cookies,
|
const conversationKey = `SydneyUser_${e.sender.user_id}`
|
||||||
debug: Config.debug,
|
const conversations = (await conversationsCache.get(conversationKey)) || {
|
||||||
cache: cacheOptions,
|
messages: [],
|
||||||
user: e.sender.user_id,
|
createdAt: Date.now()
|
||||||
proxy: Config.proxy
|
}
|
||||||
})
|
logger.info(JSON.stringify(conversations))
|
||||||
// Sydney不实现上下文传递,删除上下文索引
|
const previousCachedMessages = SydneyAIClient.getMessagesForConversation(conversations.messages, conversation.parentMessageId)
|
||||||
delete conversation.clientId
|
.map((message) => {
|
||||||
delete conversation.invocationId
|
return {
|
||||||
delete conversation.conversationSignature
|
text: message.message,
|
||||||
let response
|
author: message.role === 'User' ? 'user' : 'bot'
|
||||||
let reply = ''
|
|
||||||
let retry = 3
|
|
||||||
let errorMessage = ''
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
let opt = _.cloneDeep(conversation) || {}
|
|
||||||
opt.toneStyle = Config.toneStyle
|
|
||||||
// 如果当前没有开启对话或者当前是Sydney模式、Custom模式,则本次对话携带拓展资料
|
|
||||||
let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${e.sender.user_id}`)
|
|
||||||
if (!c) {
|
|
||||||
opt.context = useCast?.bing_resource || Config.sydneyContext
|
|
||||||
}
|
}
|
||||||
// 重新拿存储的token,因为可能之前有过期的被删了
|
})
|
||||||
let abtrs = await getAvailableBingToken(conversation, throttledTokens)
|
let system = opt.system.bing
|
||||||
bingToken = abtrs.bingToken
|
if (Config.enableGroupContext && e.isGroup) {
|
||||||
// eslint-disable-next-line no-unused-vars
|
let chats = await getChatHistoryGroup(e, Config.groupContextLength)
|
||||||
allThrottled = abtrs.allThrottled
|
const namePlaceholder = '[name]'
|
||||||
if (bingToken?.indexOf('=') > -1) {
|
const defaultBotName = 'Copilot'
|
||||||
cookies = bingToken
|
const groupContextTip = Config.groupContextTip
|
||||||
}
|
let botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname
|
||||||
if (!bingAIClient.opts) {
|
system = system.replaceAll(namePlaceholder, botName || defaultBotName) +
|
||||||
bingAIClient.opts = {}
|
((Config.enableGroupContext && e.group_id) ? groupContextTip : '')
|
||||||
}
|
system += 'Attention, you are currently chatting in a qq group, then one who asks you now is' + `${e.sender.card || e.sender.nickname}(${e.sender.user_id}).`
|
||||||
bingAIClient.opts.userToken = bingToken
|
system += `the group name is ${e.group.name || e.group_name}, group id is ${e.group_id}.`
|
||||||
bingAIClient.opts.cookies = cookies
|
system += `Your nickname is ${botName} in the group,`
|
||||||
// opt.messageType = allThrottled ? 'Chat' : 'SearchQuery'
|
if (chats) {
|
||||||
if (Config.enableGroupContext && e.isGroup) {
|
system += 'There is the conversation history in the group, you must chat according to the conversation history context"'
|
||||||
try {
|
system += chats
|
||||||
opt.groupId = e.group_id
|
.map(chat => {
|
||||||
opt.qq = e.sender.user_id
|
let sender = chat.sender || {}
|
||||||
opt.nickname = e.sender.card
|
return `【${sender.card || sender.nickname}】(qq:${sender.user_id}, ${roleMap[sender.role] || 'normal user'},${sender.area ? 'from ' + sender.area + ', ' : ''} ${sender.age} years old, 群头衔:${sender.title}, gender: ${sender.sex}, time:${formatDate(new Date(chat.time * 1000))}, messageId: ${chat.message_id}) 说:${chat.raw_message}`
|
||||||
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) {
|
|
||||||
opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname
|
|
||||||
}
|
|
||||||
if (master && !e.group) {
|
|
||||||
opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname
|
|
||||||
}
|
|
||||||
opt.chats = await getChatHistoryGroup(e, Config.groupContextLength)
|
|
||||||
} catch (err) {
|
|
||||||
logger.warn('获取群聊聊天记录失败,本次对话不携带聊天记录', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let toSummaryFileContent
|
|
||||||
try {
|
|
||||||
if (e.source) {
|
|
||||||
let seq = e.isGroup ? e.source.seq : e.source.time
|
|
||||||
if (e.adapter === 'shamrock') {
|
|
||||||
seq = e.source.message_id
|
|
||||||
}
|
|
||||||
let msgs = e.isGroup ? await e.group.getChatHistory(seq, 1) : await e.friend.getChatHistory(seq, 1)
|
|
||||||
let sourceMsg = msgs[msgs.length - 1]
|
|
||||||
let fileMsgElem = sourceMsg.file || sourceMsg.message.find(msg => msg.type === 'file')
|
|
||||||
if (fileMsgElem) {
|
|
||||||
toSummaryFileContent = await extractContentFromFile(fileMsgElem, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
logger.warn('读取文件内容出错, 忽略文件内容', err)
|
|
||||||
}
|
|
||||||
opt.toSummaryFileContent = toSummaryFileContent
|
|
||||||
// 写入图片数据
|
|
||||||
if (Config.sydneyImageRecognition) {
|
|
||||||
const image = await getImg(e)
|
|
||||||
opt.imageUrl = image ? image[0] : undefined
|
|
||||||
}
|
|
||||||
if (Config.enableGenerateContents) {
|
|
||||||
opt.onImageCreateRequest = prompt => {
|
|
||||||
logger.mark(`开始生成内容:${prompt}`)
|
|
||||||
if (Config.bingAPDraw) {
|
|
||||||
// 调用第三方API进行绘图
|
|
||||||
let apDraw = new APTool()
|
|
||||||
apDraw.func({
|
|
||||||
prompt
|
|
||||||
}, e)
|
|
||||||
} else {
|
|
||||||
let client = new BingDrawClient({
|
|
||||||
baseUrl: Config.sydneyReverseProxy,
|
|
||||||
userToken: bingToken
|
|
||||||
})
|
|
||||||
redis.set(`CHATGPT:DRAW:${e.sender.user_id}`, 'c', { EX: 30 }).then(() => {
|
|
||||||
try {
|
|
||||||
client.getImages(prompt, e)
|
|
||||||
} catch (err) {
|
|
||||||
redis.del(`CHATGPT:DRAW:${e.sender.user_id}`)
|
|
||||||
this.reply('绘图失败:' + err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opt.onSunoCreateRequest = prompt => {
|
|
||||||
logger.mark(`开始生成内容:Suno ${prompt.songtId || ''}`)
|
|
||||||
let client = new BingSunoClient({
|
|
||||||
cookies: cookies
|
|
||||||
})
|
|
||||||
redis.set(`CHATGPT:SUNO:${e.sender.user_id}`, 'c', { EX: 30 }).then(() => {
|
|
||||||
try {
|
|
||||||
if (Config.bingSuno == 'local') {
|
|
||||||
// 调用本地Suno配置进行歌曲生成
|
|
||||||
client.getLocalSuno(prompt, e)
|
|
||||||
} else if (Config.bingSuno == 'api' && Config.bingSunoApi) {
|
|
||||||
// 调用第三方Suno配置进行歌曲生成
|
|
||||||
client.getApiSuno(prompt, e)
|
|
||||||
} else {
|
|
||||||
// 调用Bing Suno进行歌曲生成
|
|
||||||
client.getSuno(prompt, e)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
redis.del(`CHATGPT:SUNO:${e.sender.user_id}`)
|
|
||||||
this.reply('歌曲生成失败:' + err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = await bingAIClient.sendMessage(prompt, opt, (token) => {
|
|
||||||
reply += token
|
|
||||||
})
|
|
||||||
if (response.details.adaptiveCards?.[0]?.body?.[0]?.text?.trim()) {
|
|
||||||
if (response.response === undefined) {
|
|
||||||
response.response = response.details.adaptiveCards?.[0]?.body?.[0]?.text?.trim()
|
|
||||||
}
|
|
||||||
response.response = response.response.replace(/\[\^[0-9]+\^\]/g, (str) => {
|
|
||||||
return str.replace(/[/^]/g, '')
|
|
||||||
})
|
})
|
||||||
// 有了新的引用属性
|
.join('\n')
|
||||||
// response.quote = response.details.adaptiveCards?.[0]?.body?.[0]?.text?.replace(/\[\^[0-9]+\^\]/g, '').replace(response.response, '').split('\n')
|
|
||||||
}
|
|
||||||
response.suggestedResponses = response.details.suggestedResponses?.map(s => s.text).join('\n')
|
|
||||||
// 新引用属性读取数据
|
|
||||||
if (response.details.sourceAttributions) {
|
|
||||||
response.quote = []
|
|
||||||
for (let quote of response.details.sourceAttributions) {
|
|
||||||
response.quote.push({
|
|
||||||
text: quote.providerDisplayName || '',
|
|
||||||
url: quote.seeMoreUrl,
|
|
||||||
imageLink: quote.imageLink || ''
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果token曾经有异常,则清除异常
|
|
||||||
let Tokens = JSON.parse((await redis.get('CHATGPT:BING_TOKENS')) || '[]')
|
|
||||||
const TokenIndex = Tokens?.findIndex(element => element.Token === abtrs.bingToken)
|
|
||||||
if (TokenIndex > 0 && Tokens[TokenIndex].exception) {
|
|
||||||
delete Tokens[TokenIndex].exception
|
|
||||||
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(Tokens))
|
|
||||||
}
|
|
||||||
errorMessage = ''
|
|
||||||
break
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error)
|
|
||||||
const message = error?.message || error?.data?.message || error || '出错了'
|
|
||||||
const { maxConv } = error
|
|
||||||
if (message && typeof message === 'string' && message.indexOf('CaptchaChallenge') > -1) {
|
|
||||||
if (bingToken) {
|
|
||||||
if (maxConv >= 20 && Config.bingCaptchaOneShotUrl) {
|
|
||||||
// maxConv为30说明token有效,可以通过解验证码码服务过码
|
|
||||||
await this.reply('出现必应验证码,尝试解决中')
|
|
||||||
try {
|
|
||||||
let captchaResolveResult = await solveCaptchaOneShot(bingToken)
|
|
||||||
if (captchaResolveResult?.success) {
|
|
||||||
await this.reply('验证码已解决')
|
|
||||||
} else {
|
|
||||||
logger.error(captchaResolveResult)
|
|
||||||
errorMessage = message
|
|
||||||
await this.reply('验证码解决失败: ' + captchaResolveResult.error)
|
|
||||||
retry = 0
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
logger.error(err)
|
|
||||||
await this.reply('验证码解决失败: ' + err)
|
|
||||||
retry = 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 未登录用户maxConv目前为5或10,出验证码是ip或MUID问题
|
|
||||||
logger.warn(`token [${bingToken}] 出现必应验证码,请前往网页版或app手动解决`)
|
|
||||||
errorMessage = message
|
|
||||||
retry = 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
retry = 0
|
|
||||||
}
|
|
||||||
} else if (message && typeof message === 'string' && message.indexOf('限流') > -1) {
|
|
||||||
throttledTokens.push(bingToken)
|
|
||||||
let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
|
|
||||||
const badBingToken = bingTokens.findIndex(element => element.Token === bingToken)
|
|
||||||
const now = new Date()
|
|
||||||
const hours = now.getHours()
|
|
||||||
now.setHours(hours + 6)
|
|
||||||
bingTokens[badBingToken].State = '受限'
|
|
||||||
bingTokens[badBingToken].DisactivationTime = now
|
|
||||||
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
|
|
||||||
// 不减次数
|
|
||||||
} else if (message && typeof message === 'string' && message.indexOf('UnauthorizedRequest') > -1) {
|
|
||||||
// token过期了
|
|
||||||
let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
|
|
||||||
const badBingToken = bingTokens.findIndex(element => element.Token === bingToken)
|
|
||||||
if (badBingToken > 0) {
|
|
||||||
// 可能是微软抽风,给三次机会
|
|
||||||
if (bingTokens[badBingToken]?.exception) {
|
|
||||||
if (bingTokens[badBingToken].exception <= 3) {
|
|
||||||
bingTokens[badBingToken].exception += 1
|
|
||||||
} else {
|
|
||||||
bingTokens[badBingToken].exception = 0
|
|
||||||
bingTokens[badBingToken].State = '过期'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bingTokens[badBingToken].exception = 1
|
|
||||||
}
|
|
||||||
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
|
|
||||||
} else {
|
|
||||||
retry = retry - 1
|
|
||||||
}
|
|
||||||
errorMessage = 'UnauthorizedRequest:必应token不正确或已过期'
|
|
||||||
// logger.warn(`token${bingToken}疑似不存在或已过期,再试试`)
|
|
||||||
// retry = retry - 1
|
|
||||||
} else {
|
|
||||||
retry--
|
|
||||||
errorMessage = message === 'Timed out waiting for response. Try enabling debug mode to see more information.' ? (reply ? `${reply}\n不行了,我的大脑过载了,处理不过来了!` : '必应的小脑瓜不好使了,不知道怎么回答!') : message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (retry > 0)
|
|
||||||
if (errorMessage) {
|
|
||||||
if (errorMessage.includes('CaptchaChallenge')) {
|
|
||||||
if (bingToken) {
|
|
||||||
errorMessage = '出现验证码,请使用当前账户前往https://www.bing.com/chat或Edge侧边栏或移动端APP手动解除验证码'
|
|
||||||
} else {
|
|
||||||
errorMessage = '未配置必应账户,建议绑定必应账户再使用必应模式'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
text: errorMessage,
|
|
||||||
error: true
|
|
||||||
}
|
|
||||||
} else if (response?.response) {
|
|
||||||
return {
|
|
||||||
text: response?.response,
|
|
||||||
quote: response?.quote,
|
|
||||||
suggestedResponses: response.suggestedResponses,
|
|
||||||
conversationId: response.conversationId,
|
|
||||||
clientId: response.clientId,
|
|
||||||
invocationId: response.invocationId,
|
|
||||||
conversationSignature: response.conversationSignature,
|
|
||||||
parentMessageId: response.apology ? conversation.parentMessageId : response.messageId,
|
|
||||||
bingToken
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.debug('no message')
|
|
||||||
return {
|
|
||||||
noMsg: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const msg = `System:\n${system}\n\nPrevious Messages:\n${JSON.stringify(previousCachedMessages)}\n\nUser: ${prompt}`
|
||||||
|
const response = await client.sendMessage(msg)
|
||||||
|
logger.info({ response })
|
||||||
|
const userMessage = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
parentMessageId: conversation.parentMessageId,
|
||||||
|
role: 'User',
|
||||||
|
message: prompt
|
||||||
|
}
|
||||||
|
conversations.messages.push(userMessage)
|
||||||
|
const replyMessage = {
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
parentMessageId: userMessage.id,
|
||||||
|
role: 'Bing',
|
||||||
|
message: response
|
||||||
|
}
|
||||||
|
conversations.messages.push(replyMessage)
|
||||||
|
await conversationsCache.set(conversationKey, conversations)
|
||||||
|
return {
|
||||||
|
text: response,
|
||||||
|
parentMessageId: replyMessage.id
|
||||||
|
|
||||||
|
}
|
||||||
} else if (use === 'api3') {
|
} else if (use === 'api3') {
|
||||||
// official without cloudflare
|
// official without cloudflare
|
||||||
let accessToken = await redis.get('CHATGPT:TOKEN')
|
let accessToken = await redis.get('CHATGPT:TOKEN')
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,6 @@ const defaultConfig = {
|
||||||
serpSource: 'ikechan8370',
|
serpSource: 'ikechan8370',
|
||||||
extraUrl: 'https://cpe.ikechan8370.com',
|
extraUrl: 'https://cpe.ikechan8370.com',
|
||||||
smartMode: false,
|
smartMode: false,
|
||||||
bingCaptchaOneShotUrl: '',
|
|
||||||
// claude2
|
// claude2
|
||||||
claudeAIOrganizationId: '',
|
claudeAIOrganizationId: '',
|
||||||
claudeAISessionKey: '',
|
claudeAISessionKey: '',
|
||||||
|
|
@ -219,6 +218,14 @@ const defaultConfig = {
|
||||||
forwardReasoning: true,
|
forwardReasoning: true,
|
||||||
geminiEnableGoogleSearch: false,
|
geminiEnableGoogleSearch: false,
|
||||||
geminiEnableCodeExecution: false,
|
geminiEnableCodeExecution: false,
|
||||||
|
bingAiToken: '', // copilot.microsoft.com accessToken
|
||||||
|
bingAiClientId: '',
|
||||||
|
bingAiScope: '140e65af-45d1-4427-bf08-3e7295db6836/ChatAI.ReadWrite openid profile offline_access',
|
||||||
|
bingAiRefreshToken: '',
|
||||||
|
bingAiOid: '',
|
||||||
|
_2captchaKey: '',
|
||||||
|
bingReasoning: false, // 是否深度思考
|
||||||
|
|
||||||
version: 'v2.8.3'
|
version: 'v2.8.3'
|
||||||
}
|
}
|
||||||
const _path = process.cwd()
|
const _path = process.cwd()
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ var ChatGPTAPI = /** @class */ (function () {
|
||||||
* @param fetch - Optional override for the `fetch` implementation to use. Defaults to the global `fetch` function.
|
* @param fetch - Optional override for the `fetch` implementation to use. Defaults to the global `fetch` function.
|
||||||
*/
|
*/
|
||||||
function ChatGPTAPI(opts) {
|
function ChatGPTAPI(opts) {
|
||||||
var apiKey = opts.apiKey, apiOrg = opts.apiOrg, _a = opts.apiBaseUrl, apiBaseUrl = _a === void 0 ? 'https://api.openai.com/v1' : _a, _b = opts.debug, debug = _b === void 0 ? false : _b, messageStore = opts.messageStore, completionParams = opts.completionParams, systemMessage = opts.systemMessage, _c = opts.maxModelTokens, maxModelTokens = _c === void 0 ? 4000 : _c, _d = opts.maxResponseTokens, maxResponseTokens = _d === void 0 ? 1000 : _d, getMessageById = opts.getMessageById, upsertMessage = opts.upsertMessage, _e = opts.fetch, fetch = _e === void 0 ? globalFetch : _e;
|
var apiKey = opts.apiKey, apiOrg = opts.apiOrg, _a = opts.apiBaseUrl, apiBaseUrl = _a === void 0 ? 'https://api.openai.com/v1' : _a, _b = opts.debug, debug = _b === void 0 ? false : _b, messageStore = opts.messageStore, completionParams = opts.completionParams, systemMessage = opts.systemMessage, _c = opts.maxModelTokens, maxModelTokens = _c === void 0 ? 4000 : _c, _d = opts.maxResponseTokens, maxResponseTokens = _d === void 0 ? 8192 : _d, getMessageById = opts.getMessageById, upsertMessage = opts.upsertMessage, _e = opts.fetch, fetch = _e === void 0 ? globalFetch : _e;
|
||||||
this._apiKey = apiKey;
|
this._apiKey = apiKey;
|
||||||
this._apiOrg = apiOrg;
|
this._apiOrg = apiOrg;
|
||||||
this._apiBaseUrl = apiBaseUrl;
|
this._apiBaseUrl = apiBaseUrl;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ export class ChatGPTAPI {
|
||||||
completionParams,
|
completionParams,
|
||||||
systemMessage,
|
systemMessage,
|
||||||
maxModelTokens = 4000,
|
maxModelTokens = 4000,
|
||||||
maxResponseTokens = 1000,
|
maxResponseTokens = 8192,
|
||||||
getMessageById,
|
getMessageById,
|
||||||
upsertMessage,
|
upsertMessage,
|
||||||
fetch = globalFetch
|
fetch = globalFetch
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue