mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 08:25:07 +00:00
perf: openapi auth and lafgpt
This commit is contained in:
@@ -12,7 +12,7 @@ import { pushChatBill } from '@/service/events/pushBill';
|
|||||||
import { connectRedis } from '@/service/redis';
|
import { connectRedis } from '@/service/redis';
|
||||||
import { VecModelDataPrefix } from '@/constants/redis';
|
import { VecModelDataPrefix } from '@/constants/redis';
|
||||||
import { vectorToBuffer } from '@/utils/tools';
|
import { vectorToBuffer } from '@/utils/tools';
|
||||||
import { openaiCreateEmbedding, getOpenApiKey, gpt35StreamResponse } from '@/service/utils/openai';
|
import { openaiCreateEmbedding, gpt35StreamResponse } from '@/service/utils/openai';
|
||||||
|
|
||||||
/* 发送提示词 */
|
/* 发送提示词 */
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
@@ -31,12 +31,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { prompt, modelId } = req.body as {
|
const {
|
||||||
|
prompt,
|
||||||
|
modelId,
|
||||||
|
isStream = true
|
||||||
|
} = req.body as {
|
||||||
prompt: ChatItemType;
|
prompt: ChatItemType;
|
||||||
modelId: string;
|
modelId: string;
|
||||||
|
isStream: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!prompt) {
|
if (!prompt || !modelId) {
|
||||||
throw new Error('缺少参数');
|
throw new Error('缺少参数');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,9 +50,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
let startTime = Date.now();
|
let startTime = Date.now();
|
||||||
|
|
||||||
/* 凭证校验 */
|
/* 凭证校验 */
|
||||||
const userId = await authOpenApiKey(req);
|
const { apiKey, userId } = await authOpenApiKey(req);
|
||||||
|
|
||||||
const { userApiKey, systemKey } = await getOpenApiKey(userId);
|
|
||||||
|
|
||||||
/* 查找数据库里的模型信息 */
|
/* 查找数据库里的模型信息 */
|
||||||
const model = await Model.findById(modelId);
|
const model = await Model.findById(modelId);
|
||||||
@@ -61,15 +64,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
if (!modelConstantsData) {
|
if (!modelConstantsData) {
|
||||||
throw new Error('模型已下架');
|
throw new Error('模型已下架');
|
||||||
}
|
}
|
||||||
|
console.log('laf gpt start');
|
||||||
|
|
||||||
// 获取 chatAPI
|
// 获取 chatAPI
|
||||||
const chatAPI = getOpenAIApi(userApiKey || systemKey);
|
const chatAPI = getOpenAIApi(apiKey);
|
||||||
|
|
||||||
// 请求一次 chatgpt 拆解需求
|
// 请求一次 chatgpt 拆解需求
|
||||||
const promptResponse = await chatAPI.createChatCompletion(
|
const promptResponse = await chatAPI.createChatCompletion(
|
||||||
{
|
{
|
||||||
model: ChatModelNameMap[ChatModelNameEnum.GPT35],
|
model: ChatModelNameMap[ChatModelNameEnum.GPT35],
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
|
frequency_penalty: 0.5, // 越大,重复内容越少
|
||||||
|
presence_penalty: -0.5, // 越大,越容易出现新内容
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: 'system',
|
role: 'system',
|
||||||
@@ -104,7 +110,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
timeout: 40000,
|
timeout: 120000,
|
||||||
httpsAgent
|
httpsAgent
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -114,13 +120,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
throw new Error('gpt 异常');
|
throw new Error('gpt 异常');
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt.value += `\n${promptResolve}`;
|
prompt.value += ` ${promptResolve}`;
|
||||||
console.log('prompt resolve success, time:', `${(Date.now() - startTime) / 1000}s`);
|
console.log('prompt resolve success, time:', `${(Date.now() - startTime) / 1000}s`);
|
||||||
|
|
||||||
// 获取提示词的向量
|
// 获取提示词的向量
|
||||||
const { vector: promptVector } = await openaiCreateEmbedding({
|
const { vector: promptVector } = await openaiCreateEmbedding({
|
||||||
isPay: !userApiKey,
|
isPay: true,
|
||||||
apiKey: userApiKey || systemKey,
|
apiKey: apiKey,
|
||||||
userId,
|
userId,
|
||||||
text: prompt.value
|
text: prompt.value
|
||||||
});
|
});
|
||||||
@@ -186,34 +192,44 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
const chatResponse = await chatAPI.createChatCompletion(
|
const chatResponse = await chatAPI.createChatCompletion(
|
||||||
{
|
{
|
||||||
model: model.service.chatModel,
|
model: model.service.chatModel,
|
||||||
temperature: temperature,
|
temperature,
|
||||||
// max_tokens: modelConstantsData.maxToken,
|
|
||||||
messages: formatPrompts,
|
messages: formatPrompts,
|
||||||
frequency_penalty: 0.5, // 越大,重复内容越少
|
frequency_penalty: 0.5, // 越大,重复内容越少
|
||||||
presence_penalty: -0.5, // 越大,越容易出现新内容
|
presence_penalty: -0.5, // 越大,越容易出现新内容
|
||||||
stream: true
|
stream: isStream
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
timeout: 40000,
|
timeout: 120000,
|
||||||
responseType: 'stream',
|
responseType: isStream ? 'stream' : 'json',
|
||||||
httpsAgent
|
httpsAgent
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('api response. time:', `${(Date.now() - startTime) / 1000}s`);
|
console.log('code response. time:', `${(Date.now() - startTime) / 1000}s`);
|
||||||
|
|
||||||
step = 1;
|
step = 1;
|
||||||
const { responseContent } = await gpt35StreamResponse({
|
let responseContent = '';
|
||||||
res,
|
|
||||||
stream,
|
if (isStream) {
|
||||||
chatResponse
|
const streamResponse = await gpt35StreamResponse({
|
||||||
});
|
res,
|
||||||
console.log('response done. time:', `${(Date.now() - startTime) / 1000}s`);
|
stream,
|
||||||
|
chatResponse
|
||||||
|
});
|
||||||
|
responseContent = streamResponse.responseContent;
|
||||||
|
} else {
|
||||||
|
responseContent = chatResponse.data.choices?.[0]?.message?.content || '';
|
||||||
|
jsonRes(res, {
|
||||||
|
data: responseContent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('laf gpt done. time:', `${(Date.now() - startTime) / 1000}s`);
|
||||||
|
|
||||||
const promptsContent = formatPrompts.map((item) => item.content).join('');
|
const promptsContent = formatPrompts.map((item) => item.content).join('');
|
||||||
// 只有使用平台的 key 才计费
|
|
||||||
pushChatBill({
|
pushChatBill({
|
||||||
isPay: !userApiKey,
|
isPay: true,
|
||||||
modelName: model.service.modelName,
|
modelName: model.service.modelName,
|
||||||
userId,
|
userId,
|
||||||
text: promptsContent + responseContent
|
text: promptsContent + responseContent
|
||||||
|
@@ -4,7 +4,8 @@ import jwt from 'jsonwebtoken';
|
|||||||
import tunnel from 'tunnel';
|
import tunnel from 'tunnel';
|
||||||
import { ChatItemType } from '@/types/chat';
|
import { ChatItemType } from '@/types/chat';
|
||||||
import { encode } from 'gpt-token-utils';
|
import { encode } from 'gpt-token-utils';
|
||||||
import { OpenApi } from '../mongo';
|
import { OpenApi, User } from '../mongo';
|
||||||
|
import { formatPrice } from '@/utils/user';
|
||||||
|
|
||||||
/* 密码加密 */
|
/* 密码加密 */
|
||||||
export const hashPassword = (psw: string) => {
|
export const hashPassword = (psw: string) => {
|
||||||
@@ -44,27 +45,41 @@ export const authToken = (token?: string): Promise<string> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* 校验 open api key */
|
/* 校验 open api key */
|
||||||
export const authOpenApiKey = (req: NextApiRequest) => {
|
export const authOpenApiKey = async (req: NextApiRequest) => {
|
||||||
return new Promise<string>(async (resolve, reject) => {
|
const { apikey: apiKey } = req.headers;
|
||||||
const { apikey: apiKey } = req.headers;
|
|
||||||
|
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
reject('api key is empty');
|
return Promise.reject('api key is empty');
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const openApi = await OpenApi.findOne({ apiKey });
|
||||||
|
if (!openApi) {
|
||||||
|
return Promise.reject('api key is error');
|
||||||
}
|
}
|
||||||
try {
|
const userId = String(openApi.userId);
|
||||||
const openApi = await OpenApi.findOne({ apiKey });
|
|
||||||
if (!openApi) {
|
// 余额校验
|
||||||
return reject('api key is error');
|
const user = await User.findById(userId);
|
||||||
}
|
if (!user) {
|
||||||
await OpenApi.findByIdAndUpdate(openApi._id, {
|
return Promise.reject('user is empty');
|
||||||
lastUsedTime: new Date()
|
|
||||||
});
|
|
||||||
resolve(String(openApi.userId));
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
}
|
||||||
});
|
if (formatPrice(user.balance) <= 0) {
|
||||||
|
return Promise.reject('Insufficient account balance');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新使用的时间
|
||||||
|
await OpenApi.findByIdAndUpdate(openApi._id, {
|
||||||
|
lastUsedTime: new Date()
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
apiKey: process.env.OPENAIKEY as string,
|
||||||
|
userId
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 代理 */
|
/* 代理 */
|
||||||
|
Reference in New Issue
Block a user