perf: openapi auth and lafgpt

This commit is contained in:
archer
2023-04-08 00:35:35 +08:00
parent ea1681e1eb
commit eceda01c19
2 changed files with 75 additions and 44 deletions

View File

@@ -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

View File

@@ -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);
}
}; };
/* 代理 */ /* 代理 */