From fa1b1877d0638ce5d792152de6ea890366d87939 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Wed, 8 Mar 2023 10:54:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0API=20key=E5=92=8C?= =?UTF-8?q?=E8=AE=BE=E5=AE=9A=E7=9A=84=E9=85=8D=E7=BD=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 9 +++--- apps/management.js | 72 +++++++++++++++++++++++++++++++++++++++++ utils/SydneyAIClient.js | 12 +++++-- utils/common.js | 17 ++++++++++ utils/config.js | 8 +++-- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index 3beb8b1..5270239 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -1,6 +1,6 @@ import plugin from '../../../lib/plugins/plugin.js' import _ from 'lodash' -import { Config } from '../utils/config.js' +import {Config, defaultOpenAIAPI, defaultOpenAIReverseProxy} from '../utils/config.js' import { v4 as uuid } from 'uuid' import delay from 'delay' import { ChatGPTAPI } from 'chatgpt' @@ -13,7 +13,7 @@ import { tryTimes, upsertMessage, randomString, - getDefaultUserSetting + getDefaultUserSetting, isCN } from '../utils/common.js' import { ChatGPTPuppeteer } from '../utils/browser.js' import { KeyvFile } from 'keyv-file' @@ -856,8 +856,9 @@ export class chatgpt extends plugin { assistantLabel: Config.assistantLabel, fetch: newFetch } - if (opts.apiBaseUrl !== 'https://api.openai.com' && Config.proxy && !Config.openAiForceUseReverse) { - // 如果配了proxy,而且有反代,但是没开启强制反代,将baseurl删掉 + let openAIAccessible = (Config.proxy || !(await isCN())) // 配了代理或者服务器在国外,默认认为不需要反代 + if (opts.apiBaseUrl !== defaultOpenAIAPI && openAIAccessible && !Config.openAiForceUseReverse) { + // 如果配了proxy(或者不在国内),而且有反代,但是没开启强制反代,将baseurl删掉 delete opts.apiBaseUrl } this.chatGPTApi = new ChatGPTAPI(opts) diff --git a/apps/management.js b/apps/management.js index b885bbe..e4a2146 100644 --- a/apps/management.js +++ b/apps/management.js @@ -79,6 +79,21 @@ export class ChatgptManagement extends plugin { reg: '^#chatgpt查看闭嘴', fnc: 'listShutUp', permission: 'master' + }, + { + reg: '^#chatgpt设置(API|key)(Key|key)', + fnc: 'setAPIKey', + permission: 'master' + }, + { + reg: '^#chatgpt设置(API|api)设定', + fnc: 'setAPIPromptPrefix', + permission: 'master' + }, + { + reg: '^#chatgpt设置(Bing|必应|Sydney|悉尼|sydney|bing)设定', + fnc: 'setBingPromptPrefix', + permission: 'master' } ] }) @@ -419,4 +434,61 @@ export class ChatgptManagement extends plugin { await this.reply(list.map(item => item.groupId !== 'ALL' ? `群聊${item.groupId}: ${item.ttlFormat}` : `全局: ${item.ttlFormat}`).join('\n')) } } + + async setAPIKey (e) { + this.setContext('saveAPIKey') + await this.reply('请发送OpenAI API Key.', true) + return false + } + + async saveAPIKey () { + if (!this.e.msg) return + let token = this.e.msg + if (!token.startsWith('sk-')) { + await this.reply('OpenAI API Key格式错误', true) + this.finish('saveAPIKey') + return + } + // todo + Config.apiKey = token + await this.reply('OpenAI API Key设置成功', true) + this.finish('saveAPIKey') + } + + async setAPIPromptPrefix (e) { + this.setContext('saveAPIPromptPrefix') + await this.reply('请发送用于API模式的设定', true) + return false + } + + async saveAPIPromptPrefix (e) { + if (!this.e.msg) return + if (this.e.msg === '取消') { + await this.reply('已取消设置API设定', true) + this.finish('saveAPIPromptPrefix') + return + } + // todo + Config.promptPrefixOverride = this.e.msg + await this.reply('API模式的设定设置成功', true) + this.finish('saveAPIPromptPrefix') + } + + async setBingPromptPrefix (e) { + this.setContext('saveBingPromptPrefix') + await this.reply('请发送用于Bing Sydney模式的设定', true) + return false + } + + async saveBingPromptPrefix (e) { + if (!this.e.msg) return + if (this.e.msg === '取消') { + await this.reply('已取消设置Sydney设定', true) + this.finish('saveBingPromptPrefix') + return + } + Config.sydney = this.e.msg + await this.reply('Bing Sydney模式的设定设置成功', true) + this.finish('saveBingPromptPrefix') + } } diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index 371c0ea..d68193c 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -7,6 +7,7 @@ import crypto from 'crypto' import HttpsProxyAgent from 'https-proxy-agent' import { Config } from './config.js' +import {isCN} from "./common.js"; if (!globalThis.fetch) { globalThis.fetch = fetch @@ -58,9 +59,9 @@ export default class SydneyAIClient { ...opts, host: opts.host || Config.sydneyReverseProxy || 'https://www.bing.com' } - if (opts.proxy && !Config.sydneyForceUseReverse) { - this.opts.host = 'https://www.bing.com' - } + // if (opts.proxy && !Config.sydneyForceUseReverse) { + // this.opts.host = 'https://www.bing.com' + // } this.debug = opts.debug } @@ -102,6 +103,11 @@ export default class SydneyAIClient { if (this.opts.proxy) { fetchOptions.agent = proxy(Config.proxy) } + let accessible = !(await isCN()) || this.opts.proxy + if (accessible && !Config.sydneyForceUseReverse) { + // 本身能访问bing.com,那就不用反代啦,重置host + this.opts.host = 'https://www.bing.com' + } const response = await fetch(`${this.opts.host}/turing/conversation/create`, fetchOptions) let text = await response.text() try { diff --git a/utils/common.js b/utils/common.js index ab50b67..a8f8327 100644 --- a/utils/common.js +++ b/utils/common.js @@ -351,3 +351,20 @@ export function formatDuration (duration) { return result || '0秒钟' } + +/** + * 判断服务器所在地是否为中国 + * @returns {Promise} + */ +export async function isCN () { + if (await redis.get('CHATGPT:COUNTRY_CODE')) { + return await redis.get('CHATGPT:COUNTRY_CODE') === 'CN' + } else { + let response = await fetch('https://ipinfo.io/country') + let countryCode = await response.text() + await redis.set('CHATGPT:COUNTRY_CODE', countryCode, { EX: 3600 * 24 * 7 }) + if (countryCode !== 'CN') { + return false + } + } +} \ No newline at end of file diff --git a/utils/config.js b/utils/config.js index 8c31d85..3018b9e 100644 --- a/utils/config.js +++ b/utils/config.js @@ -2,6 +2,10 @@ import fs from 'fs' import lodash from 'lodash' export const defaultChatGPTAPI = 'https://pimon.d201.cn/backend-api/conversation' export const officialChatGPTAPI = 'https://apps.openai.com/api/conversation' +// Reverse proxy of https://api.openai.com +export const defaultOpenAIReverseProxy = 'https://mondstadt.d201.eu.org' +// blocked in China Mainland +export const defaultOpenAIAPI = 'https://api.openai.com' const defaultConfig = { blockWords: ['屏蔽词1', '屏蔽词b'], promptBlockWords: ['屏蔽词1', '屏蔽词b'], @@ -20,7 +24,7 @@ const defaultConfig = { cacheUrl: 'https://content.alcedogroup.com', cacheEntry: false, apiKey: '', - openAiBaseUrl: 'https://api.openai.com', + openAiBaseUrl: defaultOpenAIReverseProxy, openAiForceUseReverse: false, drawCD: 30, model: '', @@ -51,7 +55,7 @@ const defaultConfig = { noiseScaleW: 0.668, lengthScale: 1.2, initiativeChatGroups: [], - version: 'v2.1.0' + version: 'v2.1.1' } const _path = process.cwd() let config = {}