mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-03 05:19:51 +00:00
V4.6.9-first commit (#899)
* perf: insert mongo dataset data session * perf: dataset data index * remove delay * rename bill schema * rename bill record * perf: bill table * perf: prompt * perf: sub plan * change the usage count * feat: usage bill * publish usages * doc * 新增团队聊天功能 (#20) * perf: doc * feat 添加标签部分 feat 信息团队标签配置 feat 新增团队同步管理 feat team分享页面 feat 完成team分享页面 feat 实现模糊搜索 style 格式化 fix 修复迷糊匹配 style 样式修改 fix 团队标签功能修复 * fix 修复鉴权功能 * merge 合并代码 * fix 修复引用错误 * fix 修复pr问题 * fix 修复ts格式问题 --------- Co-authored-by: archer <545436317@qq.com> Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> * update extra plan * fix: ts * format * perf: bill field * feat: standard plan * fix: ts * feat 个人账号页面修改 (#22) * feat 添加标签部分 feat 信息团队标签配置 feat 新增团队同步管理 feat team分享页面 feat 完成team分享页面 feat 实现模糊搜索 style 格式化 fix 修复迷糊匹配 style 样式修改 fix 团队标签功能修复 * fix 修复鉴权功能 * merge 合并代码 * fix 修复引用错误 * fix 修复pr问题 * fix 修复ts格式问题 * feat 修改个人账号页 --------- Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> * sub plan page (#23) * fix chunk index; error page text * feat: dataset process Integral prediction * feat: stand plan field * feat: sub plan limit * perf: index * query extension * perf: share link push app name * perf: plan point unit * perf: get sub plan * perf: account page * feat 新增套餐详情弹窗代码 (#24) * merge 合并代码 * fix 新增套餐详情弹框 * fix 修复pr问题 * feat: change http node input to prompt editor (#21) * feat: change http node input to prompt editor * fix * split PromptEditor to HttpInput * Team plans (#25) * perf: pay check * perf: team plan test * plan limit check * replace sensitive text * perf: fix some null * collection null check * perf: plans modal * perf: http module * pacakge (#26) * individuation page and pay modal amount (#27) * feat: individuation page * team chat config * pay modal * plan count and replace invalid chars (#29) * fix: user oneapi * fix: training queue * fix: qa queue * perf: remove space chars * replace invalid chars * change httpinput dropdown menu (#28) * perf: http * reseet free plan * perf: plan code to packages * remove llm config to package * perf: code * perf: faq * fix: get team plan --------- Co-authored-by: yst <77910600+yu-and-liu@users.noreply.github.com> Co-authored-by: liuxingwan <liuxingwan.lxw@alibaba-inc.com> Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
import { GET } from '@fastgpt/service/common/api/plusRequest';
|
||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
||||
|
||||
export const authTeamBalance = async (teamId: string) => {
|
||||
if (FastGPTProUrl) {
|
||||
return GET('/support/permission/authBalance', { teamId });
|
||||
}
|
||||
return true;
|
||||
};
|
@@ -6,7 +6,6 @@ import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
||||
import { authUserRole } from '@fastgpt/service/support/permission/auth/user';
|
||||
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
|
||||
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||
|
||||
/*
|
||||
outLink: Must be the owner
|
||||
token: team owner and chat owner have all permissions
|
||||
@@ -15,12 +14,14 @@ export async function autChatCrud({
|
||||
appId,
|
||||
chatId,
|
||||
shareId,
|
||||
shareTeamId,
|
||||
outLinkUid,
|
||||
per = 'owner',
|
||||
...props
|
||||
}: AuthModeType & {
|
||||
appId: string;
|
||||
chatId?: string;
|
||||
shareTeamId?: string;
|
||||
shareId?: string;
|
||||
outLinkUid?: string;
|
||||
}): Promise<{
|
||||
@@ -28,7 +29,7 @@ export async function autChatCrud({
|
||||
isOutLink: boolean;
|
||||
uid?: string;
|
||||
}> {
|
||||
const isOutLink = Boolean(shareId && outLinkUid);
|
||||
const isOutLink = Boolean((shareId || shareTeamId) && outLinkUid);
|
||||
if (!chatId) return { isOutLink, uid: outLinkUid };
|
||||
|
||||
const chat = await MongoChat.findOne({ appId, chatId }).lean();
|
||||
@@ -46,6 +47,11 @@ export async function autChatCrud({
|
||||
}
|
||||
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
}
|
||||
if (shareTeamId && outLinkUid) {
|
||||
if (chat.teamId == shareTeamId && chat.outLinkUid === outLinkUid) {
|
||||
return { uid: outLinkUid };
|
||||
}
|
||||
}
|
||||
|
||||
// req auth
|
||||
const { teamId, tmbId, role } = await authUserRole(props);
|
||||
|
@@ -24,6 +24,7 @@ export async function authDatasetData({
|
||||
|
||||
const data: DatasetDataItemType = {
|
||||
id: String(datasetData._id),
|
||||
teamId: datasetData.teamId,
|
||||
q: datasetData.q,
|
||||
a: datasetData.a,
|
||||
chunkIndex: datasetData.chunkIndex,
|
||||
|
@@ -6,7 +6,7 @@ import type {
|
||||
AuthOutLinkResponse
|
||||
} from '@fastgpt/global/support/outLink/api.d';
|
||||
import { authOutLinkValid } from '@fastgpt/service/support/permission/auth/outLink';
|
||||
import { getUserAndAuthBalance } from '@fastgpt/service/support/user/controller';
|
||||
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
|
||||
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { OutLinkErrEnum } from '@fastgpt/global/common/error/code/outLink';
|
||||
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
|
||||
@@ -58,13 +58,15 @@ export async function authOutLinkChatStart({
|
||||
// get outLink and app
|
||||
const { shareChat, appId } = await authOutLinkValid({ shareId });
|
||||
|
||||
// check balance and chat limit
|
||||
const [user, { uid }] = await Promise.all([
|
||||
getUserAndAuthBalance({ tmbId: shareChat.tmbId, minBalance: 0 }),
|
||||
// check ai points and chat limit
|
||||
const [{ user }, { uid }] = await Promise.all([
|
||||
getUserChatInfoAndAuthTeamPoints(shareChat.tmbId),
|
||||
authOutLinkChatLimit({ outLink: shareChat, ip, outLinkUid, question })
|
||||
]);
|
||||
|
||||
return {
|
||||
teamId: shareChat.teamId,
|
||||
tmbId: shareChat.tmbId,
|
||||
authType: AuthUserTypeEnum.token,
|
||||
responseDetail: shareChat.responseDetail,
|
||||
user,
|
||||
|
43
projects/app/src/service/support/permission/auth/team.ts
Normal file
43
projects/app/src/service/support/permission/auth/team.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { UserErrEnum } from '@fastgpt/global/common/error/code/user';
|
||||
import { TeamMemberWithUserSchema } from '@fastgpt/global/support/user/team/type';
|
||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
||||
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
|
||||
import { checkTeamAIPoints } from '@fastgpt/service/support/permission/teamLimit';
|
||||
import axios from 'axios';
|
||||
|
||||
export async function getUserChatInfoAndAuthTeamPoints(tmbId: string) {
|
||||
const tmb = (await MongoTeamMember.findById(tmbId, 'teamId userId').populate(
|
||||
'userId',
|
||||
'timezone openaiAccount'
|
||||
)) as TeamMemberWithUserSchema;
|
||||
if (!tmb) return Promise.reject(UserErrEnum.unAuthUser);
|
||||
|
||||
await checkTeamAIPoints(tmb.teamId);
|
||||
|
||||
return {
|
||||
user: tmb.userId
|
||||
};
|
||||
}
|
||||
|
||||
type UserInfoType = {
|
||||
data: {
|
||||
uid: string;
|
||||
tags: string[];
|
||||
};
|
||||
};
|
||||
|
||||
export async function getShareTeamUid(shareTeamId: string, authToken: string) {
|
||||
try {
|
||||
const teamInfo = await MongoTeam.findById(shareTeamId);
|
||||
const tagsUrl = teamInfo?.tagsUrl;
|
||||
const { data: userInfo } = await axios.post(tagsUrl + `/getUserInfo`, { autoken: authToken });
|
||||
|
||||
const uid = userInfo?.data?.uid;
|
||||
if (uid) {
|
||||
throw new Error('uid null');
|
||||
}
|
||||
return uid;
|
||||
} catch (err) {
|
||||
return '';
|
||||
}
|
||||
}
|
36
projects/app/src/service/support/permission/auth/teamChat.ts
Normal file
36
projects/app/src/service/support/permission/auth/teamChat.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
import type { AuthOutLinkChatProps } from '@fastgpt/global/support/outLink/api.d';
|
||||
import type { chatAppListSchema } from '@fastgpt/global/core/chat/type.d';
|
||||
import { getUserChatInfoAndAuthTeamPoints } from './team';
|
||||
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
|
||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
||||
|
||||
export function authChatTeamInfo(data: { shareTeamId: string; authToken: string }) {
|
||||
return POST<chatAppListSchema>('/core/chat/init', data);
|
||||
}
|
||||
|
||||
export async function authTeamShareChatStart({
|
||||
teamId,
|
||||
ip,
|
||||
outLinkUid,
|
||||
question
|
||||
}: AuthOutLinkChatProps & {
|
||||
teamId: string;
|
||||
}) {
|
||||
// get outLink and app
|
||||
const { teamInfo, uid } = await authChatTeamInfo({ shareTeamId: teamId, authToken: outLinkUid });
|
||||
// check balance and chat limit
|
||||
const tmb = await MongoTeamMember.findOne({ teamId, userId: String(teamInfo.ownerId) });
|
||||
|
||||
if (!tmb) {
|
||||
throw new Error('can not find it');
|
||||
}
|
||||
|
||||
const { user } = await getUserChatInfoAndAuthTeamPoints(String(tmb._id));
|
||||
|
||||
return {
|
||||
user,
|
||||
tmbId: String(tmb._id),
|
||||
uid: uid
|
||||
};
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
import { ConcatBillProps, CreateBillProps } from '@fastgpt/global/support/wallet/bill/api';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
||||
|
||||
export function createBill(data: CreateBillProps) {
|
||||
if (!FastGPTProUrl) return;
|
||||
if (data.total === 0) {
|
||||
addLog.info('0 Bill', data);
|
||||
}
|
||||
try {
|
||||
POST('/support/wallet/bill/createBill', data);
|
||||
} catch (error) {}
|
||||
}
|
||||
export function concatBill(data: ConcatBillProps) {
|
||||
if (!FastGPTProUrl) return;
|
||||
if (data.total === 0) {
|
||||
addLog.info('0 Bill', data);
|
||||
}
|
||||
try {
|
||||
POST('/support/wallet/bill/concatBill', data);
|
||||
} catch (error) {}
|
||||
}
|
@@ -1,327 +0,0 @@
|
||||
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
import { ModelTypeEnum } from '@/service/core/ai/model';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { PostReRankProps } from '@fastgpt/global/core/ai/api';
|
||||
import { createBill, concatBill } from './controller';
|
||||
import { formatModelPrice2Store } from '@/service/support/wallet/bill/utils';
|
||||
|
||||
export const pushChatBill = ({
|
||||
appName,
|
||||
appId,
|
||||
teamId,
|
||||
tmbId,
|
||||
source,
|
||||
response
|
||||
}: {
|
||||
appName: string;
|
||||
appId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
source: `${BillSourceEnum}`;
|
||||
response: ChatHistoryItemResType[];
|
||||
}) => {
|
||||
const total = response.reduce((sum, item) => sum + (item.price || 0), 0);
|
||||
|
||||
createBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName,
|
||||
appId,
|
||||
total,
|
||||
source,
|
||||
list: response.map((item) => ({
|
||||
moduleName: item.moduleName,
|
||||
amount: item.price || 0,
|
||||
model: item.model,
|
||||
inputTokens: item.inputTokens,
|
||||
outputTokens: item.outputTokens,
|
||||
charsLength: item.charsLength
|
||||
}))
|
||||
});
|
||||
addLog.info(`finish completions`, {
|
||||
source,
|
||||
teamId,
|
||||
tmbId,
|
||||
price: formatStorePrice2Read(total)
|
||||
});
|
||||
return { total };
|
||||
};
|
||||
|
||||
export const pushQABill = async ({
|
||||
teamId,
|
||||
tmbId,
|
||||
model,
|
||||
charsLength,
|
||||
billId
|
||||
}: {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
model: string;
|
||||
charsLength: number;
|
||||
billId: string;
|
||||
}) => {
|
||||
// 计算价格
|
||||
const { total } = formatModelPrice2Store({
|
||||
model,
|
||||
inputLen: charsLength,
|
||||
type: ModelTypeEnum.llm
|
||||
});
|
||||
|
||||
concatBill({
|
||||
billId,
|
||||
teamId,
|
||||
tmbId,
|
||||
total,
|
||||
charsLength,
|
||||
listIndex: 1
|
||||
});
|
||||
|
||||
return { total };
|
||||
};
|
||||
|
||||
export const pushGenerateVectorBill = ({
|
||||
billId,
|
||||
teamId,
|
||||
tmbId,
|
||||
charsLength,
|
||||
model,
|
||||
source = BillSourceEnum.fastgpt,
|
||||
extensionModel,
|
||||
extensionInputTokens,
|
||||
extensionOutputTokens
|
||||
}: {
|
||||
billId?: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
charsLength: number;
|
||||
model: string;
|
||||
source?: `${BillSourceEnum}`;
|
||||
|
||||
extensionModel?: string;
|
||||
extensionInputTokens?: number;
|
||||
extensionOutputTokens?: number;
|
||||
}) => {
|
||||
const { total: totalVector, modelName: vectorModelName } = formatModelPrice2Store({
|
||||
model,
|
||||
inputLen: charsLength,
|
||||
type: ModelTypeEnum.vector
|
||||
});
|
||||
|
||||
const { extensionTotal, extensionModelName } = (() => {
|
||||
if (!extensionModel || !extensionInputTokens || !extensionOutputTokens)
|
||||
return {
|
||||
extensionTotal: 0,
|
||||
extensionModelName: ''
|
||||
};
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model: extensionModel,
|
||||
inputLen: extensionInputTokens,
|
||||
outputLen: extensionOutputTokens,
|
||||
type: ModelTypeEnum.llm
|
||||
});
|
||||
return {
|
||||
extensionTotal: total,
|
||||
extensionModelName: modelName
|
||||
};
|
||||
})();
|
||||
|
||||
const total = totalVector + extensionTotal;
|
||||
|
||||
// 插入 Bill 记录
|
||||
if (billId) {
|
||||
concatBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
total: totalVector,
|
||||
billId,
|
||||
charsLength,
|
||||
listIndex: 0
|
||||
});
|
||||
} else {
|
||||
createBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: 'wallet.moduleName.index',
|
||||
total,
|
||||
source,
|
||||
list: [
|
||||
{
|
||||
moduleName: 'wallet.moduleName.index',
|
||||
amount: totalVector,
|
||||
model: vectorModelName,
|
||||
charsLength
|
||||
},
|
||||
...(extensionModel !== undefined
|
||||
? [
|
||||
{
|
||||
moduleName: 'core.module.template.Query extension',
|
||||
amount: extensionTotal,
|
||||
model: extensionModelName,
|
||||
inputTokens: extensionInputTokens,
|
||||
outputTokens: extensionOutputTokens
|
||||
}
|
||||
]
|
||||
: [])
|
||||
]
|
||||
});
|
||||
}
|
||||
return { total };
|
||||
};
|
||||
|
||||
export const pushQuestionGuideBill = ({
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
teamId,
|
||||
tmbId
|
||||
}: {
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
}) => {
|
||||
const qgModel = global.llmModels[0];
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
inputLen: inputTokens,
|
||||
outputLen: outputTokens,
|
||||
model: qgModel.model,
|
||||
type: ModelTypeEnum.llm
|
||||
});
|
||||
|
||||
createBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: 'wallet.bill.Next Step Guide',
|
||||
total,
|
||||
source: BillSourceEnum.fastgpt,
|
||||
list: [
|
||||
{
|
||||
moduleName: 'wallet.bill.Next Step Guide',
|
||||
amount: total,
|
||||
model: modelName,
|
||||
inputTokens,
|
||||
outputTokens
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
export function pushAudioSpeechBill({
|
||||
appName = 'wallet.bill.Audio Speech',
|
||||
model,
|
||||
charsLength,
|
||||
teamId,
|
||||
tmbId,
|
||||
source = BillSourceEnum.fastgpt
|
||||
}: {
|
||||
appName?: string;
|
||||
model: string;
|
||||
charsLength: number;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
source: `${BillSourceEnum}`;
|
||||
}) {
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model,
|
||||
inputLen: charsLength,
|
||||
type: ModelTypeEnum.audioSpeech
|
||||
});
|
||||
|
||||
createBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName,
|
||||
total,
|
||||
source,
|
||||
list: [
|
||||
{
|
||||
moduleName: appName,
|
||||
amount: total,
|
||||
model: modelName,
|
||||
charsLength
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
export function pushWhisperBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
duration
|
||||
}: {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
duration: number;
|
||||
}) {
|
||||
const whisperModel = global.whisperModel;
|
||||
|
||||
if (!whisperModel) return;
|
||||
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model: whisperModel.model,
|
||||
inputLen: duration,
|
||||
type: ModelTypeEnum.whisper,
|
||||
multiple: 60
|
||||
});
|
||||
|
||||
const name = 'wallet.bill.Whisper';
|
||||
|
||||
createBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: name,
|
||||
total,
|
||||
source: BillSourceEnum.fastgpt,
|
||||
list: [
|
||||
{
|
||||
moduleName: name,
|
||||
amount: total,
|
||||
model: modelName,
|
||||
duration
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
export function pushReRankBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
source,
|
||||
inputs
|
||||
}: {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
source: `${BillSourceEnum}`;
|
||||
inputs: PostReRankProps['inputs'];
|
||||
}) {
|
||||
const reRankModel = global.reRankModels[0];
|
||||
if (!reRankModel) return { total: 0 };
|
||||
|
||||
const charsLength = inputs.reduce((sum, item) => sum + item.text.length, 0);
|
||||
|
||||
const { total, modelName } = formatModelPrice2Store({
|
||||
model: reRankModel.model,
|
||||
inputLen: charsLength,
|
||||
type: ModelTypeEnum.rerank
|
||||
});
|
||||
const name = 'wallet.bill.ReRank';
|
||||
|
||||
createBill({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: name,
|
||||
total,
|
||||
source,
|
||||
list: [
|
||||
{
|
||||
moduleName: name,
|
||||
amount: total,
|
||||
model: modelName,
|
||||
charsLength
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
return { total };
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
import { ModelTypeEnum, getModelMap } from '@/service/core/ai/model';
|
||||
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { BillSourceEnum, PRICE_SCALE } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
|
||||
export function authType2BillSource({
|
||||
authType,
|
||||
shareId,
|
||||
source
|
||||
}: {
|
||||
authType?: `${AuthUserTypeEnum}`;
|
||||
shareId?: string;
|
||||
source?: `${BillSourceEnum}`;
|
||||
}) {
|
||||
if (source) return source;
|
||||
if (shareId) return BillSourceEnum.shareLink;
|
||||
if (authType === AuthUserTypeEnum.apikey) return BillSourceEnum.api;
|
||||
return BillSourceEnum.fastgpt;
|
||||
}
|
||||
|
||||
export const formatModelPrice2Store = ({
|
||||
model,
|
||||
inputLen = 0,
|
||||
outputLen = 0,
|
||||
type,
|
||||
multiple = 1000
|
||||
}: {
|
||||
model: string;
|
||||
inputLen: number;
|
||||
outputLen?: number;
|
||||
type: `${ModelTypeEnum}`;
|
||||
multiple?: number;
|
||||
}) => {
|
||||
const modelData = getModelMap?.[type]?.(model);
|
||||
if (!modelData)
|
||||
return {
|
||||
inputTotal: 0,
|
||||
outputTotal: 0,
|
||||
total: 0,
|
||||
modelName: ''
|
||||
};
|
||||
const inputTotal = modelData.inputPrice
|
||||
? Math.ceil(modelData.inputPrice * (inputLen / multiple) * PRICE_SCALE)
|
||||
: 0;
|
||||
const outputTotal = modelData.outputPrice
|
||||
? Math.ceil(modelData.outputPrice * (outputLen / multiple) * PRICE_SCALE)
|
||||
: 0;
|
||||
|
||||
return {
|
||||
modelName: modelData.name,
|
||||
inputTotal: inputTotal,
|
||||
outputTotal: outputTotal,
|
||||
total: inputTotal + outputTotal
|
||||
};
|
||||
};
|
23
projects/app/src/service/support/wallet/usage/controller.ts
Normal file
23
projects/app/src/service/support/wallet/usage/controller.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ConcatUsageProps, CreateUsageProps } from '@fastgpt/global/support/wallet/usage/api';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
import { FastGPTProUrl } from '@fastgpt/service/common/system/constants';
|
||||
|
||||
export function createUsage(data: CreateUsageProps) {
|
||||
if (!FastGPTProUrl) return;
|
||||
if (data.totalPoints === 0) {
|
||||
addLog.info('0 totalPoints', data);
|
||||
}
|
||||
try {
|
||||
POST('/support/wallet/usage/createUsage', data);
|
||||
} catch (error) {}
|
||||
}
|
||||
export function concatUsage(data: ConcatUsageProps) {
|
||||
if (!FastGPTProUrl) return;
|
||||
if (data.totalPoints === 0) {
|
||||
addLog.info('0 totalPoints', data);
|
||||
}
|
||||
try {
|
||||
POST('/support/wallet/usage/concatUsage', data);
|
||||
} catch (error) {}
|
||||
}
|
274
projects/app/src/service/support/wallet/usage/push.ts
Normal file
274
projects/app/src/service/support/wallet/usage/push.ts
Normal file
@@ -0,0 +1,274 @@
|
||||
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
||||
import { ModelTypeEnum } from '@fastgpt/service/core/ai/model';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { createUsage, concatUsage } from './controller';
|
||||
import { formatModelChars2Points } from '@/service/support/wallet/usage/utils';
|
||||
import { ChatModuleBillType } from '@fastgpt/global/support/wallet/bill/type';
|
||||
|
||||
export const pushChatUsage = ({
|
||||
appName,
|
||||
appId,
|
||||
teamId,
|
||||
tmbId,
|
||||
source,
|
||||
moduleDispatchBills
|
||||
}: {
|
||||
appName: string;
|
||||
appId: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
source: `${UsageSourceEnum}`;
|
||||
moduleDispatchBills: ChatModuleBillType[];
|
||||
}) => {
|
||||
const totalPoints = moduleDispatchBills.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
|
||||
|
||||
createUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName,
|
||||
appId,
|
||||
totalPoints,
|
||||
source,
|
||||
list: moduleDispatchBills.map((item) => ({
|
||||
moduleName: item.moduleName,
|
||||
amount: item.totalPoints || 0,
|
||||
model: item.model,
|
||||
charsLength: item.charsLength
|
||||
}))
|
||||
});
|
||||
addLog.info(`finish completions`, {
|
||||
source,
|
||||
teamId,
|
||||
tmbId,
|
||||
totalPoints
|
||||
});
|
||||
return { totalPoints };
|
||||
};
|
||||
|
||||
export const pushQAUsage = async ({
|
||||
teamId,
|
||||
tmbId,
|
||||
model,
|
||||
charsLength,
|
||||
billId
|
||||
}: {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
model: string;
|
||||
charsLength: number;
|
||||
billId: string;
|
||||
}) => {
|
||||
// 计算价格
|
||||
const { totalPoints } = formatModelChars2Points({
|
||||
model,
|
||||
modelType: ModelTypeEnum.llm,
|
||||
charsLength
|
||||
});
|
||||
|
||||
concatUsage({
|
||||
billId,
|
||||
teamId,
|
||||
tmbId,
|
||||
totalPoints,
|
||||
charsLength,
|
||||
listIndex: 1
|
||||
});
|
||||
|
||||
return { totalPoints };
|
||||
};
|
||||
|
||||
export const pushGenerateVectorUsage = ({
|
||||
billId,
|
||||
teamId,
|
||||
tmbId,
|
||||
charsLength,
|
||||
model,
|
||||
source = UsageSourceEnum.fastgpt,
|
||||
extensionModel,
|
||||
extensionCharsLength
|
||||
}: {
|
||||
billId?: string;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
charsLength: number;
|
||||
model: string;
|
||||
source?: `${UsageSourceEnum}`;
|
||||
|
||||
extensionModel?: string;
|
||||
extensionCharsLength?: number;
|
||||
}) => {
|
||||
const { totalPoints: totalVector, modelName: vectorModelName } = formatModelChars2Points({
|
||||
modelType: ModelTypeEnum.vector,
|
||||
model,
|
||||
charsLength
|
||||
});
|
||||
|
||||
const { extensionTotalPoints, extensionModelName } = (() => {
|
||||
if (!extensionModel || !extensionCharsLength)
|
||||
return {
|
||||
extensionTotalPoints: 0,
|
||||
extensionModelName: ''
|
||||
};
|
||||
const { totalPoints, modelName } = formatModelChars2Points({
|
||||
modelType: ModelTypeEnum.llm,
|
||||
model: extensionModel,
|
||||
charsLength: extensionCharsLength
|
||||
});
|
||||
return {
|
||||
extensionTotalPoints: totalPoints,
|
||||
extensionModelName: modelName
|
||||
};
|
||||
})();
|
||||
|
||||
const totalPoints = totalVector + extensionTotalPoints;
|
||||
|
||||
// 插入 Bill 记录
|
||||
if (billId) {
|
||||
concatUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
totalPoints,
|
||||
billId,
|
||||
charsLength,
|
||||
listIndex: 0
|
||||
});
|
||||
} else {
|
||||
createUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: 'support.wallet.moduleName.index',
|
||||
totalPoints,
|
||||
source,
|
||||
list: [
|
||||
{
|
||||
moduleName: 'support.wallet.moduleName.index',
|
||||
amount: totalVector,
|
||||
model: vectorModelName,
|
||||
charsLength
|
||||
},
|
||||
...(extensionModel !== undefined
|
||||
? [
|
||||
{
|
||||
moduleName: 'core.module.template.Query extension',
|
||||
amount: extensionTotalPoints,
|
||||
model: extensionModelName,
|
||||
charsLength: extensionCharsLength
|
||||
}
|
||||
]
|
||||
: [])
|
||||
]
|
||||
});
|
||||
}
|
||||
return { totalPoints };
|
||||
};
|
||||
|
||||
export const pushQuestionGuideUsage = ({
|
||||
charsLength,
|
||||
teamId,
|
||||
tmbId
|
||||
}: {
|
||||
charsLength: number;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
}) => {
|
||||
const qgModel = global.llmModels[0];
|
||||
const { totalPoints, modelName } = formatModelChars2Points({
|
||||
charsLength,
|
||||
model: qgModel.model,
|
||||
modelType: ModelTypeEnum.llm
|
||||
});
|
||||
|
||||
createUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: 'core.app.Next Step Guide',
|
||||
totalPoints,
|
||||
source: UsageSourceEnum.fastgpt,
|
||||
list: [
|
||||
{
|
||||
moduleName: 'core.app.Next Step Guide',
|
||||
amount: totalPoints,
|
||||
model: modelName,
|
||||
charsLength
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
export function pushAudioSpeechUsage({
|
||||
appName = 'support.wallet.bill.Audio Speech',
|
||||
model,
|
||||
charsLength,
|
||||
teamId,
|
||||
tmbId,
|
||||
source = UsageSourceEnum.fastgpt
|
||||
}: {
|
||||
appName?: string;
|
||||
model: string;
|
||||
charsLength: number;
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
source: `${UsageSourceEnum}`;
|
||||
}) {
|
||||
const { totalPoints, modelName } = formatModelChars2Points({
|
||||
model,
|
||||
charsLength,
|
||||
modelType: ModelTypeEnum.audioSpeech
|
||||
});
|
||||
|
||||
createUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName,
|
||||
totalPoints,
|
||||
source,
|
||||
list: [
|
||||
{
|
||||
moduleName: appName,
|
||||
amount: totalPoints,
|
||||
model: modelName,
|
||||
charsLength
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
export function pushWhisperUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
duration
|
||||
}: {
|
||||
teamId: string;
|
||||
tmbId: string;
|
||||
duration: number;
|
||||
}) {
|
||||
const whisperModel = global.whisperModel;
|
||||
|
||||
if (!whisperModel) return;
|
||||
|
||||
const { totalPoints, modelName } = formatModelChars2Points({
|
||||
model: whisperModel.model,
|
||||
charsLength: duration,
|
||||
modelType: ModelTypeEnum.whisper,
|
||||
multiple: 60
|
||||
});
|
||||
|
||||
const name = 'support.wallet.bill.Whisper';
|
||||
|
||||
createUsage({
|
||||
teamId,
|
||||
tmbId,
|
||||
appName: name,
|
||||
totalPoints,
|
||||
source: UsageSourceEnum.fastgpt,
|
||||
list: [
|
||||
{
|
||||
moduleName: name,
|
||||
amount: totalPoints,
|
||||
model: modelName,
|
||||
duration
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
44
projects/app/src/service/support/wallet/usage/utils.ts
Normal file
44
projects/app/src/service/support/wallet/usage/utils.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { ModelTypeEnum, getModelMap } from '@fastgpt/service/core/ai/model';
|
||||
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
||||
|
||||
export function authType2UsageSource({
|
||||
authType,
|
||||
shareId,
|
||||
source
|
||||
}: {
|
||||
authType?: `${AuthUserTypeEnum}`;
|
||||
shareId?: string;
|
||||
source?: `${UsageSourceEnum}`;
|
||||
}) {
|
||||
if (source) return source;
|
||||
if (shareId) return UsageSourceEnum.shareLink;
|
||||
if (authType === AuthUserTypeEnum.apikey) return UsageSourceEnum.api;
|
||||
return UsageSourceEnum.fastgpt;
|
||||
}
|
||||
|
||||
export const formatModelChars2Points = ({
|
||||
model,
|
||||
charsLength = 0,
|
||||
modelType,
|
||||
multiple = 1000
|
||||
}: {
|
||||
model: string;
|
||||
charsLength: number;
|
||||
modelType: `${ModelTypeEnum}`;
|
||||
multiple?: number;
|
||||
}) => {
|
||||
const modelData = getModelMap?.[modelType]?.(model);
|
||||
if (!modelData)
|
||||
return {
|
||||
totalPoints: 0,
|
||||
modelName: ''
|
||||
};
|
||||
|
||||
const totalPoints = (modelData.charsPointsPrice || 0) * (charsLength / multiple);
|
||||
|
||||
return {
|
||||
modelName: modelData.name,
|
||||
totalPoints
|
||||
};
|
||||
};
|
Reference in New Issue
Block a user