mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-10 06:39:01 +02:00
Adding More Ai Quota Tiers (#32128)
* feat: adding tiers for free and standard * feat: updating feature calculation to account for more quota tiers * feat: rename freeTrialQuota to freeQuota * feat: add hasAiFreeTier and hasUnlimitedAi to editor, block free tier from using workbench * fix: updating tests * fix: updating ordering precedence for quota tiers * feat: bump unlimited ai fair usage to 300 uses * fix: update workbench quota usage for unlimited plans * feat: bump features version for ai quota split * feat: popover should only show for relevant users on workbench, and adding upgrade notification to ineligible users GitOrigin-RevId: e3ef38797f267677cad51d7273272623027ca330
This commit is contained in:
committed by
Copybot
parent
e4e4193d55
commit
c87fd5c42e
@@ -964,6 +964,12 @@ const _ProjectController = {
|
||||
showAiFeatures,
|
||||
onAiFreeTrial:
|
||||
fullFeatureSet?.aiUsageQuota === Settings.aiFeatures?.freeTrialQuota,
|
||||
// default to free tier if they dont have a quota
|
||||
hasAiFreeTier:
|
||||
fullFeatureSet?.aiUsageQuota === Settings.aiFeatures?.freeQuota ||
|
||||
!fullFeatureSet?.aiUsageQuota,
|
||||
hasUnlimitedAi:
|
||||
fullFeatureSet?.aiUsageQuota === Settings.aiFeatures?.unlimitedQuota,
|
||||
detachRole,
|
||||
metadata: { viewport: false },
|
||||
showUpgradePrompt,
|
||||
|
||||
@@ -39,14 +39,12 @@ function mergeFeatures(featuresA, featuresB) {
|
||||
featuresB.compileTimeout || 0
|
||||
)
|
||||
} else if (key === 'aiUsageQuota') {
|
||||
if (
|
||||
features.aiUsageQuota === Settings.aiFeatures.unlimitedQuota ||
|
||||
featuresB.aiUsageQuota === Settings.aiFeatures.unlimitedQuota
|
||||
) {
|
||||
features.aiUsageQuota = Settings.aiFeatures.unlimitedQuota
|
||||
} else {
|
||||
features.aiUsageQuota = Settings.aiFeatures.freeTrialQuota
|
||||
}
|
||||
// later entries have higher precedence
|
||||
const QUOTA_TIER_LIST = ['free', 'basic', 'standard', 'unlimited']
|
||||
const quotaA = QUOTA_TIER_LIST.indexOf(features.aiUsageQuota)
|
||||
const quotaB = QUOTA_TIER_LIST.indexOf(featuresB.aiUsageQuota)
|
||||
features.aiUsageQuota =
|
||||
quotaA > quotaB ? features.aiUsageQuota : featuresB.aiUsageQuota
|
||||
} else {
|
||||
// Boolean keys, true is better
|
||||
features[key] = features[key] || featuresB[key]
|
||||
|
||||
@@ -30,7 +30,7 @@ class AiFeatureUsageRateLimiter extends FeatureUsageRateLimiter {
|
||||
if (inQuotaSplitTest) {
|
||||
const wfQuota = user.writefull?.isPremium
|
||||
? Settings.writefull.quotaTierGranted
|
||||
: Settings.aiFeatures.freeTrialQuota
|
||||
: Settings.aiFeatures.freeQuota
|
||||
const mergedFeatures = FeaturesHelper.mergeFeatures(user.features, {
|
||||
aiUsageQuota: wfQuota,
|
||||
})
|
||||
|
||||
@@ -25,7 +25,8 @@ meta(name="ol-debugPdfDetach" data-type="boolean" content=debugPdfDetach)
|
||||
meta(name="ol-showSymbolPalette" data-type="boolean" content=showSymbolPalette)
|
||||
meta(name="ol-symbolPaletteAvailable" data-type="boolean" content=symbolPaletteAvailable)
|
||||
meta(name="ol-showAiFeatures" data-type="boolean" content=showAiFeatures)
|
||||
meta(name="ol-onAiFreeTrial" data-type="boolean" content=onAiFreeTrial)
|
||||
meta(name="ol-hasUnlimitedAi" data-type="boolean" content=hasUnlimitedAi)
|
||||
meta(name="ol-hasAiFreeTier" data-type="boolean" content=hasAiFreeTier)
|
||||
meta(name="ol-detachRole" data-type="string" content=detachRole)
|
||||
meta(name="ol-imageNames" data-type="json" content=imageNames)
|
||||
meta(name="ol-languages" data-type="json" content=languages)
|
||||
|
||||
@@ -425,10 +425,21 @@ module.exports = {
|
||||
},
|
||||
|
||||
aiFeatures: {
|
||||
freeTrialQuota: 'basic',
|
||||
freeQuota: 'free',
|
||||
standardQuota: 'standard',
|
||||
basicQuota: 'basic',
|
||||
unlimitedQuota: 'unlimited',
|
||||
},
|
||||
|
||||
quotaGrants: {
|
||||
ai: {
|
||||
free: 0,
|
||||
basic: 0,
|
||||
standard: 0,
|
||||
unlimited: 0,
|
||||
},
|
||||
},
|
||||
|
||||
groupPlanModalOptions: {
|
||||
plan_codes: [],
|
||||
currencies: [],
|
||||
|
||||
@@ -710,6 +710,7 @@
|
||||
"get_most_subscription_by_checking_overleaf_ai_writefull": "",
|
||||
"get_real_time_track_changes": "",
|
||||
"get_unlimited_ai": "",
|
||||
"get_your_hands_on_the_ultimate_research_writing_ai_assistant": "",
|
||||
"git": "",
|
||||
"git_authentication_token": "",
|
||||
"git_authentication_token_create_modal_info_1": "",
|
||||
@@ -2139,6 +2140,7 @@
|
||||
"upgrade_to_add_more_collaborators_and_access_collaboration_features": "",
|
||||
"upgrade_to_add_more_collaborators_and_more": "",
|
||||
"upgrade_to_get_feature": "",
|
||||
"upgrade_to_get_started": "",
|
||||
"upgrade_to_review": "",
|
||||
"upgrade_your_subscription": "",
|
||||
"upload": "",
|
||||
|
||||
@@ -7,7 +7,7 @@ import { formatSecondsToHoursAndMinutes } from '@/shared/utils/time'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
import getMeta from '@/utils/meta'
|
||||
const onAiFreeTrial = getMeta('ol-onAiFreeTrial')
|
||||
const hasUnlimitedAi = getMeta('ol-hasUnlimitedAi')
|
||||
|
||||
type aiFeatureLocations = 'errorAssist' | 'workbench'
|
||||
|
||||
@@ -33,8 +33,8 @@ function AiPaywallNotification({
|
||||
return null
|
||||
}
|
||||
|
||||
// todo: quota clean-up: remove once we are transitioned off aiErrorAssistant naming and replace with just !onAiFreeTrial, also remove null FF check
|
||||
const hasAddOn = !onAiFreeTrial || Boolean(features?.aiErrorAssistant)
|
||||
// todo: quota clean-up: remove once we are transitioned off aiErrorAssistant naming and replace with just hasUnlimitedAi, also remove null FF check
|
||||
const hasAddOn = hasUnlimitedAi || Boolean(features?.aiErrorAssistant)
|
||||
|
||||
// error assist only needs usage quota
|
||||
const canUseErrorAssist = hasSuggestionsLeft
|
||||
|
||||
@@ -15,7 +15,7 @@ import getMeta from '@/utils/meta'
|
||||
|
||||
export const UserFeaturesContext = createContext<User['features']>(undefined)
|
||||
|
||||
const onAiFreeTrial = getMeta('ol-onAiFreeTrial')
|
||||
const hasUnlimitedAi = getMeta('ol-hasUnlimitedAi')
|
||||
|
||||
export const UserFeaturesProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
@@ -35,7 +35,7 @@ export const UserFeaturesProvider: FC<React.PropsWithChildren> = ({
|
||||
useEffect(() => {
|
||||
const listener = async ({ isPremium }: { isPremium: boolean }) => {
|
||||
// todo: quota clean-up: remove once we are transitioned off aiErrorAssistant naming
|
||||
const hasPremiumQuota = !onAiFreeTrial
|
||||
const hasPremiumQuota = hasUnlimitedAi
|
||||
const alreadyPremium =
|
||||
features?.aiErrorAssistant === isPremium ||
|
||||
hasPremiumQuota === isPremium
|
||||
|
||||
@@ -152,6 +152,7 @@ export interface Meta {
|
||||
'ol-groupSubscriptionsPendingEnrollment': PendingGroupSubscriptionEnrollment[]
|
||||
'ol-groupsAndEnterpriseBannerVariant': GroupsAndEnterpriseBannerVariant
|
||||
'ol-hasAiAssistViaWritefull': boolean
|
||||
'ol-hasAiFreeTier': boolean
|
||||
'ol-hasGroupSSOFeature': boolean
|
||||
'ol-hasIndividualPaidSubscription': boolean
|
||||
'ol-hasManagedUsersFeature': boolean
|
||||
@@ -160,6 +161,7 @@ export interface Meta {
|
||||
'ol-hasSplitTestWriteAccess': boolean
|
||||
'ol-hasSubscription': boolean
|
||||
'ol-hasTrackChangesFeature': boolean
|
||||
'ol-hasUnlimitedAi': boolean
|
||||
'ol-hasWriteAccess': boolean
|
||||
'ol-hideLinkingWidgets': boolean // CI only
|
||||
'ol-historyBlobStats': {
|
||||
@@ -221,7 +223,6 @@ export interface Meta {
|
||||
'ol-notificationsInstitution': InstitutionType[]
|
||||
'ol-oauthProviders': OAuthProviders
|
||||
'ol-odcData': OnboardingFormData
|
||||
'ol-onAiFreeTrial': boolean
|
||||
'ol-otMigrationStage': number
|
||||
'ol-overallThemes': OverallThemeMeta[]
|
||||
'ol-ownerIsManaged': boolean
|
||||
|
||||
@@ -913,6 +913,7 @@
|
||||
"get_real_time_track_changes": "Get real-time track changes",
|
||||
"get_the_best_overleaf_experience": "Get the best Overleaf experience",
|
||||
"get_unlimited_ai": "Get unlimited use of AI features",
|
||||
"get_your_hands_on_the_ultimate_research_writing_ai_assistant": "Get your hands on the ultimate research writing AI assistant.",
|
||||
"git": "Git",
|
||||
"git_authentication_token": "Git authentication token",
|
||||
"git_authentication_token_create_modal_info_1": "This is your Git authentication token. You should enter this when prompted for a password.",
|
||||
@@ -2691,6 +2692,7 @@
|
||||
"upgrade_to_add_more_collaborators_and_more": "Upgrade to add more collaborators and access features like Overleaf AI, track changes, and full project history.",
|
||||
"upgrade_to_get_feature": "Upgrade to get __feature__, plus:",
|
||||
"upgrade_to_get_more_from_overleaf": "Upgrade to get more from Overleaf",
|
||||
"upgrade_to_get_started": "Upgrade to get started",
|
||||
"upgrade_to_review": "Upgrade to Review",
|
||||
"upgrade_your_subscription": "Upgrade your subscription",
|
||||
"upload": "Upload",
|
||||
|
||||
@@ -34,9 +34,19 @@ describe('InstitutionsFeatures', function () {
|
||||
quotaTierGranted: 'unlimited',
|
||||
},
|
||||
aiFeatures: {
|
||||
freeTrialQuota: 'basic',
|
||||
freeQuota: 'free',
|
||||
standardQuota: 'standard',
|
||||
basicQuota: 'basic',
|
||||
unlimitedQuota: 'unlimited',
|
||||
},
|
||||
quotaGrants: {
|
||||
ai: {
|
||||
free: 5,
|
||||
basic: 5,
|
||||
standard: 10,
|
||||
unlimited: 200,
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
|
||||
@@ -77,9 +77,19 @@ describe('FeaturesUpdater', function () {
|
||||
quotaTierGranted: 'unlimited',
|
||||
},
|
||||
aiFeatures: {
|
||||
freeTrialQuota: 'basic',
|
||||
freeQuota: 'free',
|
||||
standardQuota: 'standard',
|
||||
basicQuota: 'basic',
|
||||
unlimitedQuota: 'unlimited',
|
||||
},
|
||||
quotaGrants: {
|
||||
ai: {
|
||||
free: 5,
|
||||
basic: 5,
|
||||
standard: 10,
|
||||
unlimited: 200,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ctx.ReferalFeatures = {
|
||||
|
||||
@@ -67,9 +67,19 @@ describe('UserGetter', function () {
|
||||
default: (ctx.settings = {
|
||||
reconfirmNotificationDays: 14,
|
||||
aiFeatures: {
|
||||
freeTrialQuota: 'basic',
|
||||
freeQuota: 'free',
|
||||
standardQuota: 'standard',
|
||||
basicQuota: 'basic',
|
||||
unlimitedQuota: 'unlimited',
|
||||
},
|
||||
quotaGrants: {
|
||||
ai: {
|
||||
free: 5,
|
||||
basic: 5,
|
||||
standard: 10,
|
||||
unlimited: 200,
|
||||
},
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
|
||||
@@ -61,12 +61,16 @@ describe('AiFeatureUsageRateLimiter', function () {
|
||||
quotaTierGranted: 'unlimited',
|
||||
},
|
||||
aiFeatures: {
|
||||
freeTrialQuota: 'basic',
|
||||
freeQuota: 'free',
|
||||
standardQuota: 'standard',
|
||||
basicQuota: 'basic',
|
||||
unlimitedQuota: 'unlimited',
|
||||
},
|
||||
quotaGrants: {
|
||||
ai: {
|
||||
free: 5,
|
||||
basic: 5,
|
||||
standard: 10,
|
||||
unlimited: 200,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user