Skip to content

Commit

Permalink
feat: 修改配置文件格式避免频繁panic;降低api模式重试次数;优化帮助显示;支持必应新增的三种模式切换
Browse files Browse the repository at this point in the history
  • Loading branch information
ikechan8370 committed Mar 3, 2023
1 parent a45ae14 commit 873deda
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 172 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 支持单人连续对话Conversation,群聊中支持加入其他人的对话
* API模式下,使用 gpt-3.5-turbo API,ChatGPT官网同款模型,仅需OpenAI Api Key,开箱即用。**注意收费**
* 支持问答图片截图
* 支持AI性格调教
* API3模式下,绕过Cloudflare防护直接访问ChatGPT的SSE API,与官方体验一致,且保留对话记录,在官网可查。免费。
* 提供基于浏览器的解决方案作为备选,API3不可用的情况下或担心账户安全的用户可以选择使用浏览器模式。
* 支持新[必应](https://www.bing.com/new)(Beta)
Expand All @@ -24,7 +25,7 @@ Node.js >= 18 / Node.js >= 14(with node-fetch)
> #### API模式和浏览器模式如何选择?
>
> * API模式会调用OpenAI官方提供的gpt-3.5-turbo API,ChatGPT官网同款模型,只需要提供API Key。一般情况下,该种方式响应速度更快,可配置项多,且不会像chatGPT官网一样总出现不可用的现象,但注意API调用是收费的,新用户有18美元试用金可用于支付,价格为`$0.0020/ 1K tokens`。(问题和回答**加起来**算token)
> * API3模式会调用第三方提供的官网反代API,他会帮你绕过CF防护,需要提供ChatGPT的Token。效果与官网和浏览器一致,但稳定性不一定。设置token和API2方法一样
> * API3模式会调用第三方提供的官网反代API,他会帮你绕过CF防护,需要提供ChatGPT的Token。效果与官网和浏览器一致,但稳定性不一定。发送#chatgpt设置token来设置token
> * 浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站,使得获得和官方以及API2模式一模一样的回复质量,同时保证安全性。缺点是本方法对环境要求较高,需要提供桌面环境和一个可用的代理(能够访问ChatGPT的IP地址),且响应速度不如API,而且高峰期容易无法使用。一般作为API3的下位替代。
> * 必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing登录Cookie方可使用。
1. 进入 Yunzai根目录
Expand All @@ -45,9 +46,10 @@ pnpm i
> 2.20更新:必应被大削,变得蠢了,建议还是API/API3优先
3. 修改配置
**本插件配置项比较多,建议使用[锅巴面板](https://github.com/guoba-yunzai/Guoba-Plugin)修改**

复制`plugins/chatgpt-plugin/config/config.example.js`并将其改名为`config.js`
编辑`plugins/chatgpt-plugin/config/config.js`文件,根据其中的注释修改必要配置项
复制`plugins/chatgpt-plugin/config/config.example.json`并将其改名为`config.json`\
编辑`plugins/chatgpt-plugin/config/config.json`文件,修改必要配置项

4. 重启Yunzai-Bot

Expand Down
138 changes: 63 additions & 75 deletions apps/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export class chatgpt extends plugin {
reg: '^#结束对话([sS]*)',
fnc: 'destroyConversations'
},
{
reg: '^#结束全部对话$',
fnc: 'endAllConversations'
},
// {
// reg: '#chatgpt帮助',
// fnc: 'help'
Expand Down Expand Up @@ -179,9 +183,40 @@ export class chatgpt extends plugin {
}
}

async endAllConversations (e) {
let use = await redis.get('CHATGPT:USE') || 'api'
let deleted = 0
switch (use) {
case 'bing':
case 'api': {
let cs = await redis.keys('CHATGPT:CONVERSATIONS:*')
for (let i = 0; i < cs.length; i++) {
await redis.del(cs[i])
if (Config.debug) {
logger.info('delete conversation of qq: ' + cs[i])
}
deleted++
}
break
}
case 'api3': {
let qcs = await redis.keys('CHATGPT:CONVERSATIONS:*')
for (let i = 0; i < qcs.length; i++) {
await redis.del(qcs[i])
if (Config.debug) {
logger.info('delete conversation bind: ' + qcs[i])
}
deleted++
}
break
}
}
await this.reply(`结束了${deleted}个中用户的对话。`, true)
}

async deleteConversation (e) {
let ats = e.message.filter(m => m.type === 'at')
let use = await redis.get('CHATGPT:USE')
let use = await redis.get('CHATGPT:USE') || 'api'
if (use !== 'api3') {
await this.reply('本功能当前仅支持API3模式', true)
return false
Expand All @@ -193,7 +228,7 @@ export class chatgpt extends plugin {
return false
} else {
let deleteResponse = await deleteConversation(conversationId, newFetch)
console.log(deleteResponse)
logger.mark(deleteResponse)
let deleted = 0
let qcs = await redis.keys('CHATGPT:QQ_CONVERSATION:*')
for (let i = 0; i < qcs.length; i++) {
Expand All @@ -215,7 +250,9 @@ export class chatgpt extends plugin {
let conversationId = await redis.get('CHATGPT:QQ_CONVERSATION:' + qq)
if (conversationId) {
let deleteResponse = await deleteConversation(conversationId)
console.log(deleteResponse)
if (Config.debug) {
logger.mark(deleteResponse)
}
let deleted = 0
let qcs = await redis.keys('CHATGPT:QQ_CONVERSATION:*')
for (let i = 0; i < qcs.length; i++) {
Expand All @@ -235,16 +272,6 @@ export class chatgpt extends plugin {
}
}

async help (e) {
let response = 'chatgpt-plugin使用帮助文字版\n' +
'@我+聊天内容: 发起对话与AI进行聊天\n' +
'#chatgpt对话列表: 查看当前发起的对话\n' +
'#结束对话: 结束自己或@用户的对话\n' +
'#chatgpt帮助: 查看本帮助\n' +
'源代码:https://github.com/ikechan8370/chatgpt-plugin'
await this.reply(response)
}

async switch2Picture (e) {
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
if (!userSetting) {
Expand Down Expand Up @@ -331,15 +358,8 @@ export class chatgpt extends plugin {
await this.reply('主人不让我回答你这种问题,真是抱歉了呢', true)
return false
}
// if (prompt.indexOf('<script>') != -1)
// {
// await this.reply('坏人,我要报告给主人', e.isGroup)
// Bot.pickUser(cfg.masterQQ[0]).sendMsg(`主人,我在${this.e.group_id ? '群' + this.e.group_id : '私聊' }被${e.sender.nickname}使用代码攻击了,请警惕`)
// return false
// }

const use = await redis.get('CHATGPT:USE')
if (use !== 'bing') {
const use = await redis.get('CHATGPT:USE') || 'api'
if (use === 'api3') {
let randomId = uuid()
// 队列队尾插入,开始排队
await redis.rPush('CHATGPT:CHAT_QUEUE', [randomId])
Expand All @@ -352,11 +372,11 @@ export class chatgpt extends plugin {
await this.reply('我正在思考如何回复你,请稍等', true, { recallMsg: 8 })
}
} else {
let length = await redis.lLen('CHATGPT:CHAT_QUEUE') - 1
if (confirmOn) {
let length = await redis.lLen('CHATGPT:CHAT_QUEUE') - 1
await this.reply(`我正在思考如何回复你,请稍等,当前队列前方还有${length}个问题`, true, { recallMsg: 8 })
logger.info(`chatgpt队列前方还有${length}个问题。管理员可通过#清空队列来强制清除所有等待的问题。`)
}
logger.info(`chatgpt队列前方还有${length}个问题。管理员可通过#清空队列来强制清除所有等待的问题。`)
// 开始排队
while (true) {
if (await redis.lIndex('CHATGPT:CHAT_QUEUE', 0) === randomId) {
Expand Down Expand Up @@ -573,48 +593,6 @@ export class chatgpt extends plugin {
case 'browser': {
return await this.chatgptBrowserBased(prompt, conversation)
}
case 'apiReverse': {
const currentDate = new Date().toISOString().split('T')[0]
let promptPrefix = `You are ${Config.assistantLabel}, a large language model trained by OpenAI. ${Config.promptPrefixOverride || defaultPropmtPrefix}
Current date: ${currentDate}`
const clientOptions = {
// (Optional) Support for a reverse proxy for the completions endpoint (private API server).
// Warning: This will expose your `openaiApiKey` to a third-party. Consider the risks before using this.
reverseProxyUrl: Config.reverseProxy || 'https://chatgpt.pawan.krd/api/completions',
// (Optional) Parameters as described in https://platform.openai.com/docs/api-reference/completions
modelOptions: {
// You can override the model name and any other parameters here.
model: Config.plus ? 'text-davinci-002-render-paid' : 'text-davinci-002-render'
},
// (Optional) Set custom instructions instead of "You are ChatGPT...".
promptPrefix,
// (Optional) Set a custom name for the user
// userLabel: 'User',
// (Optional) Set a custom name for ChatGPT
chatGptLabel: Config.assistantLabel,
// (Optional) Set to true to enable `console.debug()` logging
debug: Config.debug
}
const cacheOptions = {
// Options for the Keyv cache, see https://www.npmjs.com/package/keyv
// This is used for storing conversations, and supports additional drivers (conversations are stored in memory by default)
// For example, to use a JSON file (`npm i keyv-file`) as a database:
store: new KeyvFile({ filename: 'cache.json' })
}
let accessToken = await redis.get('CHATGPT:TOKEN')
if (!accessToken) {
throw new Error('未绑定ChatGPT AccessToken,请使用#chatgpt设置token命令绑定token')
}
// console.log(accessToken)
this.chatGPTApi = new ChatGPTClient(accessToken, clientOptions, cacheOptions)
let response = await tryTimes(async () => await this.chatGPTApi.sendMessage(prompt, conversation || {}), 1)
return {
text: response.response,
conversationId: response.conversationId,
id: response.messageId,
parentMessageId: conversation?.parentMessageId
}
}
case 'bing': {
let bingToken = await redis.get('CHATGPT:BING_TOKEN')
if (!bingToken) {
Expand All @@ -627,12 +605,15 @@ export class chatgpt extends plugin {
const bingAIClient = new BingAIClient({
userToken: bingToken, // "_U" cookie from bing.com
cookie,
debug: Config.debug
debug: Config.debug,
proxy: Config.proxy
})
let response
let reply = ''
try {
response = await bingAIClient.sendMessage(prompt, conversation || {}, (token) => {
let opt = _.cloneDeep(conversation) || {}
opt.toneStyle = Config.toneStyle
response = await bingAIClient.sendMessage(prompt, opt, (token) => {
reply += token
})
if (response.details.adaptiveCards?.[0]?.body?.[0]?.text?.trim()) {
Expand Down Expand Up @@ -714,7 +695,7 @@ export class chatgpt extends plugin {
if (conversation) {
option = Object.assign(option, conversation)
}
return await tryTimes(async () => await this.chatGPTApi.sendMessage(prompt, option), 5)
return await tryTimes(async () => await this.chatGPTApi.sendMessage(prompt, option), 1)
}
}
}
Expand Down Expand Up @@ -756,15 +737,15 @@ export class chatgpt extends plugin {

async joinConversation (e) {
let ats = e.message.filter(m => m.type === 'at')
let use = await redis.get('CHATGPT:USE')
if (use !== 'api3') {
await this.reply('本功能当前仅支持API3模式', true)
return false
}
let use = await redis.get('CHATGPT:USE') || 'api'
// if (use !== 'api3') {
// await this.reply('本功能当前仅支持API3模式', true)
// return false
// }
if (ats.length === 0) {
await this.reply('指令错误,使用本指令时请同时@某人', true)
return false
} else {
} else if (use === 'api3') {
let at = ats[0]
let qq = at.qq
let atUser = _.trimStart(at.text, '@')
Expand All @@ -775,6 +756,13 @@ export class chatgpt extends plugin {
}
await redis.set(`CHATGPT:QQ_CONVERSATION:${e.sender.user_id}`, conversationId)
await this.reply(`加入${atUser}的对话成功,当前对话id为` + conversationId)
} else {
let at = ats[0]
let qq = at.qq
let atUser = _.trimStart(at.text, '@')
let target = await redis.get('CHATGPT:CONVERSATIONS:' + qq)
await redis.set('CHATGPT:CONVERSATIONS:' + e.sender.user_id, target)
await this.reply(`加入${atUser}的对话成功`)
}
}

Expand Down
5 changes: 5 additions & 0 deletions apps/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ let helpData = [
title: '#结束对话',
desc: '结束自己当前对话,下次开启对话机器人将遗忘掉本次对话内容。'
},
{
icon: 'destroy',
title: '#结束全部对话',
desc: '结束正在与本机器人进行对话的全部用户的对话。'
},
{
icon: 'destroy-other',
title: '#结束对话 @某人',
Expand Down
9 changes: 5 additions & 4 deletions apps/management.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class ChatgptManagement extends plugin {
},
{
reg: '^#chatgpt切换(必应|Bing)$',
fnc: 'useReversedBingSolution',
fnc: 'useBingSolution',
permission: 'master'
},
{
Expand Down Expand Up @@ -157,8 +157,9 @@ export class ChatgptManagement extends plugin {
}

async useReversedAPIBasedSolution (e) {
await redis.set('CHATGPT:USE', 'apiReverse')
await this.reply('【暂时不可用,请关注仓库更新和群公告】已切换到基于第三方Reversed CompletionAPI的解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
await this.reply('API2已废弃,处于不可用状态,不会为你切换')
// await redis.set('CHATGPT:USE', 'apiReverse')
// await this.reply('【暂时不可用,请关注仓库更新和群公告】已切换到基于第三方Reversed CompletionAPI的解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
}

async useReversedAPIBasedSolution2 (e) {
Expand All @@ -171,7 +172,7 @@ export class ChatgptManagement extends plugin {
}
}

async useReversedBingSolution (e) {
async useBingSolution (e) {
let use = await redis.get('CHATGPT:USE')
if (use !== 'bing') {
await redis.set('CHATGPT:USE', 'bing')
Expand Down
Loading

0 comments on commit 873deda

Please sign in to comment.