diff --git a/.env.template b/.env.template index 73369b178dfe..83c440724465 100644 --- a/.env.template +++ b/.env.template @@ -1,7 +1,6 @@ # proxy AXIOS_PROXY_HOST=127.0.0.1 -AXIOS_PROXY_PORT_FAST=7890 -AXIOS_PROXY_PORT_NORMAL=7890 +AXIOS_PROXY_PORT=7890 queueTask=1 parentUrl=https://hostname/api/openapi/startEvents # email @@ -16,6 +15,7 @@ aliTemplateCode=SMS_xxx TOKEN_KEY=xxx # openai OPENAIKEY=sk-xxx +OPENAI_BASE_URL=https://api.openai.com/v1 # db MONGODB_URI=mongodb://username:password@0.0.0.0:27017/test?authSource=admin PG_HOST=0.0.0.0 diff --git a/README.md b/README.md index 46481ab526d2..0399349562f0 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,10 @@ Fast GPT 允许你使用自己的 openai API KEY 来快速的调用 openai 接 ```bash # proxy(不需要代理可忽略) AXIOS_PROXY_HOST=127.0.0.1 -AXIOS_PROXY_PORT_FAST=7890 -AXIOS_PROXY_PORT_NORMAL=7890 +AXIOS_PROXY_PORT=7890 +# 中转方案,修改 openai 的 base url +OPENAI_BASE_URL=https://api.openai.com/v1 +# 是否开启队列任务。 1-开启,0-关闭(请求parentUrl去执行任务,单机时直接填1) queueTask=1 parentUrl=https://hostname/api/openapi/startEvents # email,参考 nodeMail 获取参数 @@ -181,24 +183,17 @@ services: restart: always container_name: fast-gpt environment: - # 代理(不需要代理,可去掉下面三个参数) - AXIOS_PROXY_HOST=127.0.0.1 - - AXIOS_PROXY_PORT_FAST=7890 - - AXIOS_PROXY_PORT_NORMAL=7890 - # 邮箱 + - AXIOS_PROXY_PORT=7890 - MY_MAIL=xxxx@qq.com - MAILE_CODE=xxxx - # 阿里云短信 - aliAccessKeyId=xxxx - aliAccessKeySecret=xxxx - aliSignName=xxxxx - aliTemplateCode=SMS_xxxx - # 登录 key - TOKEN_KEY=xxxx - # 是否开启队列任务。 1-开启,0-关闭(请求parentUrl去执行任务,单机时直接填1) - queueTask=1 - parentUrl=https://hostname/api/openapi/startEvents - # db - MONGODB_URI=mongodb://username:passsword@0.0.0.0:27017/?authSource=admin - MONGODB_NAME=xxx - PG_HOST=0.0.0.0 @@ -206,7 +201,6 @@ services: - PG_USER=xxx - PG_PASSWORD=xxx - PG_DB_NAME=xxx - # openai 账号 - OPENAIKEY=sk-xxxxx nginx: image: nginx:alpine3.17 diff --git a/src/pages/api/chat/chatGpt.ts b/src/pages/api/chat/chatGpt.ts index e102ede09eed..5154c2364843 100644 --- a/src/pages/api/chat/chatGpt.ts +++ b/src/pages/api/chat/chatGpt.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase } from '@/service/mongo'; import { getOpenAIApi, authChat } from '@/service/utils/auth'; -import { httpsAgent, openaiChatFilter } from '@/service/utils/tools'; +import { axiosConfig, openaiChatFilter } from '@/service/utils/tools'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; @@ -88,7 +88,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) { timeout: 40000, responseType: 'stream', - httpsAgent: httpsAgent(!userApiKey) + ...axiosConfig } ); diff --git a/src/pages/api/chat/vectorGpt.ts b/src/pages/api/chat/vectorGpt.ts index 41fa099b3b19..ec74a004aee4 100644 --- a/src/pages/api/chat/vectorGpt.ts +++ b/src/pages/api/chat/vectorGpt.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase } from '@/service/mongo'; import { authChat } from '@/service/utils/auth'; -import { httpsAgent, systemPromptFilter, openaiChatFilter } from '@/service/utils/tools'; +import { axiosConfig, systemPromptFilter, openaiChatFilter } from '@/service/utils/tools'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; @@ -150,7 +150,7 @@ ${ { timeout: 40000, responseType: 'stream', - httpsAgent: httpsAgent(!userApiKey) + ...axiosConfig } ); diff --git a/src/pages/api/model/data/fetchingUrlData.ts b/src/pages/api/model/data/fetchingUrlData.ts index 5919b54b40ed..f032c64b1480 100644 --- a/src/pages/api/model/data/fetchingUrlData.ts +++ b/src/pages/api/model/data/fetchingUrlData.ts @@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response'; import { connectToDatabase } from '@/service/mongo'; import { authToken } from '@/service/utils/tools'; import axios from 'axios'; -import { httpsAgent } from '@/service/utils/tools'; +import { axiosConfig } from '@/service/utils/tools'; /** * 读取网站的内容 @@ -22,7 +22,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const data = await axios .get(url, { - httpsAgent: httpsAgent(false) + httpsAgent: axiosConfig.httpsAgent }) .then((res) => res.data as string); diff --git a/src/pages/api/model/del.ts b/src/pages/api/model/del.ts index e82cade53790..e2b3dea6da2c 100644 --- a/src/pages/api/model/del.ts +++ b/src/pages/api/model/del.ts @@ -1,11 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/service/response'; -import { Chat, Model, Training, connectToDatabase } from '@/service/mongo'; +import { Chat, Model, connectToDatabase } from '@/service/mongo'; import { authToken } from '@/service/utils/tools'; -import { getUserApiOpenai } from '@/service/utils/openai'; -import { TrainingStatusEnum } from '@/constants/model'; -import { TrainingItemType } from '@/types/training'; -import { httpsAgent } from '@/service/utils/tools'; import { PgClient } from '@/service/pg'; /* 获取我的模型 */ @@ -47,31 +43,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< modelId }); - // 查看是否正在训练 - const training: TrainingItemType | null = await Training.findOne({ - modelId, - status: TrainingStatusEnum.pending - }); - - // 如果正在训练,需要删除openai上的相关信息 - if (training) { - const { openai } = await getUserApiOpenai(userId); - // 获取训练记录 - const tuneRecord = await openai.retrieveFineTune(training.tuneId, { - httpsAgent: httpsAgent(false) - }); - - // 删除训练文件 - openai.deleteFile(tuneRecord.data.training_files[0].id, { httpsAgent: httpsAgent(false) }); - // 取消训练 - openai.cancelFineTune(training.tuneId, { httpsAgent: httpsAgent(false) }); - } - - // 删除对应训练记录 - await Training.deleteMany({ - modelId - }); - // 删除模型 await Model.deleteOne({ _id: modelId, diff --git a/src/pages/api/model/train/getTrainings.ts b/src/pages/api/model/train/getTrainings.ts deleted file mode 100644 index f50c0b747679..000000000000 --- a/src/pages/api/model/train/getTrainings.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@/service/response'; -import { connectToDatabase, Training } from '@/service/mongo'; -import { authToken } from '@/service/utils/tools'; - -// 关闭next默认的bodyParser处理方式 -export const config = { - api: { - bodyParser: false - } -}; - -/* 获取模型训练记录 */ -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - const { authorization } = req.headers; - - if (!authorization) { - throw new Error('无权操作'); - } - const { modelId } = req.query; - if (!modelId) { - throw new Error('参数错误'); - } - await authToken(authorization); - - await connectToDatabase(); - - /* 获取 modelId 下的 training 记录 */ - const records = await Training.find({ - modelId - }); - - jsonRes(res, { - data: records - }); - } catch (err: any) { - /* 清除上传的文件,关闭训练记录 */ - // @ts-ignore - if (openai) { - // @ts-ignore - uploadFileId && openai.deleteFile(uploadFileId); - // @ts-ignore - trainId && openai.cancelFineTune(trainId); - } - - jsonRes(res, { - code: 500, - error: err - }); - } -} diff --git a/src/pages/api/model/train/putTrainStatus.ts b/src/pages/api/model/train/putTrainStatus.ts deleted file mode 100644 index cde2869d5924..000000000000 --- a/src/pages/api/model/train/putTrainStatus.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@/service/response'; -import { connectToDatabase, Model, Training } from '@/service/mongo'; -import { authToken } from '@/service/utils/tools'; -import { getUserApiOpenai } from '@/service/utils/openai'; -import type { ModelSchema } from '@/types/mongoSchema'; -import { TrainingItemType } from '@/types/training'; -import { ModelStatusEnum, TrainingStatusEnum } from '@/constants/model'; -import { OpenAiTuneStatusEnum } from '@/service/constants/training'; -import { httpsAgent } from '@/service/utils/tools'; - -/* 更新训练状态 */ -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - const { authorization } = req.headers; - - if (!authorization) { - throw new Error('无权操作'); - } - const { modelId } = req.query as { modelId: string }; - if (!modelId) { - throw new Error('参数错误'); - } - const userId = await authToken(authorization); - - await connectToDatabase(); - - // 获取模型 - const model = await Model.findById(modelId); - - if (!model || model.status !== 'training') { - throw new Error('模型不在训练中'); - } - - // 查询正在训练中的训练记录 - const training: TrainingItemType | null = await Training.findOne({ - modelId, - status: 'pending' - }); - - if (!training) { - throw new Error('找不到训练记录'); - } - - // 用户的 openai 实例 - const { openai } = await getUserApiOpenai(userId); - - // 获取 openai 的训练情况 - const { data } = await openai.retrieveFineTune(training.tuneId, { - httpsAgent: httpsAgent(false) - }); - // console.log(data); - if (data.status === OpenAiTuneStatusEnum.succeeded) { - // 删除训练文件 - openai.deleteFile(data.training_files[0].id, { httpsAgent: httpsAgent(false) }); - - // 更新模型状态和模型内容 - await Model.findByIdAndUpdate(modelId, { - status: ModelStatusEnum.running, - updateTime: new Date(), - service: { - ...model.service, - trainId: data.fine_tuned_model, // 训练完后,再次训练和对话使用的 model 是一样的 - chatModel: data.fine_tuned_model - } - }); - // 更新训练数据 - await Training.findByIdAndUpdate(training._id, { - status: TrainingStatusEnum.succeed - }); - - return jsonRes(res, { - data: '模型微调完成' - }); - } - - /* 取消微调 */ - if (data.status === OpenAiTuneStatusEnum.cancelled) { - // 删除训练文件 - openai.deleteFile(data.training_files[0].id, { httpsAgent: httpsAgent(false) }); - - // 更新模型 - await Model.findByIdAndUpdate(modelId, { - status: ModelStatusEnum.running, - updateTime: new Date() - }); - // 更新训练数据 - await Training.findByIdAndUpdate(training._id, { - status: TrainingStatusEnum.canceled - }); - - return jsonRes(res, { - data: '模型微调已取消' - }); - } - - jsonRes(res, { - data: '模型还在训练中' - }); - } catch (err: any) { - jsonRes(res, { - code: 500, - error: err - }); - } -} diff --git a/src/pages/api/model/train/train.ts b/src/pages/api/model/train/train.ts deleted file mode 100644 index 9a6d9ed713ed..000000000000 --- a/src/pages/api/model/train/train.ts +++ /dev/null @@ -1,130 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@/service/response'; -import { connectToDatabase, Model, Training } from '@/service/mongo'; -import formidable from 'formidable'; -import { authToken } from '@/service/utils/tools'; -import { getUserApiOpenai } from '@/service/utils/openai'; -import { join } from 'path'; -import fs from 'fs'; -import type { ModelSchema } from '@/types/mongoSchema'; -import type { OpenAIApi } from 'openai'; -import { ModelStatusEnum, TrainingStatusEnum } from '@/constants/model'; -import { httpsAgent } from '@/service/utils/tools'; - -// 关闭next默认的bodyParser处理方式 -export const config = { - api: { - bodyParser: false - } -}; - -/* 上传文件,开始微调 */ -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - let openai: OpenAIApi, trainId: string, uploadFileId: string; - - try { - const { authorization } = req.headers; - - if (!authorization) { - throw new Error('无权操作'); - } - const { modelId } = req.query; - - if (!modelId) { - throw new Error('参数错误'); - } - const userId = await authToken(authorization); - - await connectToDatabase(); - - // 获取模型的状态 - const model = await Model.findById(modelId); - - if (!model || model.status !== 'running') { - throw new Error('模型正忙'); - } - - // const trainingType = model.service.modelType - const trainingType = model.service.trainId; // 目前都默认是 openai text-davinci-03 - - // 获取用户的 API Key 实例化后的对象 - const user = await getUserApiOpenai(userId); - openai = user.openai; - - // 接收文件并保存 - const form = formidable({ - uploadDir: join(process.cwd(), 'public/trainData'), - keepExtensions: true - }); - - const { files } = await new Promise<{ - fields: formidable.Fields; - files: formidable.Files; - }>((resolve, reject) => { - form.parse(req, (err, fields, files) => { - if (err) return reject(err); - resolve({ fields, files }); - }); - }); - const file = files.file; - - // 上传文件到 openai - // @ts-ignore - const uploadRes = await openai.createFile( - // @ts-ignore - fs.createReadStream(file.filepath), - 'fine-tune', - { httpsAgent: httpsAgent(false) } - ); - uploadFileId = uploadRes.data.id; // 记录上传文件的 ID - - // 开始训练 - const trainRes = await openai.createFineTune( - { - training_file: uploadFileId, - model: trainingType, - suffix: model.name, - n_epochs: 4 - }, - { httpsAgent: httpsAgent(false) } - ); - - trainId = trainRes.data.id; // 记录训练 ID - - // 创建训练记录 - await Training.create({ - serviceName: 'openai', - tuneId: trainId, - status: TrainingStatusEnum.pending, - modelId - }); - - // 修改模型状态 - await Model.findByIdAndUpdate(modelId, { - $inc: { - trainingTimes: +1 - }, - updateTime: new Date(), - status: ModelStatusEnum.training - }); - - jsonRes(res, { - data: 'start training' - }); - } catch (err: any) { - /* 清除上传的文件,关闭训练记录 */ - // @ts-ignore - if (openai) { - // @ts-ignore - uploadFileId && openai.deleteFile(uploadFileId, { httpsAgent: httpsAgent(false) }); - // @ts-ignore - trainId && openai.cancelFineTune(trainId, { httpsAgent: httpsAgent(false) }); - } - - jsonRes(res, { - code: 500, - error: err - }); - } -} diff --git a/src/pages/api/openapi/chat/chatGpt.ts b/src/pages/api/openapi/chat/chatGpt.ts index b06b1764b276..926b015603c4 100644 --- a/src/pages/api/openapi/chat/chatGpt.ts +++ b/src/pages/api/openapi/chat/chatGpt.ts @@ -1,8 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase, Model } from '@/service/mongo'; import { getOpenAIApi } from '@/service/utils/auth'; -import { httpsAgent, openaiChatFilter, authOpenApiKey } from '@/service/utils/tools'; -import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai'; +import { axiosConfig, openaiChatFilter, authOpenApiKey } from '@/service/utils/tools'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; @@ -101,7 +100,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) { timeout: 40000, responseType: isStream ? 'stream' : 'json', - httpsAgent: httpsAgent(true) + ...axiosConfig } ); diff --git a/src/pages/api/openapi/chat/lafGpt.ts b/src/pages/api/openapi/chat/lafGpt.ts index 4619e6b38c31..230d1a741201 100644 --- a/src/pages/api/openapi/chat/lafGpt.ts +++ b/src/pages/api/openapi/chat/lafGpt.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase, Model } from '@/service/mongo'; import { getOpenAIApi } from '@/service/utils/auth'; import { authOpenApiKey } from '@/service/utils/tools'; -import { httpsAgent, openaiChatFilter, systemPromptFilter } from '@/service/utils/tools'; +import { axiosConfig, openaiChatFilter, systemPromptFilter } from '@/service/utils/tools'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; @@ -120,7 +120,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, { timeout: 180000, - httpsAgent: httpsAgent(true) + ...axiosConfig } ); @@ -196,7 +196,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) { timeout: 180000, responseType: isStream ? 'stream' : 'json', - httpsAgent: httpsAgent(true) + ...axiosConfig } ); diff --git a/src/pages/api/openapi/chat/vectorGpt.ts b/src/pages/api/openapi/chat/vectorGpt.ts index 4b73dcdda3dc..f8b821d699f6 100644 --- a/src/pages/api/openapi/chat/vectorGpt.ts +++ b/src/pages/api/openapi/chat/vectorGpt.ts @@ -1,12 +1,11 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase, Model } from '@/service/mongo'; import { - httpsAgent, + axiosConfig, systemPromptFilter, authOpenApiKey, openaiChatFilter } from '@/service/utils/tools'; -import { ChatCompletionRequestMessage, ChatCompletionRequestMessageRoleEnum } from 'openai'; import { ChatItemType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; @@ -172,7 +171,7 @@ ${ { timeout: 180000, responseType: isStream ? 'stream' : 'json', - httpsAgent: httpsAgent(true) + ...axiosConfig } ); diff --git a/src/pages/model/detail/components/InputDataModal.tsx b/src/pages/model/detail/components/InputDataModal.tsx index c2dc4225e378..84473d1d392f 100644 --- a/src/pages/model/detail/components/InputDataModal.tsx +++ b/src/pages/model/detail/components/InputDataModal.tsx @@ -119,31 +119,27 @@ const InputDataModal = ({ pb={2} > - 问题 + {'匹配的知识点'}