mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 21:37:11 +00:00
feat: add support for bing(beta and WIP)
This commit is contained in:
parent
83c058ab85
commit
3ff591d205
5 changed files with 91 additions and 19 deletions
|
|
@ -5,9 +5,11 @@
|
||||||
* 支持问答图片截图
|
* 支持问答图片截图
|
||||||
* 仅需OpenAI Api Key,开箱即用
|
* 仅需OpenAI Api Key,开箱即用
|
||||||
* 提供基于浏览器的解决方案作为备选,有条件且希望得到更好回答质量可以选择使用浏览器模式。
|
* 提供基于浏览器的解决方案作为备选,有条件且希望得到更好回答质量可以选择使用浏览器模式。
|
||||||
|
* 支持新Bing(Beta)
|
||||||
|
|
||||||
## 版本要求
|
## 版本要求
|
||||||
Node.js >= 18 / Node.js >= 14(with node-fetch)
|
Node.js >= 18 / Node.js >= 14(with node-fetch)
|
||||||
|
小白尽可能使用18版本以上的nodejs
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
首先判断自己需要使用哪种模式,本插件支持官方API、第三方API和浏览器两种模式。也可以选择**我全都要**,通过qq发送命令`#chatgpt切换浏览器/API/API2`实时切换。对于轻量用户可以先使用API模式,有较高要求再转为使用其他模式。
|
首先判断自己需要使用哪种模式,本插件支持官方API、第三方API和浏览器两种模式。也可以选择**我全都要**,通过qq发送命令`#chatgpt切换浏览器/API/API2`实时切换。对于轻量用户可以先使用API模式,有较高要求再转为使用其他模式。
|
||||||
|
|
@ -15,9 +17,9 @@ Node.js >= 18 / Node.js >= 14(with node-fetch)
|
||||||
> API模式和浏览器模式如何选择?
|
> API模式和浏览器模式如何选择?
|
||||||
>
|
>
|
||||||
> * API模式会调用OpenAI官方提供的GPT-3 LLM API,只需要提供API Key。一般情况下,该种方式响应速度更快,可配置项多,且不会像chatGPT官网一样总出现不可用的现象,但其聊天效果明显较官网差。但注意GPT-3的API调用是收费的,新用户有18美元试用金可用于支付,价格为`$0.0200/ 1K tokens`.(问题和回答加起来算token)
|
> * API模式会调用OpenAI官方提供的GPT-3 LLM API,只需要提供API Key。一般情况下,该种方式响应速度更快,可配置项多,且不会像chatGPT官网一样总出现不可用的现象,但其聊天效果明显较官网差。但注意GPT-3的API调用是收费的,新用户有18美元试用金可用于支付,价格为`$0.0200/ 1K tokens`.(问题和回答加起来算token)
|
||||||
> * API2模式会调用第三方提供的基于OpenAI text-davinci-002-render模型(官网同款)的API,需要提供ChatGPT的Token。效果比单纯的GPT-3 API好很多,但同时将Token提供给了第三方API,其中风险自行承担。
|
> * API2模式会调用第三方提供的基于OpenAI text-davinci-002-render模型(官网同款)的API,需要提供ChatGPT的Token。效果比单纯的GPT-3 API好很多,但同时将Token提供给了第三方API,其中风险自行承担。#chatgpt设置token
|
||||||
> * 浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站,使得获得和官方以及API2模式一模一样的回复质量,同时保证安全性。缺点是本方法对环境要求较高,需要提供桌面环境和一个可用的代理(能够访问ChatGPT的IP地址),且响应速度不如API,而且高峰期容易无法使用。
|
> * 浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站,使得获得和官方以及API2模式一模一样的回复质量,同时保证安全性。缺点是本方法对环境要求较高,需要提供桌面环境和一个可用的代理(能够访问ChatGPT的IP地址),且响应速度不如API,而且高峰期容易无法使用。
|
||||||
|
> * 必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing 登录Cookie方可使用。#chatgpt设置必应token. ("_U" cookie from bing.com)
|
||||||
1. 进入 Yunzai根目录
|
1. 进入 Yunzai根目录
|
||||||
2. 检查 Node.js 版本
|
2. 检查 Node.js 版本
|
||||||
|
|
||||||
|
|
@ -74,7 +76,6 @@ git clone https://github.com/ikechan8370/chatgpt-plugin.git ./plugins/chatgpt-pl
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
* 更灵活的Conversation管理
|
* 更灵活的Conversation管理
|
||||||
* 支持Bing版本
|
|
||||||
* 版本号和归档
|
* 版本号和归档
|
||||||
* API2模式下自动获取/刷新Token
|
* API2模式下自动获取/刷新Token
|
||||||
|
|
||||||
|
|
|
||||||
47
apps/chat.js
47
apps/chat.js
|
|
@ -6,7 +6,7 @@ import mjAPI from 'mathjax-node'
|
||||||
import { uuid } from 'oicq/lib/common.js'
|
import { uuid } from 'oicq/lib/common.js'
|
||||||
import delay from 'delay'
|
import delay from 'delay'
|
||||||
import { ChatGPTAPI } from 'chatgpt'
|
import { ChatGPTAPI } from 'chatgpt'
|
||||||
import { ChatGPTClient } from '@waylaidwanderer/chatgpt-api'
|
import { ChatGPTClient, BingAIClient } from '@waylaidwanderer/chatgpt-api'
|
||||||
import { getMessageById, tryTimes, upsertMessage } from '../utils/common.js'
|
import { getMessageById, tryTimes, upsertMessage } from '../utils/common.js'
|
||||||
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
||||||
import { KeyvFile } from 'keyv-file'
|
import { KeyvFile } from 'keyv-file'
|
||||||
|
|
@ -247,15 +247,25 @@ export class chatgpt extends plugin {
|
||||||
previousConversation = JSON.parse(previousConversation)
|
previousConversation = JSON.parse(previousConversation)
|
||||||
conversation = {
|
conversation = {
|
||||||
conversationId: previousConversation.conversation.conversationId,
|
conversationId: previousConversation.conversation.conversationId,
|
||||||
parentMessageId: previousConversation.conversation.parentMessageId
|
parentMessageId: previousConversation.conversation.parentMessageId,
|
||||||
|
clientId: previousConversation.clientId,
|
||||||
|
invocationId: previousConversation.invocationId,
|
||||||
|
conversationSignature: previousConversation.conversationSignature
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const use = await redis.get('CHATGPT:USE')
|
||||||
try {
|
try {
|
||||||
let chatMessage = await this.sendMessage(prompt, conversation)
|
let chatMessage = await this.sendMessage(prompt, conversation, use)
|
||||||
previousConversation.conversation = {
|
previousConversation.conversation = {
|
||||||
conversationId: chatMessage.conversationId,
|
conversationId: chatMessage.conversationId
|
||||||
parentMessageId: chatMessage.id
|
}
|
||||||
|
if (use === 'bing') {
|
||||||
|
previousConversation.clientId = chatMessage.clientId
|
||||||
|
previousConversation.invocationId = chatMessage.invocationId
|
||||||
|
previousConversation.conversationSignature = chatMessage.conversationSignature
|
||||||
|
} else {
|
||||||
|
// 或许这样切换回来不会404?
|
||||||
|
previousConversation.conversation.parentMessageId = chatMessage.id
|
||||||
}
|
}
|
||||||
console.log(chatMessage)
|
console.log(chatMessage)
|
||||||
let response = chatMessage?.text
|
let response = chatMessage?.text
|
||||||
|
|
@ -284,7 +294,7 @@ export class chatgpt extends plugin {
|
||||||
// !response.trimEnd().endsWith('!') && !response.trimEnd().endsWith('!') && !response.trimEnd().endsWith(']') && !response.trimEnd().endsWith('】')
|
// !response.trimEnd().endsWith('!') && !response.trimEnd().endsWith('!') && !response.trimEnd().endsWith(']') && !response.trimEnd().endsWith('】')
|
||||||
// ) {
|
// ) {
|
||||||
await this.reply('内容有点多,我正在奋笔疾书,请再等一会', true, { recallMsg: 5 })
|
await this.reply('内容有点多,我正在奋笔疾书,请再等一会', true, { recallMsg: 5 })
|
||||||
let responseAppend = await this.sendMessage('Continue', conversation)
|
let responseAppend = await this.sendMessage('Continue', conversation, use)
|
||||||
previousConversation.conversation = {
|
previousConversation.conversation = {
|
||||||
conversationId: responseAppend.conversationId,
|
conversationId: responseAppend.conversationId,
|
||||||
parentMessageId: responseAppend.id
|
parentMessageId: responseAppend.id
|
||||||
|
|
@ -325,8 +335,8 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage (prompt, conversation = {}) {
|
async sendMessage (prompt, conversation = {}, use) {
|
||||||
const use = await redis.get('CHATGPT:USE')
|
|
||||||
// console.log(use)
|
// console.log(use)
|
||||||
if (use === 'browser') {
|
if (use === 'browser') {
|
||||||
return await this.chatgptBrowserBased(prompt, conversation)
|
return await this.chatgptBrowserBased(prompt, conversation)
|
||||||
|
|
@ -350,7 +360,7 @@ export class chatgpt extends plugin {
|
||||||
// (Optional) Set a custom name for ChatGPT
|
// (Optional) Set a custom name for ChatGPT
|
||||||
chatGptLabel: Config.assistantLabel,
|
chatGptLabel: Config.assistantLabel,
|
||||||
// (Optional) Set to true to enable `console.debug()` logging
|
// (Optional) Set to true to enable `console.debug()` logging
|
||||||
debug: false
|
debug: Config.debug
|
||||||
}
|
}
|
||||||
const cacheOptions = {
|
const cacheOptions = {
|
||||||
// Options for the Keyv cache, see https://www.npmjs.com/package/keyv
|
// Options for the Keyv cache, see https://www.npmjs.com/package/keyv
|
||||||
|
|
@ -371,6 +381,23 @@ export class chatgpt extends plugin {
|
||||||
id: response.messageId,
|
id: response.messageId,
|
||||||
parentMessageId: conversation?.parentMessageId
|
parentMessageId: conversation?.parentMessageId
|
||||||
}
|
}
|
||||||
|
} else if (use === 'bing') {
|
||||||
|
let bingToken = await redis.get('CHATGPT:BING_TOKEN')
|
||||||
|
if (!bingToken) {
|
||||||
|
throw new Error('未绑定Bing Cookie,请使用#chatgpt设置Bing Cookie命令绑定Bing Cookie')
|
||||||
|
}
|
||||||
|
const bingAIClient = new BingAIClient({
|
||||||
|
userToken: bingToken, // "_U" cookie from bing.com
|
||||||
|
debug: Config.debug
|
||||||
|
})
|
||||||
|
let response = await bingAIClient.sendMessage(prompt, conversation)
|
||||||
|
return {
|
||||||
|
text: response.response,
|
||||||
|
conversationId: response.conversationId,
|
||||||
|
clientId: response.clientId,
|
||||||
|
invocationId: response.invocationId,
|
||||||
|
conversationSignature: response.conversationSignature
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let completionParams = {}
|
let completionParams = {}
|
||||||
if (Config.model) {
|
if (Config.model) {
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,13 @@ let helpData = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'switch',
|
icon: 'switch',
|
||||||
title: '#chatgpt切换浏览器/API/API2',
|
title: '#chatgpt切换浏览器/API/API2/Bing',
|
||||||
desc: '切换使用的后端为浏览器或OpenAI API/第三方API'
|
desc: '切换使用的后端为浏览器或OpenAI API/第三方API/Bing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'help',
|
||||||
|
title: '#chatgpt设置(必应)token',
|
||||||
|
desc: '设置ChatGPT或bing的Token'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'help',
|
icon: 'help',
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,11 @@ export class ChatgptManagement extends plugin {
|
||||||
fnc: 'setAccessToken',
|
fnc: 'setAccessToken',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
reg: '#chatgpt设置必应token',
|
||||||
|
fnc: 'setBingAccessToken',
|
||||||
|
permission: 'master'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
reg: '^#chatgpt切换浏览器$',
|
reg: '^#chatgpt切换浏览器$',
|
||||||
fnc: 'useBrowserBasedSolution',
|
fnc: 'useBrowserBasedSolution',
|
||||||
|
|
@ -38,6 +43,11 @@ export class ChatgptManagement extends plugin {
|
||||||
fnc: 'useReversedAPIBasedSolution',
|
fnc: 'useReversedAPIBasedSolution',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
reg: '^#chatgpt切换(必应|Bing)$',
|
||||||
|
fnc: 'useReversedBingSolution',
|
||||||
|
permission: 'master'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
reg: '^#chatgpt模式帮助$',
|
reg: '^#chatgpt模式帮助$',
|
||||||
fnc: 'modeHelp'
|
fnc: 'modeHelp'
|
||||||
|
|
@ -68,9 +78,28 @@ export class ChatgptManagement extends plugin {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setBingAccessToken (e) {
|
||||||
|
this.setContext('saveBingToken')
|
||||||
|
await this.reply('请发送Bing Cookie Token.("_U" cookie from bing.com)', true)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveBingToken () {
|
||||||
|
if (!this.e.msg) return
|
||||||
|
let token = this.e.msg
|
||||||
|
// todo 未知bing token是什么样的,有号的可以加个校验在这
|
||||||
|
await redis.set('CHATGPT:BING_TOKEN', token)
|
||||||
|
await this.reply('Bing Token设置成功', true)
|
||||||
|
this.finish('saveBingToken')
|
||||||
|
}
|
||||||
|
|
||||||
async saveToken () {
|
async saveToken () {
|
||||||
if (!this.e.msg) return
|
if (!this.e.msg) return
|
||||||
let token = this.e.msg
|
let token = this.e.msg
|
||||||
|
if (!token.startsWith('ey') || token.length < 20) {
|
||||||
|
await this.reply('ChatGPT AccessToken格式错误', true)
|
||||||
|
this.finish('saveToken')
|
||||||
|
}
|
||||||
await redis.set('CHATGPT:TOKEN', token)
|
await redis.set('CHATGPT:TOKEN', token)
|
||||||
await this.reply('ChatGPT AccessToken设置成功', true)
|
await this.reply('ChatGPT AccessToken设置成功', true)
|
||||||
this.finish('saveToken')
|
this.finish('saveToken')
|
||||||
|
|
@ -91,12 +120,18 @@ export class ChatgptManagement extends plugin {
|
||||||
await this.reply('已切换到基于第三方Reversed API的解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
|
await this.reply('已切换到基于第三方Reversed API的解决方案,如果已经对话过建议执行`#结束对话`避免引起404错误')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async useReversedBingSolution (e) {
|
||||||
|
await redis.set('CHATGPT:USE', 'bing')
|
||||||
|
await this.reply('已切换到基于第三方Reversed API的解决方案,如果已经对话过务必执行`#结束对话`避免引起404错误')
|
||||||
|
}
|
||||||
|
|
||||||
async modeHelp () {
|
async modeHelp () {
|
||||||
let mode = await redis.get('CHATGPT:USE')
|
let mode = await redis.get('CHATGPT:USE')
|
||||||
const modeMap = {
|
const modeMap = {
|
||||||
browser: '浏览器',
|
browser: '浏览器',
|
||||||
apiReverse: 'API2',
|
apiReverse: 'API2',
|
||||||
api: 'API'
|
api: 'API',
|
||||||
|
bing: '必应'
|
||||||
}
|
}
|
||||||
let modeText = modeMap[mode || 'api']
|
let modeText = modeMap[mode || 'api']
|
||||||
let message = ` API模式和浏览器模式如何选择?
|
let message = ` API模式和浏览器模式如何选择?
|
||||||
|
|
@ -104,11 +139,14 @@ export class ChatgptManagement extends plugin {
|
||||||
// eslint-disable-next-line no-irregular-whitespace
|
// eslint-disable-next-line no-irregular-whitespace
|
||||||
API模式会调用OpenAI官方提供的GPT-3 LLM API,只需要提供API Key。一般情况下,该种方式响应速度更快,可配置项多,且不会像chatGPT官网一样总出现不可用的现象,但其聊天效果明显较官网差。但注意GPT-3的API调用是收费的,新用户有18美元试用金可用于支付,价格为$0.0200/ 1K tokens.(问题和回答加起来算token)
|
API模式会调用OpenAI官方提供的GPT-3 LLM API,只需要提供API Key。一般情况下,该种方式响应速度更快,可配置项多,且不会像chatGPT官网一样总出现不可用的现象,但其聊天效果明显较官网差。但注意GPT-3的API调用是收费的,新用户有18美元试用金可用于支付,价格为$0.0200/ 1K tokens.(问题和回答加起来算token)
|
||||||
|
|
||||||
API2模式会调用第三方提供的基于OpenAI text-davinci-002-render模型(官网同款)的API,需要提供ChatGPT的Token。效果比单纯的GPT-3 API好很多,但同时将Token提供给了第三方API,其中风险自行承担。
|
API2模式会调用第三方提供的基于OpenAI text-davinci-002-render模型(官网同款)的API,需要提供ChatGPT的Token。效果比单纯的GPT-3 API好很多,但同时将Token提供给了第三方API,其中风险自行承担。#chatgpt设置token
|
||||||
|
|
||||||
浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站,使得获得和官方以及API2模式一模一样的回复质量,同时保证安全性。缺点是本方法对环境要求较高,需要提供桌面环境和一个可用的代理(能够访问ChatGPT的IP地址),且响应速度不如API,而且高峰期容易无法使用。
|
浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站,使得获得和官方以及API2模式一模一样的回复质量,同时保证安全性。缺点是本方法对环境要求较高,需要提供桌面环境和一个可用的代理(能够访问ChatGPT的IP地址),且响应速度不如API,而且高峰期容易无法使用。
|
||||||
|
|
||||||
您可以使用‘#chatgpt切换浏览器/API/API2’来切换到指定模式。
|
必应(Bing)将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing 登录Cookie方可使用。#chatgpt设置必应token
|
||||||
|
|
||||||
|
您可以使用‘#chatgpt切换浏览器/API/API2/Bing’来切换到指定模式。
|
||||||
|
|
||||||
当前为${modeText}模式。
|
当前为${modeText}模式。
|
||||||
`
|
`
|
||||||
await this.reply(message)
|
await this.reply(message)
|
||||||
|
|
|
||||||
|
|
@ -49,5 +49,6 @@ export const Config = {
|
||||||
// 可注册2captcha实现跳过验证码,收费服务但很便宜。否则可能会遇到验证码而卡住。
|
// 可注册2captcha实现跳过验证码,收费服务但很便宜。否则可能会遇到验证码而卡住。
|
||||||
'2captchaToken': '',
|
'2captchaToken': '',
|
||||||
// http或socks5代理
|
// http或socks5代理
|
||||||
proxy: PROXY
|
proxy: PROXY,
|
||||||
|
debug: false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue