perf: bill logs

This commit is contained in:
archer 2023-03-27 13:58:57 +08:00
parent 9280a21d12
commit 5249297cb1
No known key found for this signature in database
GPG Key ID: 569A5660D2379E28
6 changed files with 160 additions and 152 deletions

View File

@ -148,8 +148,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const promptsContent = formatPrompts.map((item) => item.content).join(''); const promptsContent = formatPrompts.map((item) => item.content).join('');
// 只有使用平台的 key 才计费 // 只有使用平台的 key 才计费
!userApiKey &&
pushChatBill({ pushChatBill({
isPay: !userApiKey,
modelName: model.service.modelName, modelName: model.service.modelName,
userId, userId,
chatId, chatId,

View File

@ -149,8 +149,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
stream.destroy(); stream.destroy();
// 只有使用平台的 key 才计费 // 只有使用平台的 key 才计费
!userApiKey &&
pushChatBill({ pushChatBill({
isPay: !userApiKey,
modelName: model.service.modelName, modelName: model.service.modelName,
userId, userId,
chatId, chatId,

View File

@ -12,7 +12,7 @@ export async function generateAbstract(next = false): Promise<any> {
const systemPrompt: ChatCompletionRequestMessage = { const systemPrompt: ChatCompletionRequestMessage = {
role: 'system', role: 'system',
content: `总结助手,我会向你发送一段长文本,请从文本中归纳总结5至15条信息,请直接输出总结内容,并按以下格式输出: 'A1:'\n'A2:'\n'A3:'\n` content: `总结助手,我会向你发送一段长文本,请从文本中归纳总结5至15条信息,如果是英文,请增加一条中文的总结,并按以下格式输出: A1:\nA2:\nA3:\n`
}; };
let dataItem: DataItemSchema | null = null; let dataItem: DataItemSchema | null = null;
@ -80,36 +80,36 @@ export async function generateAbstract(next = false): Promise<any> {
const rawContent: string = abstractResponse?.data.choices[0].message?.content || ''; const rawContent: string = abstractResponse?.data.choices[0].message?.content || '';
// 从 content 中提取摘要内容 // 从 content 中提取摘要内容
const splitContents = splitText(rawContent); const splitContents = splitText(rawContent);
console.log(rawContent); // console.log(rawContent);
// 生成词向量 // 生成词向量
const vectorResponse = await Promise.allSettled( // const vectorResponse = await Promise.allSettled(
splitContents.map((item) => // splitContents.map((item) =>
chatAPI.createEmbedding( // chatAPI.createEmbedding(
{ // {
model: 'text-embedding-ada-002', // model: 'text-embedding-ada-002',
input: item.abstract // input: item.abstract
}, // },
{ // {
timeout: 120000, // timeout: 120000,
httpsAgent // httpsAgent
} // }
) // )
) // )
); // );
// 筛选成功的向量请求 // 筛选成功的向量请求
const vectorSuccessResponse = vectorResponse // const vectorSuccessResponse = vectorResponse
.map((item: any, i) => { // .map((item: any, i) => {
if (item.status !== 'fulfilled') { // if (item.status !== 'fulfilled') {
// 没有词向量的【摘要】不要 // // 没有词向量的【摘要】不要
console.log('获取词向量错误: ', item); // console.log('获取词向量错误: ', item);
return ''; // return '';
} // }
return { // return {
abstract: splitContents[i].abstract, // abstract: splitContents[i].abstract,
abstractVector: item?.value?.data?.data?.[0]?.embedding // abstractVector: item?.value?.data?.data?.[0]?.embedding
}; // };
}) // })
.filter((item) => item); // .filter((item) => item);
// 插入数据库,并修改状态 // 插入数据库,并修改状态
await DataItem.findByIdAndUpdate(dataItem._id, { await DataItem.findByIdAndUpdate(dataItem._id, {
@ -117,28 +117,22 @@ export async function generateAbstract(next = false): Promise<any> {
$push: { $push: {
rawResponse: rawContent, rawResponse: rawContent,
result: { result: {
$each: vectorSuccessResponse $each: splitContents
} }
} }
}); });
// 计费
!userApiKey &&
vectorSuccessResponse.length > 0 &&
pushSplitDataBill({
userId: dataItem.userId,
type: 'abstract',
text:
systemPrompt.content +
dataItem.text +
rawContent +
rawContent.substring(0, Math.floor(dataItem.text.length / 10)) // 向量价格是 gpt35 的1/10
});
console.log( console.log(
`生成摘要成功time: ${(Date.now() - startTime) / 1000}s`, `生成摘要成功time: ${(Date.now() - startTime) / 1000}s`,
`摘要匹配数量: ${splitContents.length}`, `摘要匹配数量: ${splitContents.length}`
`有向量摘要数量:${vectorSuccessResponse.length}`
); );
// 计费
pushSplitDataBill({
isPay: !userApiKey && splitContents.length > 0,
userId: dataItem.userId,
type: 'abstract',
text: systemPrompt.content + dataItem.text + rawContent
});
} catch (error: any) { } catch (error: any) {
console.log('error: 生成摘要错误', dataItem?._id); console.log('error: 生成摘要错误', dataItem?._id);
console.log('response:', error); console.log('response:', error);

View File

@ -12,7 +12,7 @@ export async function generateQA(next = false): Promise<any> {
const systemPrompt: ChatCompletionRequestMessage = { const systemPrompt: ChatCompletionRequestMessage = {
role: 'system', role: 'system',
content: `总结助手。我会向你发送一段长文本,请从中总结出5至15个问题和答案,答案请尽量详细,请按以下格式返回: "Q1:"\n"A1:"\n"Q2:"\n"A2:"\n` content: `总结助手。我会向你发送一段长文本,请从中总结出5至15个问题和答案,答案请尽量详细,请按以下格式返回: Q1:\nA1:\nQ2:\nA2:\n`
}; };
let dataItem: DataItemSchema | null = null; let dataItem: DataItemSchema | null = null;
@ -58,8 +58,10 @@ export async function generateQA(next = false): Promise<any> {
const chatAPI = getOpenAIApi(userApiKey || systemKey); const chatAPI = getOpenAIApi(userApiKey || systemKey);
// 请求 chatgpt 获取回答 // 请求 chatgpt 获取回答
const response = await Promise.allSettled( const response = await Promise.allSettled(
[0, 0.5, 0.8].map((temperature) => [0.2, 0.8].map(
chatAPI.createChatCompletion( (temperature) =>
chatAPI
.createChatCompletion(
{ {
model: ChatModelNameEnum.GPT35, model: ChatModelNameEnum.GPT35,
temperature: temperature, temperature: temperature,
@ -77,42 +79,47 @@ export async function generateQA(next = false): Promise<any> {
httpsAgent httpsAgent
} }
) )
.then((res) => ({
rawContent: res?.data.choices[0].message?.content || '',
result: splitText(res?.data.choices[0].message?.content || '')
})) // 从 content 中提取 QA
) )
); );
// 过滤出成功的响应 // 过滤出成功的响应
const successResponse = response.filter((item) => item.status === 'fulfilled'); const successResponse: {
// 提取响应内容 rawContent: string;
const rawContents: string[] = successResponse.map( result: { q: string; a: string }[];
(item: any) => item?.value?.data.choices[0].message?.content || '' }[] = response.filter((item) => item.status === 'fulfilled').map((item: any) => item.value);
);
// 从 content 中提取 QA const rawContents = successResponse.map((item) => item.rawContent);
const splitResponses = rawContents.map((content) => splitText(content)).flat(); const results = successResponse.map((item) => item.result).flat();
// 插入数据库,并修改状态 // 插入数据库,并修改状态
await DataItem.findByIdAndUpdate(dataItem._id, { await DataItem.findByIdAndUpdate(dataItem._id, {
status: 0, status: 0,
$push: { $push: {
rawResponse: { rawResponse: {
$each: rawContents $each: successResponse.map((item) => item.rawContent)
}, },
result: { result: {
$each: splitResponses $each: results
} }
} }
}); });
// 计费
!userApiKey &&
splitResponses.length > 0 &&
pushSplitDataBill({
userId: dataItem.userId,
type: 'QA',
text: systemPrompt.content + dataItem.text + rawContents.join('')
});
console.log( console.log(
'生成QA成功time:', '生成QA成功time:',
`${(Date.now() - startTime) / 1000}s`, `${(Date.now() - startTime) / 1000}s`,
'QA数量', 'QA数量',
splitResponses.length results.length
); );
// 计费
pushSplitDataBill({
isPay: !userApiKey && results.length > 0,
userId: dataItem.userId,
type: 'QA',
text: systemPrompt.content + dataItem.text + rawContents.join('')
});
} catch (error: any) { } catch (error: any) {
console.log('error: 生成QA错误', dataItem?._id); console.log('error: 生成QA错误', dataItem?._id);
console.log('response:', error?.response); console.log('response:', error?.response);

View File

@ -5,34 +5,36 @@ import { formatPrice } from '@/utils/user';
import type { DataType } from '@/types/data'; import type { DataType } from '@/types/data';
export const pushChatBill = async ({ export const pushChatBill = async ({
isPay,
modelName, modelName,
userId, userId,
chatId, chatId,
text text
}: { }: {
isPay: boolean;
modelName: string; modelName: string;
userId: string; userId: string;
chatId: string; chatId: string;
text: string; text: string;
}) => { }) => {
await connectToDatabase();
let billId; let billId;
try { try {
// 获取模型单价格
const modelItem = modelList.find((item) => item.model === modelName);
const unitPrice = modelItem?.price || 5;
// 计算 token 数量 // 计算 token 数量
const tokens = encode(text); const tokens = encode(text);
// 计算价格
const price = unitPrice * tokens.length;
console.log('chat bill');
console.log('token len:', tokens.length);
console.log('text len: ', text.length); console.log('text len: ', text.length);
console.log('price: ', `${formatPrice(price)}`); console.log('token len:', tokens.length);
if (isPay) {
await connectToDatabase();
// 获取模型单价格
const modelItem = modelList.find((item) => item.model === modelName);
// 计算价格
const unitPrice = modelItem?.price || 5;
const price = unitPrice * tokens.length;
console.log(`chat bill, price: ${formatPrice(price)}`);
try { try {
// 插入 Bill 记录 // 插入 Bill 记录
@ -55,16 +57,19 @@ export const pushChatBill = async ({
console.log('创建账单失败:', error); console.log('创建账单失败:', error);
billId && Bill.findByIdAndDelete(billId); billId && Bill.findByIdAndDelete(billId);
} }
}
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
}; };
export const pushSplitDataBill = async ({ export const pushSplitDataBill = async ({
isPay,
userId, userId,
text, text,
type type
}: { }: {
isPay: boolean;
userId: string; userId: string;
text: string; text: string;
type: DataType; type: DataType;
@ -74,21 +79,22 @@ export const pushSplitDataBill = async ({
let billId; let billId;
try { try {
// 获取模型单价格, 都是用 gpt35 拆分
const modelItem = modelList.find((item) => item.model === ChatModelNameEnum.GPT35);
const unitPrice = modelItem?.price || 5;
// 计算 token 数量 // 计算 token 数量
const tokens = encode(text); const tokens = encode(text);
console.log('text len: ', text.length);
console.log('token len:', tokens.length);
if (isPay) {
try {
// 获取模型单价格, 都是用 gpt35 拆分
const modelItem = modelList.find((item) => item.model === ChatModelNameEnum.GPT35);
const unitPrice = modelItem?.price || 5;
// 计算价格 // 计算价格
const price = unitPrice * tokens.length; const price = unitPrice * tokens.length;
console.log('splitData bill');
console.log('token len:', tokens.length);
console.log('text len: ', text.length);
console.log('price: ', `${formatPrice(price)}`);
try { console.log(`splitData bill, price: ${formatPrice(price)}`);
// 插入 Bill 记录 // 插入 Bill 记录
const res = await Bill.create({ const res = await Bill.create({
userId, userId,
@ -108,6 +114,7 @@ export const pushSplitDataBill = async ({
console.log('创建账单失败:', error); console.log('创建账单失败:', error);
billId && Bill.findByIdAndDelete(billId); billId && Bill.findByIdAndDelete(billId);
} }
}
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

View File

@ -28,10 +28,10 @@ export const jsonRes = <T = any>(
} else if (openaiError[error?.response?.statusText]) { } else if (openaiError[error?.response?.statusText]) {
msg = openaiError[error.response.statusText]; msg = openaiError[error.response.statusText];
} }
error?.response && console.log('chat err:', error?.response);
console.log('error->'); console.log('error->');
console.log('code:', error.code); console.log('code:', error.code);
console.log('statusText:', error?.response?.statusText); console.log('statusText:', error?.response?.statusText);
console.log('data len:', error?.response?.config?.data.length);
console.log('msg:', msg); console.log('msg:', msg);
} }