mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
perf: bill framwork
This commit is contained in:
@@ -2,10 +2,9 @@ import { GET, POST, PUT } from './request';
|
||||
import { createHashPassword, Obj2Query } from '@/utils/tools';
|
||||
import { ResLogin, PromotionRecordType } from './response/user';
|
||||
import { UserAuthTypeEnum } from '@/constants/common';
|
||||
import { UserType, UserUpdateParams } from '@/types/user';
|
||||
import { UserBillType, UserType, UserUpdateParams } from '@/types/user';
|
||||
import type { PagingData, RequestPaging } from '@/types';
|
||||
import { BillSchema, PaySchema } from '@/types/mongoSchema';
|
||||
import { adaptBill } from '@/utils/adapt';
|
||||
import { PaySchema } from '@/types/mongoSchema';
|
||||
|
||||
export const sendAuthCode = ({
|
||||
username,
|
||||
@@ -69,10 +68,7 @@ export const loginOut = () => GET('/user/loginout');
|
||||
export const putUserInfo = (data: UserUpdateParams) => PUT('/user/update', data);
|
||||
|
||||
export const getUserBills = (data: RequestPaging) =>
|
||||
GET<PagingData<BillSchema>>(`/user/getBill?${Obj2Query(data)}`).then((res) => ({
|
||||
...res,
|
||||
data: res.data.map((bill) => adaptBill(bill))
|
||||
}));
|
||||
GET<PagingData<UserBillType>>(`/user/getBill?${Obj2Query(data)}`);
|
||||
|
||||
export const getPayOrders = () => GET<PaySchema[]>(`/user/getPayOrders`);
|
||||
|
||||
|
@@ -1,8 +1,7 @@
|
||||
export enum BillTypeEnum {
|
||||
chat = 'chat',
|
||||
splitData = 'splitData',
|
||||
openapiChat = 'openapiChat',
|
||||
QA = 'QA',
|
||||
abstract = 'abstract',
|
||||
vector = 'vector',
|
||||
return = 'return'
|
||||
}
|
||||
@@ -14,9 +13,8 @@ export enum PageTypeEnum {
|
||||
|
||||
export const BillTypeMap: Record<`${BillTypeEnum}`, string> = {
|
||||
[BillTypeEnum.chat]: '对话',
|
||||
[BillTypeEnum.splitData]: 'QA拆分',
|
||||
[BillTypeEnum.openapiChat]: 'api 对话',
|
||||
[BillTypeEnum.QA]: 'QA拆分',
|
||||
[BillTypeEnum.abstract]: '摘要总结',
|
||||
[BillTypeEnum.vector]: '索引生成',
|
||||
[BillTypeEnum.return]: '退款'
|
||||
};
|
||||
|
@@ -1,18 +0,0 @@
|
||||
import React, { useState, useCallback, useRef } from 'react';
|
||||
|
||||
export const useTabs = ({
|
||||
tabs = []
|
||||
}: {
|
||||
tabs: {
|
||||
id: string;
|
||||
label: string;
|
||||
}[];
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState(tabs[0].id);
|
||||
|
||||
return {
|
||||
tabs,
|
||||
activeTab,
|
||||
setActiveTab
|
||||
};
|
||||
};
|
@@ -9,6 +9,7 @@ import { pushChatBill } from '@/service/events/pushBill';
|
||||
import { resStreamResponse } from '@/service/utils/chat';
|
||||
import { searchKb } from '@/service/plugins/searchKb';
|
||||
import { ChatRoleEnum } from '@/constants/chat';
|
||||
import { BillTypeEnum } from '@/constants/user';
|
||||
|
||||
/* 发送提示词 */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -108,7 +109,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
userId,
|
||||
chatId,
|
||||
textLen: finishMessages.map((item) => item.value).join('').length,
|
||||
tokens: totalTokens
|
||||
tokens: totalTokens,
|
||||
type: BillTypeEnum.chat
|
||||
});
|
||||
} catch (err: any) {
|
||||
if (step === 1) {
|
||||
|
@@ -9,6 +9,7 @@ import { pushChatBill, updateShareChatBill } from '@/service/events/pushBill';
|
||||
import { resStreamResponse } from '@/service/utils/chat';
|
||||
import { searchKb } from '@/service/plugins/searchKb';
|
||||
import { ChatRoleEnum } from '@/constants/chat';
|
||||
import { BillTypeEnum } from '@/constants/user';
|
||||
|
||||
/* 发送提示词 */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -98,7 +99,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
chatModel: model.chat.chatModel,
|
||||
userId,
|
||||
textLen: finishMessages.map((item) => item.value).join('').length,
|
||||
tokens: totalTokens
|
||||
tokens: totalTokens,
|
||||
type: BillTypeEnum.chat
|
||||
});
|
||||
updateShareChatBill({
|
||||
shareId,
|
||||
|
@@ -9,6 +9,7 @@ import { pushChatBill } from '@/service/events/pushBill';
|
||||
import { searchKb } from '@/service/plugins/searchKb';
|
||||
import { ChatRoleEnum } from '@/constants/chat';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { BillTypeEnum } from '@/constants/user';
|
||||
|
||||
/* 发送提示词 */
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
@@ -45,7 +46,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
let startTime = Date.now();
|
||||
|
||||
/* 凭证校验 */
|
||||
const { userId } = await authUser({ req, authOpenApi: true });
|
||||
const { userId } = await authUser({ req });
|
||||
|
||||
const { model } = await authModel({
|
||||
userId,
|
||||
@@ -74,7 +75,9 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
|
||||
// search result is empty
|
||||
if (code === 201) {
|
||||
return res.send(searchPrompts[0]?.value);
|
||||
return isStream
|
||||
? res.send(searchPrompts[0]?.value)
|
||||
: jsonRes(res, { data: searchPrompts[0]?.value });
|
||||
}
|
||||
prompts.splice(prompts.length - 3, 0, ...searchPrompts);
|
||||
} else {
|
||||
@@ -129,7 +132,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
chatModel: model.chat.chatModel,
|
||||
userId,
|
||||
textLen,
|
||||
tokens
|
||||
tokens,
|
||||
type: BillTypeEnum.openapiChat
|
||||
});
|
||||
} catch (err: any) {
|
||||
if (step === 1) {
|
||||
|
@@ -15,7 +15,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { userId } = await authUser({ req, authToken: true });
|
||||
const { userId } = await authUser({ req });
|
||||
|
||||
await PgClient.delete('modelData', {
|
||||
where: [['user_id', userId], 'AND', ['id', dataId]]
|
||||
|
@@ -15,7 +15,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { userId } = await authUser({ req, authToken: true });
|
||||
const { userId } = await authUser({ req });
|
||||
|
||||
// 更新 pg 内容.仅修改a,不需要更新向量。
|
||||
await PgClient.update('modelData', {
|
||||
|
@@ -22,7 +22,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
}
|
||||
await connectToDatabase();
|
||||
|
||||
const { userId } = await authUser({ req, authToken: true });
|
||||
const { userId } = await authUser({ req });
|
||||
|
||||
// 验证是否是该用户的 model
|
||||
await authKb({
|
||||
|
@@ -3,7 +3,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase, Bill } from '@/service/mongo';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
import type { BillSchema } from '@/types/mongoSchema';
|
||||
import { adaptBill } from '@/utils/adapt';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
@@ -17,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
await connectToDatabase();
|
||||
|
||||
// 根据 id 获取用户账单
|
||||
const bills = await Bill.find<BillSchema>({
|
||||
const bills = await Bill.find({
|
||||
userId
|
||||
})
|
||||
.sort({ _id: -1 }) // 按照创建时间倒序排列
|
||||
@@ -33,7 +33,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
data: {
|
||||
pageNum,
|
||||
pageSize,
|
||||
data: bills,
|
||||
data: bills.map(adaptBill),
|
||||
total
|
||||
}
|
||||
});
|
||||
|
@@ -5,6 +5,7 @@ import { getUserBills } from '@/api/user';
|
||||
import type { UserBillType } from '@/types/user';
|
||||
import { usePagination } from '@/hooks/usePagination';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const BillTable = () => {
|
||||
const { Loading } = useLoading();
|
||||
@@ -28,6 +29,7 @@ const BillTable = () => {
|
||||
<Tr>
|
||||
<Th>时间</Th>
|
||||
<Th>类型</Th>
|
||||
<Th>底层模型</Th>
|
||||
<Th>内容长度</Th>
|
||||
<Th>Tokens 长度</Th>
|
||||
<Th>金额</Th>
|
||||
@@ -36,8 +38,9 @@ const BillTable = () => {
|
||||
<Tbody fontSize={'sm'}>
|
||||
{bills.map((item) => (
|
||||
<Tr key={item.id}>
|
||||
<Td>{item.time}</Td>
|
||||
<Td>{BillTypeMap[item.type]}</Td>
|
||||
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
|
||||
<Td>{BillTypeMap[item.type] || '-'}</Td>
|
||||
<Td>{item.modelName}</Td>
|
||||
<Td>{item.textLen}</Td>
|
||||
<Td>{item.tokenLen}</Td>
|
||||
<Td>{item.price}元</Td>
|
||||
|
@@ -9,6 +9,7 @@ import { SplitDataSchema } from '@/types/mongoSchema';
|
||||
import { modelServiceToolMap } from '../utils/chat';
|
||||
import { ChatRoleEnum } from '@/constants/chat';
|
||||
import { getErrText } from '@/utils/tools';
|
||||
import { BillTypeEnum } from '@/constants/user';
|
||||
|
||||
export async function generateQA(next = false): Promise<any> {
|
||||
if (process.env.queueTask !== '1') {
|
||||
@@ -98,7 +99,7 @@ A2:
|
||||
pushSplitDataBill({
|
||||
isPay: !userOpenAiKey && result.length > 0,
|
||||
userId: dataItem.userId,
|
||||
type: 'QA',
|
||||
type: BillTypeEnum.QA,
|
||||
textLen: responseMessages.map((item) => item.value).join('').length,
|
||||
totalTokens
|
||||
});
|
||||
|
@@ -8,7 +8,8 @@ export const pushChatBill = async ({
|
||||
userId,
|
||||
chatId,
|
||||
textLen,
|
||||
tokens
|
||||
tokens,
|
||||
type
|
||||
}: {
|
||||
isPay: boolean;
|
||||
chatModel: ChatModelType;
|
||||
@@ -16,6 +17,7 @@ export const pushChatBill = async ({
|
||||
chatId?: '' | string;
|
||||
textLen: number;
|
||||
tokens: number;
|
||||
type: BillTypeEnum.chat | BillTypeEnum.openapiChat;
|
||||
}) => {
|
||||
console.log(`chat generate success. text len: ${textLen}. token len: ${tokens}. pay:${isPay}`);
|
||||
if (!isPay) return;
|
||||
@@ -33,7 +35,7 @@ export const pushChatBill = async ({
|
||||
// 插入 Bill 记录
|
||||
const res = await Bill.create({
|
||||
userId,
|
||||
type: 'chat',
|
||||
type,
|
||||
modelName: chatModel,
|
||||
chatId: chatId ? chatId : undefined,
|
||||
textLen,
|
||||
@@ -83,7 +85,7 @@ export const pushSplitDataBill = async ({
|
||||
userId: string;
|
||||
totalTokens: number;
|
||||
textLen: number;
|
||||
type: `${BillTypeEnum}`;
|
||||
type: BillTypeEnum.QA;
|
||||
}) => {
|
||||
console.log(
|
||||
`splitData generate success. text len: ${textLen}. token len: ${totalTokens}. pay:${isPay}`
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Schema, model, models, Model } from 'mongoose';
|
||||
import { ChatModelMap } from '@/constants/model';
|
||||
import { ChatModelMap, embeddingModel } from '@/constants/model';
|
||||
import { BillSchema as BillType } from '@/types/mongoSchema';
|
||||
import { BillTypeMap } from '@/constants/user';
|
||||
|
||||
@@ -16,7 +16,7 @@ const BillSchema = new Schema({
|
||||
},
|
||||
modelName: {
|
||||
type: String,
|
||||
enum: [...Object.keys(ChatModelMap), 'text-embedding-ada-002'],
|
||||
enum: [...Object.keys(ChatModelMap), embeddingModel],
|
||||
required: true
|
||||
},
|
||||
chatId: {
|
||||
|
@@ -1,35 +1,34 @@
|
||||
import axios from 'axios';
|
||||
|
||||
{/*Bing 搜索*/}
|
||||
{
|
||||
/*Bing 搜索*/
|
||||
}
|
||||
const BingSearch = async (wait_val: string) => {
|
||||
const response = await axios.post("newbing中转服务器", {
|
||||
prompt: wait_val,
|
||||
const response = await axios.post('newbing中转服务器', {
|
||||
prompt: wait_val
|
||||
});
|
||||
const result = response.data.result;
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
{/*google 搜索*/}
|
||||
{
|
||||
/*google 搜索*/
|
||||
}
|
||||
const GoogleSearch = async (wait_val: string) => {
|
||||
|
||||
const response = await axios.get('https://www.googleapis.com/customsearch/v1', {
|
||||
params: {
|
||||
key: google_api,
|
||||
key: process.env.GOOGLE_KEY,
|
||||
q: wait_val,
|
||||
cx: searchEngineId,
|
||||
cx: process.env.searchEngineId,
|
||||
start: 1,
|
||||
num: 3,
|
||||
dateRestrict: 'm[1]', //搜索结果限定为一个月内
|
||||
},
|
||||
dateRestrict: 'm[1]' //搜索结果限定为一个月内
|
||||
}
|
||||
});
|
||||
const results = response.data.items;
|
||||
if (results !== null) {
|
||||
const result = results.map((item: { snippet: string }) => item.snippet).join('\n');
|
||||
return result;
|
||||
}
|
||||
}
|
||||
export {
|
||||
BingSearch,
|
||||
GoogleSearch
|
||||
};
|
||||
export { BingSearch, GoogleSearch };
|
||||
|
@@ -14,13 +14,11 @@ import { hashPassword } from '@/service/utils/tools';
|
||||
/* uniform auth user */
|
||||
export const authUser = async ({
|
||||
req,
|
||||
userId = '',
|
||||
authToken = false,
|
||||
authOpenApi = false,
|
||||
authRoot = false
|
||||
}: {
|
||||
req: NextApiRequest;
|
||||
userId?: string;
|
||||
authToken?: boolean;
|
||||
authOpenApi?: boolean;
|
||||
authRoot?: boolean;
|
||||
@@ -68,17 +66,18 @@ export const authUser = async ({
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
const parseRootKey = async (rootKey?: string) => {
|
||||
if (!rootKey || !process.env.ROOT_KEY || rootKey !== process.env.ROOT_KEY) {
|
||||
const parseRootKey = async (rootKey?: string, userId?: string) => {
|
||||
if (!rootKey || !userId || !process.env.ROOT_KEY || rootKey !== process.env.ROOT_KEY) {
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
}
|
||||
return userId;
|
||||
};
|
||||
|
||||
const { cookie, apikey, rootkey } = (req.headers || {}) as {
|
||||
const { cookie, apikey, rootkey, userid } = (req.headers || {}) as {
|
||||
cookie?: string;
|
||||
apikey?: string;
|
||||
rootkey?: string;
|
||||
userid?: string;
|
||||
};
|
||||
|
||||
let uid = '';
|
||||
@@ -88,13 +87,13 @@ export const authUser = async ({
|
||||
} else if (authOpenApi) {
|
||||
uid = await parseOpenApiKey(apikey);
|
||||
} else if (authRoot) {
|
||||
uid = await parseRootKey(rootkey);
|
||||
uid = await parseRootKey(rootkey, userid);
|
||||
} else if (cookie) {
|
||||
uid = await parseCookie(cookie);
|
||||
} else if (apikey) {
|
||||
uid = await parseOpenApiKey(apikey);
|
||||
} else if (rootkey) {
|
||||
uid = await parseRootKey(rootkey);
|
||||
uid = await parseRootKey(rootkey, userid);
|
||||
} else {
|
||||
return Promise.reject(ERROR_ENUM.unAuthorization);
|
||||
}
|
||||
|
7
src/types/mongoSchema.d.ts
vendored
7
src/types/mongoSchema.d.ts
vendored
@@ -3,9 +3,11 @@ import {
|
||||
ModelStatusEnum,
|
||||
ModelNameEnum,
|
||||
ModelVectorSearchModeEnum,
|
||||
ChatModelType
|
||||
ChatModelType,
|
||||
EmbeddingModelType
|
||||
} from '@/constants/model';
|
||||
import type { DataType } from './data';
|
||||
import { BillTypeEnum } from '@/constants/user';
|
||||
|
||||
export interface UserModelSchema {
|
||||
_id: string;
|
||||
@@ -89,7 +91,8 @@ export interface ChatPopulate extends ChatSchema {
|
||||
export interface BillSchema {
|
||||
_id: string;
|
||||
userId: string;
|
||||
type: 'chat' | 'splitData' | 'return';
|
||||
type: `${BillTypeEnum}`;
|
||||
modelName: ChatModelType | EmbeddingModelType;
|
||||
chatId: string;
|
||||
time: Date;
|
||||
textLen: number;
|
||||
|
8
src/types/user.d.ts
vendored
8
src/types/user.d.ts
vendored
@@ -1,3 +1,4 @@
|
||||
import type { BillSchema } from './mongoSchema';
|
||||
export interface UserType {
|
||||
_id: string;
|
||||
username: string;
|
||||
@@ -17,11 +18,10 @@ export interface UserUpdateParams {
|
||||
|
||||
export interface UserBillType {
|
||||
id: string;
|
||||
time: string;
|
||||
type: 'chat' | 'splitData' | 'return';
|
||||
time: Date;
|
||||
modelName: BillSchema['modelName'];
|
||||
type: BillSchema['type'];
|
||||
textLen: number;
|
||||
tokenLen: number;
|
||||
userId: string;
|
||||
chatId: string;
|
||||
price: number;
|
||||
}
|
||||
|
@@ -7,9 +7,8 @@ export const adaptBill = (bill: BillSchema): UserBillType => {
|
||||
return {
|
||||
id: bill._id,
|
||||
type: bill.type,
|
||||
userId: bill.userId,
|
||||
chatId: bill.chatId,
|
||||
time: dayjs(bill.time).format('YYYY/MM/DD HH:mm:ss'),
|
||||
modelName: bill.modelName,
|
||||
time: bill.time,
|
||||
textLen: bill.textLen,
|
||||
tokenLen: bill.tokenLen,
|
||||
price: formatPrice(bill.price)
|
||||
|
Reference in New Issue
Block a user