mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
perf: bill logs
This commit is contained in:
@@ -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) {
|
||||
// 直接结束流
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user