diff --git a/service/src/chatgpt/index.ts b/service/src/chatgpt/index.ts index a5ea473..7b20d23 100644 --- a/service/src/chatgpt/index.ts +++ b/service/src/chatgpt/index.ts @@ -6,6 +6,7 @@ import { SocksProxyAgent } from 'socks-proxy-agent' import { HttpsProxyAgent } from 'https-proxy-agent' import fetch from 'node-fetch' import { sendResponse } from '../utils' +import { isNotEmptyString } from '../utils/is' import type { ApiModel, ChatContext, ChatGPTUnofficialProxyAPIOptions, ModelConfig } from '../types' const ErrorCodeMessage: Record = { @@ -27,42 +28,21 @@ if (!process.env.OPENAI_API_KEY && !process.env.OPENAI_ACCESS_TOKEN) throw new Error('Missing OPENAI_API_KEY or OPENAI_ACCESS_TOKEN environment variable') let api: ChatGPTAPI | ChatGPTUnofficialProxyAPI -function setupProxy(options) { - if (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) { - const agent = new SocksProxyAgent({ - hostname: process.env.SOCKS_PROXY_HOST, - port: process.env.SOCKS_PROXY_PORT, - }) - options.fetch = (url, options) => { - return fetch(url, { agent, ...options }) - } - } - - const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.ALL_PROXY || process.env.all_proxy - if (httpsProxy) { - const agent = new HttpsProxyAgent(httpsProxy) - options.fetch = (url, options) => { - return fetch(url, { agent, ...options }) - } - } -} (async () => { // More Info: https://github.com/transitive-bullshit/chatgpt-api if (process.env.OPENAI_API_KEY) { const OPENAI_API_MODEL = process.env.OPENAI_API_MODEL - const model = (typeof OPENAI_API_MODEL === 'string' && OPENAI_API_MODEL.length > 0) - ? OPENAI_API_MODEL - : 'gpt-3.5-turbo' + const model = isNotEmptyString(OPENAI_API_MODEL) ? OPENAI_API_MODEL : 'gpt-3.5-turbo' const options: ChatGPTAPIOptions = { apiKey: process.env.OPENAI_API_KEY, completionParams: { model }, - debug: false, + debug: true, } - if (process.env.OPENAI_API_BASE_URL && process.env.OPENAI_API_BASE_URL.trim().length > 0) + if (isNotEmptyString(process.env.OPENAI_API_BASE_URL)) options.apiBaseUrl = process.env.OPENAI_API_BASE_URL setupProxy(options) @@ -73,14 +53,14 @@ function setupProxy(options) { else { const options: ChatGPTUnofficialProxyAPIOptions = { accessToken: process.env.OPENAI_ACCESS_TOKEN, - debug: false, + debug: true, } - setupProxy(options) - - if (process.env.API_REVERSE_PROXY) + if (isNotEmptyString(process.env.API_REVERSE_PROXY)) options.apiReverseProxyUrl = process.env.API_REVERSE_PROXY + setupProxy(options) + api = new ChatGPTUnofficialProxyAPI({ ...options }) apiModel = 'ChatGPTUnofficialProxyAPI' } @@ -91,9 +71,6 @@ async function chatReplyProcess( lastContext?: { conversationId?: string; parentMessageId?: string }, process?: (chat: ChatMessage) => void, ) { - // if (!message) - // return sendResponse({ type: 'Fail', message: 'Message is empty' }) - try { let options: SendMessageOptions = { timeoutMs } @@ -123,20 +100,39 @@ async function chatReplyProcess( } async function chatConfig() { - const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.ALL_PROXY || process.env.all_proxy + const reverseProxy = process.env.API_REVERSE_PROXY ?? '-' + const socksProxy = (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) ? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`) : '-' + const httpsProxy = (process.env.HTTPS_PROXY || process.env.ALL_PROXY) ?? '-' - return sendResponse({ + return sendResponse({ type: 'Success', - data: { - apiModel, - reverseProxy: process.env.API_REVERSE_PROXY, - timeoutMs, - socksProxy: (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) ? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`) : '-', - httpsProxy, - } as ModelConfig, + data: { apiModel, reverseProxy, timeoutMs, socksProxy, httpsProxy }, }) } +function setupProxy(options: ChatGPTAPIOptions | ChatGPTUnofficialProxyAPIOptions) { + if (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) { + const agent = new SocksProxyAgent({ + hostname: process.env.SOCKS_PROXY_HOST, + port: process.env.SOCKS_PROXY_PORT, + }) + options.fetch = (url, options) => { + return fetch(url, { agent, ...options }) + } + } + else { + if (process.env.HTTPS_PROXY || process.env.ALL_PROXY) { + const httpsProxy = process.env.HTTPS_PROXY || process.env.ALL_PROXY + if (httpsProxy) { + const agent = new HttpsProxyAgent(httpsProxy) + options.fetch = (url, options) => { + return fetch(url, { agent, ...options }) + } + } + } + } +} + export type { ChatContext, ChatMessage } export { chatReplyProcess, chatConfig } diff --git a/service/src/index.ts b/service/src/index.ts index 402deaa..a14b843 100644 --- a/service/src/index.ts +++ b/service/src/index.ts @@ -2,6 +2,7 @@ import express from 'express' import type { ChatContext, ChatMessage } from './chatgpt' import { chatConfig, chatReplyProcess } from './chatgpt' import { auth } from './middleware/auth' +import { isNotEmptyString } from './utils/is' const app = express() const router = express.Router() @@ -48,7 +49,7 @@ router.post('/config', async (req, res) => { router.post('/session', async (req, res) => { try { const AUTH_SECRET_KEY = process.env.AUTH_SECRET_KEY - const hasAuth = typeof AUTH_SECRET_KEY === 'string' && AUTH_SECRET_KEY.length > 0 + const hasAuth = isNotEmptyString(AUTH_SECRET_KEY) res.send({ status: 'Success', message: '', data: { auth: hasAuth } }) } catch (error) { diff --git a/service/src/middleware/auth.ts b/service/src/middleware/auth.ts index 50bf02a..8b04ced 100644 --- a/service/src/middleware/auth.ts +++ b/service/src/middleware/auth.ts @@ -1,6 +1,8 @@ +import { isNotEmptyString } from '../utils/is' + const auth = async (req, res, next) => { const AUTH_SECRET_KEY = process.env.AUTH_SECRET_KEY - if (typeof AUTH_SECRET_KEY === 'string' && AUTH_SECRET_KEY.length > 0) { + if (isNotEmptyString(AUTH_SECRET_KEY)) { try { const Authorization = req.header('Authorization') if (!Authorization || Authorization.replace('Bearer ', '').trim() !== AUTH_SECRET_KEY.trim()) diff --git a/service/src/utils/index.ts b/service/src/utils/index.ts index 1d83253..726f807 100644 --- a/service/src/utils/index.ts +++ b/service/src/utils/index.ts @@ -1,10 +1,10 @@ -interface SendResponseOptions { +interface SendResponseOptions { type: 'Success' | 'Fail' message?: string - data?: any + data?: T } -export function sendResponse(options: SendResponseOptions) { +export function sendResponse(options: SendResponseOptions) { if (options.type === 'Success') { return Promise.resolve({ message: options.message ?? null, diff --git a/service/src/utils/is.ts b/service/src/utils/is.ts new file mode 100644 index 0000000..c1253f2 --- /dev/null +++ b/service/src/utils/is.ts @@ -0,0 +1,19 @@ +export function isNumber(value: T | unknown): value is number { + return Object.prototype.toString.call(value) === '[object Number]' +} + +export function isString(value: T | unknown): value is string { + return Object.prototype.toString.call(value) === '[object String]' +} + +export function isNotEmptyString(value: any): boolean { + return typeof value === 'string' && value.length > 0 +} + +export function isBoolean(value: T | unknown): value is boolean { + return Object.prototype.toString.call(value) === '[object Boolean]' +} + +export function isFunction any | void | never>(value: T | unknown): value is T { + return Object.prototype.toString.call(value) === '[object Function]' +}