perf: bill logs

This commit is contained in:
archer
2023-03-27 13:58:57 +08:00
parent 9280a21d12
commit 5249297cb1
6 changed files with 160 additions and 152 deletions

View File

@@ -148,13 +148,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const promptsContent = formatPrompts.map((item) => item.content).join('');
// 只有使用平台的 key 才计费
!userApiKey &&
pushChatBill({
modelName: model.service.modelName,
userId,
chatId,
text: promptsContent + responseContent
});
pushChatBill({
isPay: !userApiKey,
modelName: model.service.modelName,
userId,
chatId,
text: promptsContent + responseContent
});
} catch (err: any) {
if (step === 1) {
// 直接结束流

View File

@@ -149,13 +149,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
stream.destroy();
// 只有使用平台的 key 才计费
!userApiKey &&
pushChatBill({
modelName: model.service.modelName,
userId,
chatId,
text: promptText + responseContent
});
pushChatBill({
isPay: !userApiKey,
modelName: model.service.modelName,
userId,
chatId,
text: promptText + responseContent
});
} catch (err: any) {
// console.log(err?.response);
if (step === 1) {

View File

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

View File

@@ -12,7 +12,7 @@ export async function generateQA(next = false): Promise<any> {
const systemPrompt: ChatCompletionRequestMessage = {
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;
@@ -58,61 +58,68 @@ export async function generateQA(next = false): Promise<any> {
const chatAPI = getOpenAIApi(userApiKey || systemKey);
// 请求 chatgpt 获取回答
const response = await Promise.allSettled(
[0, 0.5, 0.8].map((temperature) =>
chatAPI.createChatCompletion(
{
model: ChatModelNameEnum.GPT35,
temperature: temperature,
n: 1,
messages: [
systemPrompt,
[0.2, 0.8].map(
(temperature) =>
chatAPI
.createChatCompletion(
{
role: 'user',
content: dataItem?.text || ''
model: ChatModelNameEnum.GPT35,
temperature: temperature,
n: 1,
messages: [
systemPrompt,
{
role: 'user',
content: dataItem?.text || ''
}
]
},
{
timeout: 120000,
httpsAgent
}
]
},
{
timeout: 120000,
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 rawContents: string[] = successResponse.map(
(item: any) => item?.value?.data.choices[0].message?.content || ''
);
// 从 content 中提取 QA
const splitResponses = rawContents.map((content) => splitText(content)).flat();
const successResponse: {
rawContent: string;
result: { q: string; a: string }[];
}[] = response.filter((item) => item.status === 'fulfilled').map((item: any) => item.value);
const rawContents = successResponse.map((item) => item.rawContent);
const results = successResponse.map((item) => item.result).flat();
// 插入数据库,并修改状态
await DataItem.findByIdAndUpdate(dataItem._id, {
status: 0,
$push: {
rawResponse: {
$each: rawContents
$each: successResponse.map((item) => item.rawContent)
},
result: {
$each: splitResponses
$each: results
}
}
});
// 计费
!userApiKey &&
splitResponses.length > 0 &&
pushSplitDataBill({
userId: dataItem.userId,
type: 'QA',
text: systemPrompt.content + dataItem.text + rawContents.join('')
});
console.log(
'生成QA成功time:',
`${(Date.now() - startTime) / 1000}s`,
'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) {
console.log('error: 生成QA错误', dataItem?._id);
console.log('response:', error?.response);

View File

@@ -5,55 +5,58 @@ import { formatPrice } from '@/utils/user';
import type { DataType } from '@/types/data';
export const pushChatBill = async ({
isPay,
modelName,
userId,
chatId,
text
}: {
isPay: boolean;
modelName: string;
userId: string;
chatId: string;
text: string;
}) => {
await connectToDatabase();
let billId;
try {
// 获取模型单价格
const modelItem = modelList.find((item) => item.model === modelName);
const unitPrice = modelItem?.price || 5;
// 计算 token 数量
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('price: ', `${formatPrice(price)}`);
console.log('token len:', tokens.length);
try {
// 插入 Bill 记录
const res = await Bill.create({
userId,
type: 'chat',
modelName,
chatId,
textLen: text.length,
tokenLen: tokens.length,
price
});
billId = res._id;
if (isPay) {
await connectToDatabase();
// 账号扣费
await User.findByIdAndUpdate(userId, {
$inc: { balance: -price }
});
} catch (error) {
console.log('创建账单失败:', error);
billId && Bill.findByIdAndDelete(billId);
// 获取模型单价格
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 {
// 插入 Bill 记录
const res = await Bill.create({
userId,
type: 'chat',
modelName,
chatId,
textLen: text.length,
tokenLen: tokens.length,
price
});
billId = res._id;
// 账号扣费
await User.findByIdAndUpdate(userId, {
$inc: { balance: -price }
});
} catch (error) {
console.log('创建账单失败:', error);
billId && Bill.findByIdAndDelete(billId);
}
}
} catch (error) {
console.log(error);
@@ -61,10 +64,12 @@ export const pushChatBill = async ({
};
export const pushSplitDataBill = async ({
isPay,
userId,
text,
type
}: {
isPay: boolean;
userId: string;
text: string;
type: DataType;
@@ -74,39 +79,41 @@ export const pushSplitDataBill = async ({
let billId;
try {
// 获取模型单价格, 都是用 gpt35 拆分
const modelItem = modelList.find((item) => item.model === ChatModelNameEnum.GPT35);
const unitPrice = modelItem?.price || 5;
// 计算 token 数量
const tokens = encode(text);
// 计算价格
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)}`);
console.log('token len:', tokens.length);
try {
// 插入 Bill 记录
const res = await Bill.create({
userId,
type,
modelName: ChatModelNameEnum.GPT35,
textLen: text.length,
tokenLen: tokens.length,
price
});
billId = res._id;
if (isPay) {
try {
// 获取模型单价格, 都是用 gpt35 拆分
const modelItem = modelList.find((item) => item.model === ChatModelNameEnum.GPT35);
const unitPrice = modelItem?.price || 5;
// 计算价格
const price = unitPrice * tokens.length;
// 账号扣费
await User.findByIdAndUpdate(userId, {
$inc: { balance: -price }
});
} catch (error) {
console.log('创建账单失败:', error);
billId && Bill.findByIdAndDelete(billId);
console.log(`splitData bill, price: ${formatPrice(price)}`);
// 插入 Bill 记录
const res = await Bill.create({
userId,
type,
modelName: ChatModelNameEnum.GPT35,
textLen: text.length,
tokenLen: tokens.length,
price
});
billId = res._id;
// 账号扣费
await User.findByIdAndUpdate(userId, {
$inc: { balance: -price }
});
} catch (error) {
console.log('创建账单失败:', error);
billId && Bill.findByIdAndDelete(billId);
}
}
} catch (error) {
console.log(error);

View File

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