feat: more sub plan info;fix: emprt index (#4997)

* feat: more sub plan info

* fix: emprt index

* doc
This commit is contained in:
Archer
2025-06-10 19:01:10 +08:00
committed by GitHub
parent ccae96a981
commit a848c2e3ba
26 changed files with 333 additions and 166 deletions

View File

@@ -45,6 +45,9 @@ export type TeamSubSchema = {
nextMode: `${SubModeEnum}`;
currentSubLevel: StandardSubLevelEnum;
nextSubLevel: StandardSubLevelEnum;
maxTeamMember?: number;
maxApp?: number;
maxDataset?: number;
totalPoints: number;
surplusPoints: number;
@@ -52,7 +55,7 @@ export type TeamSubSchema = {
currentExtraDatasetSize: number;
};
export type FeTeamPlanStatusType = {
export type TeamPlanStatusType = {
[SubTypeEnum.standard]?: TeamSubSchema;
standardConstants?: TeamStandardSubPlanItemType;
@@ -61,5 +64,11 @@ export type FeTeamPlanStatusType = {
// standard + extra
datasetMaxSize: number;
usedDatasetSize: number;
};
export type ClientTeamPlanStatusType = TeamPlanStatusType & {
usedMember: number;
usedAppAmount: number;
usedDatasetSize: number;
usedDatasetIndexSize: number;
};

View File

@@ -18,7 +18,7 @@ import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import type { ClientSession } from '../../../common/mongo';
import { createOrGetCollectionTags } from './utils';
import { rawText2Chunks } from '../read';
import { checkDatasetLimit } from '../../../support/permission/teamLimit';
import { checkDatasetIndexLimit } from '../../../support/permission/teamLimit';
import { predictDataLimitLength } from '../../../../global/core/dataset/utils';
import { mongoSessionRun } from '../../../common/mongo/sessionRun';
import { createTrainingUsage } from '../../../support/wallet/usage/controller';
@@ -166,7 +166,7 @@ export const createCollectionAndInsertData = async ({
})();
// 2. auth limit
await checkDatasetLimit({
await checkDatasetIndexLimit({
teamId,
insertLen: predictDataLimitLength(trainingMode, chunks)
});

View File

@@ -199,7 +199,7 @@ export const rawText2Chunks = async ({
.map((item) => ({
q: item[0] || '',
a: item[1] || '',
indexes: item.slice(2),
indexes: item.slice(2).filter((item) => item.trim()),
imageIdList
}))
.filter((item) => item.q || item.a);

View File

@@ -83,8 +83,7 @@ const TrainingDataSchema = new Schema({
enum: Object.values(DatasetDataIndexTypeEnum)
},
text: {
type: String,
required: true
type: String
}
}
],

View File

@@ -5,28 +5,9 @@ import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
import { SystemErrEnum } from '@fastgpt/global/common/error/code/system';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
export const checkDatasetLimit = async ({
teamId,
insertLen = 0
}: {
teamId: string;
insertLen?: number;
}) => {
const { standardConstants, totalPoints, usedPoints, datasetMaxSize, usedDatasetSize } =
await getTeamPlanStatus({ teamId });
if (!standardConstants) return;
if (usedDatasetSize + insertLen >= datasetMaxSize) {
return Promise.reject(TeamErrEnum.datasetSizeNotEnough);
}
if (usedPoints >= totalPoints) {
return Promise.reject(TeamErrEnum.aiPointsNotEnough);
}
return;
};
import { MongoTeamMember } from '../user/team/teamMemberSchema';
import { TeamMemberStatusEnum } from '@fastgpt/global/support/user/team/constant';
import { getVectorCountByTeamId } from '../../common/vectorDB/controller';
export const checkTeamAIPoints = async (teamId: string) => {
const { standardConstants, totalPoints, usedPoints } = await getTeamPlanStatus({
@@ -45,6 +26,72 @@ export const checkTeamAIPoints = async (teamId: string) => {
};
};
export const checkTeamMemberLimit = async (teamId: string, newCount: number) => {
const [{ standardConstants }, memberCount] = await Promise.all([
getTeamStandPlan({
teamId
}),
MongoTeamMember.countDocuments({
teamId,
status: { $ne: TeamMemberStatusEnum.leave }
})
]);
if (standardConstants && newCount + memberCount > standardConstants.maxTeamMember) {
return Promise.reject(TeamErrEnum.teamOverSize);
}
};
export const checkTeamAppLimit = async (teamId: string, amount = 1) => {
const [{ standardConstants }, appCount] = await Promise.all([
getTeamStandPlan({ teamId }),
MongoApp.countDocuments({
teamId,
type: {
$in: [AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.plugin, AppTypeEnum.tool]
}
})
]);
if (standardConstants && appCount + amount >= standardConstants.maxAppAmount) {
return Promise.reject(TeamErrEnum.appAmountNotEnough);
}
// System check
if (global?.licenseData?.maxApps && typeof global?.licenseData?.maxApps === 'number') {
const totalApps = await MongoApp.countDocuments({
type: {
$in: [AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.plugin, AppTypeEnum.tool]
}
});
if (totalApps >= global.licenseData.maxApps) {
return Promise.reject(SystemErrEnum.licenseAppAmountLimit);
}
}
};
export const checkDatasetIndexLimit = async ({
teamId,
insertLen = 0
}: {
teamId: string;
insertLen?: number;
}) => {
const [{ standardConstants, totalPoints, usedPoints, datasetMaxSize }, usedDatasetIndexSize] =
await Promise.all([getTeamPlanStatus({ teamId }), getVectorCountByTeamId(teamId)]);
if (!standardConstants) return;
if (usedDatasetIndexSize + insertLen >= datasetMaxSize) {
return Promise.reject(TeamErrEnum.datasetSizeNotEnough);
}
if (usedPoints >= totalPoints) {
return Promise.reject(TeamErrEnum.aiPointsNotEnough);
}
return;
};
export const checkTeamDatasetLimit = async (teamId: string) => {
const [{ standardConstants }, datasetCount] = await Promise.all([
getTeamStandPlan({ teamId }),
@@ -74,30 +121,12 @@ export const checkTeamDatasetLimit = async (teamId: string) => {
}
};
export const checkTeamAppLimit = async (teamId: string, amount = 1) => {
const [{ standardConstants }, appCount] = await Promise.all([
getTeamStandPlan({ teamId }),
MongoApp.countDocuments({
teamId,
type: {
$in: [AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.plugin, AppTypeEnum.tool]
}
})
]);
export const checkTeamWebSyncPermission = async (teamId: string) => {
const { standardConstants } = await getTeamStandPlan({
teamId
});
if (standardConstants && appCount + amount >= standardConstants.maxAppAmount) {
return Promise.reject(TeamErrEnum.appAmountNotEnough);
}
// System check
if (global?.licenseData?.maxApps && typeof global?.licenseData?.maxApps === 'number') {
const totalApps = await MongoApp.countDocuments({
type: {
$in: [AppTypeEnum.simple, AppTypeEnum.workflow, AppTypeEnum.plugin, AppTypeEnum.tool]
}
});
if (totalApps >= global.licenseData.maxApps) {
return Promise.reject(SystemErrEnum.licenseAppAmountLimit);
}
if (standardConstants && !standardConstants?.permissionWebsiteSync) {
return Promise.reject(TeamErrEnum.websiteSyncNotEnough);
}
};

View File

@@ -52,6 +52,9 @@ const SubSchema = new Schema({
type: String,
enum: Object.values(StandardSubLevelEnum)
},
maxTeamMember: Number,
maxApp: Number,
maxDataset: Number,
// stand sub and extra points sub. Plan total points
totalPoints: {

View File

@@ -6,10 +6,9 @@ import {
} from '@fastgpt/global/support/wallet/sub/constants';
import { MongoTeamSub } from './schema';
import {
type FeTeamPlanStatusType,
type TeamPlanStatusType,
type TeamSubSchema
} from '@fastgpt/global/support/wallet/sub/type.d';
import { getVectorCountByTeamId } from '../../../common/vectorDB/controller';
import dayjs from 'dayjs';
import { type ClientSession } from '../../../common/mongo';
import { addMonths } from 'date-fns';
@@ -44,12 +43,21 @@ export const getTeamStandPlan = async ({ teamId }: { teamId: string }) => {
const standardPlans = global.subPlans?.standard;
const standard = plans[0];
const standardConstants =
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]
: undefined;
return {
[SubTypeEnum.standard]: standard,
standardConstants:
standard?.currentSubLevel && standardPlans
? standardPlans[standard.currentSubLevel]
: undefined
standardConstants: standardConstants
? {
...standardConstants,
maxTeamMember: standard?.maxTeamMember || standardConstants.maxTeamMember,
maxAppAmount: standard?.maxApp || standardConstants.maxAppAmount,
maxDatasetAmount: standard?.maxDataset || standardConstants.maxDatasetAmount
}
: undefined
};
};
@@ -111,14 +119,11 @@ export const getTeamPlanStatus = async ({
teamId
}: {
teamId: string;
}): Promise<FeTeamPlanStatusType> => {
}): Promise<TeamPlanStatusType> => {
const standardPlans = global.subPlans?.standard;
/* Get all plans and datasetSize */
const [plans, usedDatasetSize] = await Promise.all([
MongoTeamSub.find({ teamId }).lean(),
getVectorCountByTeamId(teamId)
]);
const plans = await MongoTeamSub.find({ teamId }).lean();
/* Get all standardPlans and active standardPlan */
const teamStandardPlans = sortStandPlans(
@@ -158,17 +163,25 @@ export const getTeamPlanStatus = async ({
standardMaxDatasetSize +
extraDatasetSize.reduce((acc, cur) => acc + (cur.currentExtraDatasetSize || 0), 0);
const standardConstants =
standardPlan?.currentSubLevel && standardPlans
? standardPlans[standardPlan.currentSubLevel]
: undefined;
return {
[SubTypeEnum.standard]: standardPlan,
standardConstants:
standardPlan?.currentSubLevel && standardPlans
? standardPlans[standardPlan.currentSubLevel]
: undefined,
standardConstants: standardConstants
? {
...standardConstants,
maxTeamMember: standardPlan?.maxTeamMember || standardConstants.maxTeamMember,
maxAppAmount: standardPlan?.maxApp || standardConstants.maxAppAmount,
maxDatasetAmount: standardPlan?.maxDataset || standardConstants.maxDatasetAmount
}
: undefined,
totalPoints,
usedPoints: totalPoints - surplusPoints,
datasetMaxSize: totalDatasetSize,
usedDatasetSize
datasetMaxSize: totalDatasetSize
};
};

View File

@@ -14,7 +14,10 @@ export const getSafeEnv = () => {
return {
LOG_LEVEL: process.env.LOG_LEVEL,
STORE_LOG_LEVEL: process.env.STORE_LOG_LEVEL,
NODE_ENV: process.env.NODE_ENV
NODE_ENV: process.env.NODE_ENV,
HTTP_PROXY: process.env.HTTP_PROXY,
HTTPS_PROXY: process.env.HTTPS_PROXY,
NO_PROXY: process.env.NO_PROXY
};
};

View File

@@ -6,6 +6,7 @@
"ai_points_calculation_standard": "AI points",
"ai_points_usage": "AI points",
"ai_points_usage_tip": "Each time the AI model is called, a certain amount of AI points will be consumed. \nFor specific calculation standards, please refer to the \"Billing Standards\" above.",
"app_amount": "App amount",
"avatar": "Avatar",
"avatar_selection_exception": "Abnormal avatar selection",
"balance": "balance",
@@ -21,6 +22,7 @@
"contact_us": "Contact us",
"current_package": "Current plan",
"current_token_price": "Current points price",
"dataset_amount": "Dataset amount",
"effective_time": "Effective time",
"email_label": "Mail",
"exchange": "Exchange",
@@ -34,6 +36,7 @@
"help_document": "Help documentation",
"knowledge_base_capacity": "Dataset usages",
"manage": "Manage",
"member_amount": "Member amount",
"member_name": "Name",
"month": "moon",
"new_password": "New Password",

View File

@@ -215,7 +215,6 @@
"core.app.Interval timer run": "Scheduled Execution",
"core.app.Interval timer tip": "Can Execute App on Schedule",
"core.app.Make a brief introduction of your app": "Give Your AI App an Introduction",
"core.app.name": "name",
"core.app.Name and avatar": "Avatar & Name",
"core.app.Publish": "Publish",
"core.app.Publish Confirm": "Confirm to Publish App? This Will Immediately Update the App Status on All Publishing Channels.",
@@ -261,6 +260,7 @@
"core.app.have_saved": "Saved",
"core.app.logs.Source And Time": "Source & Time",
"core.app.more": "View More",
"core.app.name": "name",
"core.app.no_app": "No Apps Yet, Create One Now!",
"core.app.not_saved": "Not Saved",
"core.app.outLink.Can Drag": "Icon Can Be Dragged",
@@ -1145,10 +1145,10 @@
"support.wallet.subscription.Upgrade plan": "Upgrade Package",
"support.wallet.subscription.ai_model": "AI Language Model",
"support.wallet.subscription.function.History store": "{{amount}} Days of Chat History Retention",
"support.wallet.subscription.function.Max app": "{{amount}} Apps & Plugins",
"support.wallet.subscription.function.Max dataset": "{{amount}} Datasets",
"support.wallet.subscription.function.Max app": "{{amount}} App limit",
"support.wallet.subscription.function.Max dataset": "{{amount}} Dataset limit",
"support.wallet.subscription.function.Max dataset size": "{{amount}} Dataset Indexes",
"support.wallet.subscription.function.Max members": "{{amount}} Team Members",
"support.wallet.subscription.function.Max members": "{{amount}} Member limit",
"support.wallet.subscription.function.Points": "{{amount}} AI Points",
"support.wallet.subscription.mode.Month": "Month",
"support.wallet.subscription.mode.Period": "Subscription Period",

View File

@@ -6,6 +6,7 @@
"ai_points_calculation_standard": "AI 积分",
"ai_points_usage": "AI 积分使用量",
"ai_points_usage_tip": "每次调用 AI 模型时,都会消耗一定的 AI 积分。具体的计算标准可参考上方的“计费标准”。",
"app_amount": "应用数量",
"avatar": "头像",
"avatar_selection_exception": "头像选择异常",
"balance": "余额",
@@ -21,6 +22,7 @@
"contact_us": "联系我们",
"current_package": "当前套餐",
"current_token_price": "当前积分价格",
"dataset_amount": "知识库数量",
"effective_time": "生效时间",
"email_label": "邮箱",
"exchange": "兑换",
@@ -34,6 +36,7 @@
"help_document": "帮助文档",
"knowledge_base_capacity": "知识库容量",
"manage": "管理",
"member_amount": "成员数量",
"member_name": "成员名",
"month": "月",
"new_password": "新密码",
@@ -53,7 +56,9 @@
"please_bind_contact": "请绑定联系方式",
"please_bind_notification_receiving_path": "请先绑定通知接收途径",
"purchase_extra_package": "购买额外套餐",
"redeem_coupon": "兑换码",
"reminder_create_bound_notification_account": "提醒创建者绑定通知账号",
"reset_password": "重置密码",
"resource_usage": "资源用量",
"select_avatar": "点击选择头像",
"standard_package_and_extra_resource_package": "包含标准套餐与额外资源包",
@@ -65,7 +70,6 @@
"type": "类型",
"unlimited": "无限制",
"update_password": "修改密码",
"reset_password": "重置密码",
"update_success_tip": "更新数据成功",
"upgrade_package": "升级套餐",
"usage_balance": "使用余额: 使用余额",
@@ -74,6 +78,5 @@
"user_team_team_name": "团队",
"verification_code": "验证码",
"you_can_convert": "您可以兑换",
"yuan": "元",
"redeem_coupon": "兑换码"
"yuan": "元"
}

View File

@@ -1145,10 +1145,10 @@
"support.wallet.subscription.Upgrade plan": "升级套餐",
"support.wallet.subscription.ai_model": "AI语言模型",
"support.wallet.subscription.function.History store": "{{amount}} 天对话记录保留",
"support.wallet.subscription.function.Max app": "{{amount}} 个应用&插件",
"support.wallet.subscription.function.Max dataset": "{{amount}} 个知识库",
"support.wallet.subscription.function.Max app": "{{amount}} 个应用上限",
"support.wallet.subscription.function.Max dataset": "{{amount}} 个知识库上限",
"support.wallet.subscription.function.Max dataset size": "{{amount}} 组知识库索引",
"support.wallet.subscription.function.Max members": "{{amount}} 个团队成员",
"support.wallet.subscription.function.Max members": "{{amount}} 个团队成员上限",
"support.wallet.subscription.function.Points": "{{amount}} AI 积分",
"support.wallet.subscription.mode.Month": "按月",
"support.wallet.subscription.mode.Period": "订阅周期",

View File

@@ -6,6 +6,7 @@
"ai_points_calculation_standard": "AI 積分",
"ai_points_usage": "AI 積分使用量",
"ai_points_usage_tip": "每次呼叫 AI 模型時,都會消耗一定的 AI 積分。\n具體的計算標準可參考上方的「計費標準」。",
"app_amount": "應用數量",
"avatar": "頭像",
"avatar_selection_exception": "頭像選擇異常",
"balance": "餘額",
@@ -21,6 +22,7 @@
"contact_us": "聯絡我們",
"current_package": "目前套餐",
"current_token_price": "目前積分價格",
"dataset_amount": "知識庫數量",
"effective_time": "生效時間",
"email_label": "信箱",
"exchange": "兌換",
@@ -34,6 +36,7 @@
"help_document": "幫助文件",
"knowledge_base_capacity": "知識庫容量",
"manage": "管理",
"member_amount": "成員數量",
"member_name": "成員名",
"month": "月",
"new_password": "新密碼",

View File

@@ -215,7 +215,6 @@
"core.app.Interval timer run": "排程執行",
"core.app.Interval timer tip": "可排程執行應用程式",
"core.app.Make a brief introduction of your app": "為您的 AI 應用程式寫一段介紹",
"core.app.name": "名稱",
"core.app.Name and avatar": "頭像與名稱",
"core.app.Publish": "發布",
"core.app.Publish Confirm": "確認發布應用程式?這將立即更新所有發布管道的應用程式狀態。",
@@ -261,6 +260,7 @@
"core.app.have_saved": "已儲存",
"core.app.logs.Source And Time": "來源與時間",
"core.app.more": "檢視更多",
"core.app.name": "名稱",
"core.app.no_app": "還沒有應用程式,快來建立一個吧!",
"core.app.not_saved": "未儲存",
"core.app.outLink.Can Drag": "圖示可拖曳",
@@ -1145,8 +1145,8 @@
"support.wallet.subscription.Upgrade plan": "升級方案",
"support.wallet.subscription.ai_model": "AI 語言模型",
"support.wallet.subscription.function.History store": "{{amount}} 天對話紀錄保留",
"support.wallet.subscription.function.Max app": "{{amount}} 個應用程式與外掛程式",
"support.wallet.subscription.function.Max dataset": "{{amount}} 個知識庫",
"support.wallet.subscription.function.Max app": "{{amount}} 個應用上限",
"support.wallet.subscription.function.Max dataset": "{{amount}} 個知識庫上限",
"support.wallet.subscription.function.Max dataset size": "{{amount}} 組知識庫索引",
"support.wallet.subscription.function.Max members": "{{amount}} 個團隊成員",
"support.wallet.subscription.function.Points": "{{amount}} AI 點數",