mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 13:27:08 +00:00
feat: 修改配置文件格式避免频繁panic;降低api模式重试次数;优化帮助显示;支持必应新增的三种模式切换
This commit is contained in:
parent
a45ae14a5c
commit
873deda49d
10 changed files with 156 additions and 172 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
* 支持单人连续对话Conversation,群聊中支持加入其他人的对话
|
* 支持单人连续对话Conversation,群聊中支持加入其他人的对话
|
||||||
* API模式下,使用 gpt-3.5-turbo API,ChatGPT官网同款模型,仅需OpenAI Api Key,开箱即用。**注意收费**
|
* API模式下,使用 gpt-3.5-turbo API,ChatGPT官网同款模型,仅需OpenAI Api Key,开箱即用。**注意收费**
|
||||||
* 支持问答图片截图
|
* 支持问答图片截图
|
||||||
|
* 支持AI性格调教
|
||||||
* API3模式下,绕过Cloudflare防护直接访问ChatGPT的SSE API,与官方体验一致,且保留对话记录,在官网可查。免费。
|
* API3模式下,绕过Cloudflare防护直接访问ChatGPT的SSE API,与官方体验一致,且保留对话记录,在官网可查。免费。
|
||||||
* 提供基于浏览器的解决方案作为备选,API3不可用的情况下或担心账户安全的用户可以选择使用浏览器模式。
|
* 提供基于浏览器的解决方案作为备选,API3不可用的情况下或担心账户安全的用户可以选择使用浏览器模式。
|
||||||
* 支持新[必应](https://www.bing.com/new)(Beta)
|
* 支持新[必应](https://www.bing.com/new)(Beta)
|
||||||
|
|
@ -24,7 +25,7 @@ Node.js >= 18 / Node.js >= 14(with node-fetch)
|
||||||
> #### API模式和浏览器模式如何选择?
|
> #### API模式和浏览器模式如何选择?
|
||||||
>
|
>
|
||||||
> * API模式会调用OpenAI官方提供的gpt-3.5-turbo API,ChatGPT官网同款模型,只需要提供API Key。一般情况下,该种方式响应速度更快,可配置项多,且不会像chatGPT官网一样总出现不可用的现象,但注意API调用是收费的,新用户有18美元试用金可用于支付,价格为`$0.0020/ 1K tokens`。(问题和回答**加起来**算token)
|
> * 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的下位替代。
|
> * 浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站,使得获得和官方以及API2模式一模一样的回复质量,同时保证安全性。缺点是本方法对环境要求较高,需要提供桌面环境和一个可用的代理(能够访问ChatGPT的IP地址),且响应速度不如API,而且高峰期容易无法使用。一般作为API3的下位替代。
|
||||||
> * 必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing登录Cookie方可使用。
|
> * 必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing登录Cookie方可使用。
|
||||||
1. 进入 Yunzai根目录
|
1. 进入 Yunzai根目录
|
||||||
|
|
@ -45,9 +46,10 @@ pnpm i
|
||||||
> 2.20更新:必应被大削,变得蠢了,建议还是API/API3优先
|
> 2.20更新:必应被大削,变得蠢了,建议还是API/API3优先
|
||||||
|
|
||||||
3. 修改配置
|
3. 修改配置
|
||||||
|
**本插件配置项比较多,建议使用[锅巴面板](https://github.com/guoba-yunzai/Guoba-Plugin)修改**
|
||||||
|
|
||||||
复制`plugins/chatgpt-plugin/config/config.example.js`并将其改名为`config.js`
|
复制`plugins/chatgpt-plugin/config/config.example.json`并将其改名为`config.json`\
|
||||||
编辑`plugins/chatgpt-plugin/config/config.js`文件,根据其中的注释修改必要配置项
|
编辑`plugins/chatgpt-plugin/config/config.json`文件,修改必要配置项
|
||||||
|
|
||||||
4. 重启Yunzai-Bot
|
4. 重启Yunzai-Bot
|
||||||
|
|
||||||
|
|
|
||||||
138
apps/chat.js
138
apps/chat.js
|
|
@ -72,6 +72,10 @@ export class chatgpt extends plugin {
|
||||||
reg: '^#结束对话([sS]*)',
|
reg: '^#结束对话([sS]*)',
|
||||||
fnc: 'destroyConversations'
|
fnc: 'destroyConversations'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
reg: '^#结束全部对话$',
|
||||||
|
fnc: 'endAllConversations'
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// reg: '#chatgpt帮助',
|
// reg: '#chatgpt帮助',
|
||||||
// fnc: 'help'
|
// fnc: 'help'
|
||||||
|
|
@ -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) {
|
async deleteConversation (e) {
|
||||||
let ats = e.message.filter(m => m.type === 'at')
|
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') {
|
if (use !== 'api3') {
|
||||||
await this.reply('本功能当前仅支持API3模式', true)
|
await this.reply('本功能当前仅支持API3模式', true)
|
||||||
return false
|
return false
|
||||||
|
|
@ -193,7 +228,7 @@ export class chatgpt extends plugin {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
let deleteResponse = await deleteConversation(conversationId, newFetch)
|
let deleteResponse = await deleteConversation(conversationId, newFetch)
|
||||||
console.log(deleteResponse)
|
logger.mark(deleteResponse)
|
||||||
let deleted = 0
|
let deleted = 0
|
||||||
let qcs = await redis.keys('CHATGPT:QQ_CONVERSATION:*')
|
let qcs = await redis.keys('CHATGPT:QQ_CONVERSATION:*')
|
||||||
for (let i = 0; i < qcs.length; i++) {
|
for (let i = 0; i < qcs.length; i++) {
|
||||||
|
|
@ -215,7 +250,9 @@ export class chatgpt extends plugin {
|
||||||
let conversationId = await redis.get('CHATGPT:QQ_CONVERSATION:' + qq)
|
let conversationId = await redis.get('CHATGPT:QQ_CONVERSATION:' + qq)
|
||||||
if (conversationId) {
|
if (conversationId) {
|
||||||
let deleteResponse = await deleteConversation(conversationId)
|
let deleteResponse = await deleteConversation(conversationId)
|
||||||
console.log(deleteResponse)
|
if (Config.debug) {
|
||||||
|
logger.mark(deleteResponse)
|
||||||
|
}
|
||||||
let deleted = 0
|
let deleted = 0
|
||||||
let qcs = await redis.keys('CHATGPT:QQ_CONVERSATION:*')
|
let qcs = await redis.keys('CHATGPT:QQ_CONVERSATION:*')
|
||||||
for (let i = 0; i < qcs.length; i++) {
|
for (let i = 0; i < qcs.length; i++) {
|
||||||
|
|
@ -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) {
|
async switch2Picture (e) {
|
||||||
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||||
if (!userSetting) {
|
if (!userSetting) {
|
||||||
|
|
@ -331,15 +358,8 @@ export class chatgpt extends plugin {
|
||||||
await this.reply('主人不让我回答你这种问题,真是抱歉了呢', true)
|
await this.reply('主人不让我回答你这种问题,真是抱歉了呢', true)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// if (prompt.indexOf('<script>') != -1)
|
const use = await redis.get('CHATGPT:USE') || 'api'
|
||||||
// {
|
if (use === 'api3') {
|
||||||
// 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') {
|
|
||||||
let randomId = uuid()
|
let randomId = uuid()
|
||||||
// 队列队尾插入,开始排队
|
// 队列队尾插入,开始排队
|
||||||
await redis.rPush('CHATGPT:CHAT_QUEUE', [randomId])
|
await redis.rPush('CHATGPT:CHAT_QUEUE', [randomId])
|
||||||
|
|
@ -352,11 +372,11 @@ export class chatgpt extends plugin {
|
||||||
await this.reply('我正在思考如何回复你,请稍等', true, { recallMsg: 8 })
|
await this.reply('我正在思考如何回复你,请稍等', true, { recallMsg: 8 })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let length = await redis.lLen('CHATGPT:CHAT_QUEUE') - 1
|
||||||
if (confirmOn) {
|
if (confirmOn) {
|
||||||
let length = await redis.lLen('CHATGPT:CHAT_QUEUE') - 1
|
|
||||||
await this.reply(`我正在思考如何回复你,请稍等,当前队列前方还有${length}个问题`, true, { recallMsg: 8 })
|
await this.reply(`我正在思考如何回复你,请稍等,当前队列前方还有${length}个问题`, true, { recallMsg: 8 })
|
||||||
logger.info(`chatgpt队列前方还有${length}个问题。管理员可通过#清空队列来强制清除所有等待的问题。`)
|
|
||||||
}
|
}
|
||||||
|
logger.info(`chatgpt队列前方还有${length}个问题。管理员可通过#清空队列来强制清除所有等待的问题。`)
|
||||||
// 开始排队
|
// 开始排队
|
||||||
while (true) {
|
while (true) {
|
||||||
if (await redis.lIndex('CHATGPT:CHAT_QUEUE', 0) === randomId) {
|
if (await redis.lIndex('CHATGPT:CHAT_QUEUE', 0) === randomId) {
|
||||||
|
|
@ -573,48 +593,6 @@ export class chatgpt extends plugin {
|
||||||
case 'browser': {
|
case 'browser': {
|
||||||
return await this.chatgptBrowserBased(prompt, conversation)
|
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': {
|
case 'bing': {
|
||||||
let bingToken = await redis.get('CHATGPT:BING_TOKEN')
|
let bingToken = await redis.get('CHATGPT:BING_TOKEN')
|
||||||
if (!bingToken) {
|
if (!bingToken) {
|
||||||
|
|
@ -627,12 +605,15 @@ export class chatgpt extends plugin {
|
||||||
const bingAIClient = new BingAIClient({
|
const bingAIClient = new BingAIClient({
|
||||||
userToken: bingToken, // "_U" cookie from bing.com
|
userToken: bingToken, // "_U" cookie from bing.com
|
||||||
cookie,
|
cookie,
|
||||||
debug: Config.debug
|
debug: Config.debug,
|
||||||
|
proxy: Config.proxy
|
||||||
})
|
})
|
||||||
let response
|
let response
|
||||||
let reply = ''
|
let reply = ''
|
||||||
try {
|
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
|
reply += token
|
||||||
})
|
})
|
||||||
if (response.details.adaptiveCards?.[0]?.body?.[0]?.text?.trim()) {
|
if (response.details.adaptiveCards?.[0]?.body?.[0]?.text?.trim()) {
|
||||||
|
|
@ -714,7 +695,7 @@ export class chatgpt extends plugin {
|
||||||
if (conversation) {
|
if (conversation) {
|
||||||
option = Object.assign(option, 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -756,15 +737,15 @@ export class chatgpt extends plugin {
|
||||||
|
|
||||||
async joinConversation (e) {
|
async joinConversation (e) {
|
||||||
let ats = e.message.filter(m => m.type === 'at')
|
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') {
|
// if (use !== 'api3') {
|
||||||
await this.reply('本功能当前仅支持API3模式', true)
|
// await this.reply('本功能当前仅支持API3模式', true)
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
if (ats.length === 0) {
|
if (ats.length === 0) {
|
||||||
await this.reply('指令错误,使用本指令时请同时@某人', true)
|
await this.reply('指令错误,使用本指令时请同时@某人', true)
|
||||||
return false
|
return false
|
||||||
} else {
|
} else if (use === 'api3') {
|
||||||
let at = ats[0]
|
let at = ats[0]
|
||||||
let qq = at.qq
|
let qq = at.qq
|
||||||
let atUser = _.trimStart(at.text, '@')
|
let atUser = _.trimStart(at.text, '@')
|
||||||
|
|
@ -775,6 +756,13 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
await redis.set(`CHATGPT:QQ_CONVERSATION:${e.sender.user_id}`, conversationId)
|
await redis.set(`CHATGPT:QQ_CONVERSATION:${e.sender.user_id}`, conversationId)
|
||||||
await this.reply(`加入${atUser}的对话成功,当前对话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}的对话成功`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,11 @@ let helpData = [
|
||||||
title: '#结束对话',
|
title: '#结束对话',
|
||||||
desc: '结束自己当前对话,下次开启对话机器人将遗忘掉本次对话内容。'
|
desc: '结束自己当前对话,下次开启对话机器人将遗忘掉本次对话内容。'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'destroy',
|
||||||
|
title: '#结束全部对话',
|
||||||
|
desc: '结束正在与本机器人进行对话的全部用户的对话。'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: 'destroy-other',
|
icon: 'destroy-other',
|
||||||
title: '#结束对话 @某人',
|
title: '#结束对话 @某人',
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export class ChatgptManagement extends plugin {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reg: '^#chatgpt切换(必应|Bing)$',
|
reg: '^#chatgpt切换(必应|Bing)$',
|
||||||
fnc: 'useReversedBingSolution',
|
fnc: 'useBingSolution',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -157,8 +157,9 @@ export class ChatgptManagement extends plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async useReversedAPIBasedSolution (e) {
|
async useReversedAPIBasedSolution (e) {
|
||||||
await redis.set('CHATGPT:USE', 'apiReverse')
|
await this.reply('API2已废弃,处于不可用状态,不会为你切换')
|
||||||
await this.reply('【暂时不可用,请关注仓库更新和群公告】已切换到基于第三方Reversed CompletionAPI的解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
|
// await redis.set('CHATGPT:USE', 'apiReverse')
|
||||||
|
// await this.reply('【暂时不可用,请关注仓库更新和群公告】已切换到基于第三方Reversed CompletionAPI的解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
|
||||||
}
|
}
|
||||||
|
|
||||||
async useReversedAPIBasedSolution2 (e) {
|
async useReversedAPIBasedSolution2 (e) {
|
||||||
|
|
@ -171,7 +172,7 @@ export class ChatgptManagement extends plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async useReversedBingSolution (e) {
|
async useBingSolution (e) {
|
||||||
let use = await redis.get('CHATGPT:USE')
|
let use = await redis.get('CHATGPT:USE')
|
||||||
if (use !== 'bing') {
|
if (use !== 'bing') {
|
||||||
await redis.set('CHATGPT:USE', 'bing')
|
await redis.set('CHATGPT:USE', 'bing')
|
||||||
|
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
// 将当前文件复制为config.js使得配配置生效
|
|
||||||
// 例如http://127.0.0.1:7890
|
|
||||||
const PROXY = ''
|
|
||||||
const API_KEY = ''
|
|
||||||
|
|
||||||
export default {
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// 通用配置 *
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// 如果回答包括屏蔽词,就不返回。
|
|
||||||
// blockWords: ['屏蔽词1', '屏蔽词b'],
|
|
||||||
// 问题中如果触发屏蔽词,也会拒绝回答
|
|
||||||
// promptBlockWords: ['屏蔽词1', '屏蔽词b'],
|
|
||||||
// imgOcr: true,
|
|
||||||
// 改为true后,全局默认以图片形式回复,并自动发出Continue命令补全回答。长回复可能会有bug。
|
|
||||||
// defaultUsePicture: false,
|
|
||||||
// 如果true,字数大于阈值(autoUsePictureThreshold)会自动用图片发送,即使是文本模式。
|
|
||||||
// autoUsePicture: true,
|
|
||||||
// 仅当autoUsePicture为true时生效,字数大于该阈值会自动用图片发送,即使是文本模式。
|
|
||||||
// autoUsePictureThreshold: 1200,
|
|
||||||
// 每个人发起的对话保留时长。超过这个时长没有进行对话,再进行对话将开启新的对话。单位:秒
|
|
||||||
// conversationPreserveTime: 0,
|
|
||||||
// 触发方式 可选值:at 或 prefix 。at模式下只有at机器人才会回复。prefix模式下不需要at,但需要添加前缀#chat
|
|
||||||
// toggleMode: 'at',
|
|
||||||
// 是否在回复图片时引用原始消息
|
|
||||||
// quoteReply: true,
|
|
||||||
// 是否在图片模式中启用二维码。该对话内容将被发送至第三方服务器以进行渲染展示。改为false关闭该功能
|
|
||||||
// showQRCode: true,
|
|
||||||
// 图片内容渲染服务器API地址
|
|
||||||
// cacheUrl: 'https://content.alcedogroup.com',
|
|
||||||
// 图片内容渲染服务器开启预制访问代码,当渲染服务器访问较慢时可以开启,但无法保证远程渲染是否成功
|
|
||||||
// cacheEntry: false,
|
|
||||||
// 绘图指令的CD时间,主人不受限制
|
|
||||||
// drawCD: 30,
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// 以下为API方式(默认)的配置 *
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
apiKey: API_KEY,
|
|
||||||
// 如果有openai api的加速反代可以写
|
|
||||||
// openAiBaseUrl: null,
|
|
||||||
// 模型名称,选填。如无特殊需求保持默认即可,会使用chatgpt-api库提供的当前可用的最适合的默认值。保底可用的是 text-davinci-003。当发现新的可用的chatGPT模型会更新这里的值
|
|
||||||
// 20230211: text-chat-davinci-002-sh-alpha-aoruigiofdj83 中午存活了几分钟
|
|
||||||
// model: '',
|
|
||||||
// temperature: 0.8,
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// 以下为API3方式的配置 *
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// from https://github.com/acheong08/ChatGPT
|
|
||||||
// 或者: https://gpt.pawan.krd/backend-api/conversation
|
|
||||||
// api: 'https://chatgpt.duti.tech/api/conversation',
|
|
||||||
// 或者 https://gpt.pawan.krd/backend-api
|
|
||||||
// apiBaseUrl: 'https://chatgpt.duti.tech/api',
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// 以下为API/API2方式公用的配置 *
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// 给模型的前言promt。选填。默认完整值:`You are ${this._assistantLabel}, a large language model trained by OpenAI. You answer as concisely as possible for each response (e.g. don’t be verbose). It is very important that you answer as concisely as possible, so please remember this. If you are generating a list, do not have too many items. Keep the number of items short. Current date: ${currentDate}\n\n
|
|
||||||
// 此项配置会覆盖掉中间部分。保持为空将使用网友从对话中推测出的指令。
|
|
||||||
// 你可以在这里写入你希望AI回答的风格,比如希望优先回答中文,回答长一点等
|
|
||||||
// promptPrefixOverride: 'Your answer shouldn\'t be too verbose. If you are generating a list, do not have too many items. Keep the number of items short. Prefer to answer in Chinese.',
|
|
||||||
// AI认为的自己的名字,当你问他你是谁是他会回答这里的名字。
|
|
||||||
// assistantLabel: 'ChatGPT',
|
|
||||||
// 是否开启AI正在思考中的提示信息
|
|
||||||
// thinkingTips: true,
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// 以下为浏览器方式的配置 *
|
|
||||||
// ***********************************************************************************************************************************
|
|
||||||
// username: '',
|
|
||||||
// password: '',
|
|
||||||
// UA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
|
|
||||||
// 服务器无interface的话只能用true,但是可能遇到验证码就一定要配置下面的2captchaToken了
|
|
||||||
// true时使用无头模式,无界面的服务器可以为true,但遇到验证码时可能无法使用。(实测很容易卡住,几乎不可用)
|
|
||||||
// headless: false,
|
|
||||||
// 为空使用默认puppeteer的chromium,也可以传递自己本机安装的Chrome可执行文件地址,提高通过率。windows可以是‘C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe’,linux通过which查找路径
|
|
||||||
// chromePath: '',
|
|
||||||
// 可注册2captcha实现跳过验证码,收费服务但很便宜。否则可能会遇到验证码而卡住。
|
|
||||||
// '2captchaToken': '',
|
|
||||||
// http或socks5代理
|
|
||||||
proxy: PROXY,
|
|
||||||
// debug: true,
|
|
||||||
// 各个地方的默认超时时间
|
|
||||||
// defaultTimeoutMs: 120000,
|
|
||||||
// 浏览器默认超时,浏览器可能需要更高的超时时间
|
|
||||||
// chromeTimeoutMS: 120000
|
|
||||||
}
|
|
||||||
21
config/config.example.json
Normal file
21
config/config.example.json
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"apiKey": "",
|
||||||
|
"proxy": "",
|
||||||
|
"openAiBaseUrl": "https://api.openai.com",
|
||||||
|
"api": "https://chatgpt.duti.tech/api/conversation",
|
||||||
|
"apiBaseUrl": "https://chatgpt.duti.tech/api",
|
||||||
|
"promptPrefixOverride": "Your answer shouldn't be too verbose. If you are generating a list, do not have too many items. Keep the number of items short. Prefer to answer in Chinese.",
|
||||||
|
"debug": false,
|
||||||
|
"blockWords": ["屏蔽词1", "屏蔽词b"],
|
||||||
|
"promptBlockWords": ["屏蔽词1", "屏蔽词b"],
|
||||||
|
"imgOcr": true,
|
||||||
|
"defaultUsePicture": false,
|
||||||
|
"autoUsePicture": true,
|
||||||
|
"autoUsePictureThreshold": 1200,
|
||||||
|
"toggleMode": "at",
|
||||||
|
"quoteReply": true,
|
||||||
|
"showQRCode": true,
|
||||||
|
"cacheUrl": "https://content.alcedogroup.com",
|
||||||
|
"cacheEntry": false,
|
||||||
|
"drawCD": 30
|
||||||
|
}
|
||||||
|
|
@ -262,6 +262,19 @@ export function supportGuoba () {
|
||||||
label: '验证码平台Token',
|
label: '验证码平台Token',
|
||||||
bottomHelpMessage: '可注册2captcha实现跳过验证码,收费服务但很便宜。否则可能会遇到验证码而卡住。',
|
bottomHelpMessage: '可注册2captcha实现跳过验证码,收费服务但很便宜。否则可能会遇到验证码而卡住。',
|
||||||
component: 'InputPassword'
|
component: 'InputPassword'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'toneStyle',
|
||||||
|
label: 'Bing模式',
|
||||||
|
bottomHelpMessage: '微软必应官方的三种应答风格。默认为均衡',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: [
|
||||||
|
{ label: '均衡', value: 'balanced' },
|
||||||
|
{ label: '创意', value: 'creative' },
|
||||||
|
{ label: '精确', value: 'precise' }
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// 获取配置数据方法(用于前端填充显示数据)
|
// 获取配置数据方法(用于前端填充显示数据)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "ikechan8370",
|
"author": "ikechan8370",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@waylaidwanderer/chatgpt-api": "^1.23.0",
|
"@waylaidwanderer/chatgpt-api": "^1.24.0",
|
||||||
"chatgpt": "^5.0.5",
|
"chatgpt": "^5.0.5",
|
||||||
"delay": "^5.0.0",
|
"delay": "^5.0.0",
|
||||||
"keyv-file": "^0.2.0",
|
"keyv-file": "^0.2.0",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ body {
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
width: 630px;
|
width: 930px;
|
||||||
padding: 20px 15px 10px 15px;
|
padding: 20px 15px 10px 15px;
|
||||||
background-color: #f5f6fb;
|
background-color: #f5f6fb;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
|
import { execSync } from 'child_process'
|
||||||
|
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
blockWords: ['屏蔽词1', '屏蔽词b'],
|
blockWords: ['屏蔽词1', '屏蔽词b'],
|
||||||
promptBlockWords: ['屏蔽词1', '屏蔽词b'],
|
promptBlockWords: ['屏蔽词1', '屏蔽词b'],
|
||||||
|
|
@ -34,19 +36,55 @@ const defaultConfig = {
|
||||||
debug: true,
|
debug: true,
|
||||||
defaultTimeoutMs: 120000,
|
defaultTimeoutMs: 120000,
|
||||||
chromeTimeoutMS: 120000,
|
chromeTimeoutMS: 120000,
|
||||||
version: '2.0.10'
|
// version: 'v2.0.11',
|
||||||
|
toneStyle: 'balanced' // or creative, precise
|
||||||
}
|
}
|
||||||
const _path = process.cwd()
|
const _path = process.cwd()
|
||||||
let config = {}
|
let config = {}
|
||||||
if (fs.existsSync(`${_path}/plugins/chatgpt-plugin/config/config.js`)) {
|
if (fs.existsSync(`${_path}/plugins/chatgpt-plugin/config/config.json`)) {
|
||||||
|
const fullPath = fs.realpathSync(`${_path}/plugins/chatgpt-plugin/config/config.json`)
|
||||||
|
const data = fs.readFileSync(fullPath)
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
config = JSON.parse(data)
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('chatgpt插件读取配置文件出错,请检查config/config.json格式,将忽略用户配置转为使用默认配置', e)
|
||||||
|
logger.warn('chatgpt插件即将使用默认配置')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fs.existsSync(`${_path}/plugins/chatgpt-plugin/config/config.js`)) {
|
||||||
|
// 旧版本的config.js,读取其内容,生成config.json,然后删掉config.js
|
||||||
const fullPath = fs.realpathSync(`${_path}/plugins/chatgpt-plugin/config/config.js`)
|
const fullPath = fs.realpathSync(`${_path}/plugins/chatgpt-plugin/config/config.js`)
|
||||||
config = (await import(`file://${fullPath}`)).default
|
config = (await import(`file://${fullPath}`)).default
|
||||||
|
try {
|
||||||
|
logger.warn('[ChatGPT-Plugin]发现旧版本config.js文件,正在读取其内容并转换为新版本config.json文件')
|
||||||
|
// 读取其内容,生成config.json
|
||||||
|
fs.writeFileSync(`${_path}/plugins/chatgpt-plugin/config/config.json`, JSON.stringify(config, null, 2))
|
||||||
|
// 删掉config.js
|
||||||
|
fs.unlinkSync(`${_path}/plugins/chatgpt-plugin/config/config.js`)
|
||||||
|
logger.info('[ChatGPT-Plugin]配置文件转换处理完成')
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('[ChatGPT-Plugin]转换旧版配置文件失败,建议手动清理旧版config.js文件,并转为使用新版config.json格式', err)
|
||||||
|
}
|
||||||
} else if (fs.existsSync(`${_path}/plugins/chatgpt-plugin/config/index.js`)) {
|
} else if (fs.existsSync(`${_path}/plugins/chatgpt-plugin/config/index.js`)) {
|
||||||
// 兼容旧版本
|
// 兼容旧版本
|
||||||
const fullPath = fs.realpathSync(`${_path}/plugins/chatgpt-plugin/config/index.js`)
|
const fullPath = fs.realpathSync(`${_path}/plugins/chatgpt-plugin/config/index.js`)
|
||||||
config = (await import(`file://${fullPath}`)).Config
|
config = (await import(`file://${fullPath}`)).Config
|
||||||
|
try {
|
||||||
|
logger.warn('[ChatGPT-Plugin]发现旧版本config.js文件,正在读取其内容并转换为新版本config.json文件')
|
||||||
|
// 读取其内容,生成config.json
|
||||||
|
fs.writeFileSync(`${_path}/plugins/chatgpt-plugin/config/config.json`, JSON.stringify(config, null, 2))
|
||||||
|
// index.js
|
||||||
|
fs.unlinkSync(`${_path}/plugins/chatgpt-plugin/config/index.js`)
|
||||||
|
logger.info('[ChatGPT-Plugin]配置文件转换处理完成')
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('[ChatGPT-Plugin]转换旧版配置文件失败,建议手动清理旧版index.js文件,并转为使用新版config.json格式', err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
config = Object.assign({}, defaultConfig, config)
|
config = Object.assign({}, defaultConfig, config)
|
||||||
|
const latestTag = execSync('git describe --tags --abbrev=0').toString().trim()
|
||||||
|
config.version = latestTag
|
||||||
|
|
||||||
export const Config = new Proxy(config, {
|
export const Config = new Proxy(config, {
|
||||||
set (target, property, value) {
|
set (target, property, value) {
|
||||||
target[property] = value
|
target[property] = value
|
||||||
|
|
@ -56,9 +94,9 @@ export const Config = new Proxy(config, {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(`${_path}/plugins/chatgpt-plugin/config/config.js`, `export default ${JSON.stringify(change, '', '\t')}`, { flag: 'w' })
|
fs.writeFileSync(`${_path}/plugins/chatgpt-plugin/config/config.json`, JSON.stringify(change, null, 2), { flag: 'w' })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
logger.error(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue