feat: add independent load_factor field for scheduling load calculation

This commit is contained in:
erio
2026-03-06 05:07:10 +08:00
parent ae5d9c8bfc
commit 0d6c1c7790
31 changed files with 596 additions and 49 deletions

View File

@@ -469,7 +469,7 @@
</div>
<!-- Concurrency & Priority -->
<div class="grid grid-cols-2 gap-4 border-t border-gray-200 pt-4 dark:border-dark-600 lg:grid-cols-3">
<div class="grid grid-cols-2 gap-4 border-t border-gray-200 pt-4 dark:border-dark-600 lg:grid-cols-4">
<div>
<div class="mb-3 flex items-center justify-between">
<label
@@ -498,6 +498,35 @@
aria-labelledby="bulk-edit-concurrency-label"
/>
</div>
<div>
<div class="mb-3 flex items-center justify-between">
<label
id="bulk-edit-load-factor-label"
class="input-label mb-0"
for="bulk-edit-load-factor-enabled"
>
{{ t('admin.accounts.loadFactor') }}
</label>
<input
v-model="enableLoadFactor"
id="bulk-edit-load-factor-enabled"
type="checkbox"
aria-controls="bulk-edit-load-factor"
class="rounded border-gray-300 text-primary-600 focus:ring-primary-500"
/>
</div>
<input
v-model.number="loadFactor"
id="bulk-edit-load-factor"
type="number"
min="1"
:disabled="!enableLoadFactor"
class="input"
:class="!enableLoadFactor && 'cursor-not-allowed opacity-50'"
aria-labelledby="bulk-edit-load-factor-label"
/>
<p class="input-hint">{{ t('admin.accounts.loadFactorHint') }}</p>
</div>
<div>
<div class="mb-3 flex items-center justify-between">
<label
@@ -869,6 +898,7 @@ const enableCustomErrorCodes = ref(false)
const enableInterceptWarmup = ref(false)
const enableProxy = ref(false)
const enableConcurrency = ref(false)
const enableLoadFactor = ref(false)
const enablePriority = ref(false)
const enableRateMultiplier = ref(false)
const enableStatus = ref(false)
@@ -889,6 +919,7 @@ const customErrorCodeInput = ref<number | null>(null)
const interceptWarmupRequests = ref(false)
const proxyId = ref<number | null>(null)
const concurrency = ref(1)
const loadFactor = ref<number | null>(null)
const priority = ref(1)
const rateMultiplier = ref(1)
const status = ref<'active' | 'inactive'>('active')
@@ -1195,6 +1226,10 @@ const buildUpdatePayload = (): Record<string, unknown> | null => {
updates.concurrency = concurrency.value
}
if (enableLoadFactor.value) {
updates.load_factor = loadFactor.value
}
if (enablePriority.value) {
updates.priority = priority.value
}
@@ -1340,6 +1375,7 @@ const handleSubmit = async () => {
enableInterceptWarmup.value ||
enableProxy.value ||
enableConcurrency.value ||
enableLoadFactor.value ||
enablePriority.value ||
enableRateMultiplier.value ||
enableStatus.value ||
@@ -1430,6 +1466,7 @@ watch(
enableInterceptWarmup.value = false
enableProxy.value = false
enableConcurrency.value = false
enableLoadFactor.value = false
enablePriority.value = false
enableRateMultiplier.value = false
enableStatus.value = false
@@ -1446,6 +1483,7 @@ watch(
interceptWarmupRequests.value = false
proxyId.value = null
concurrency.value = 1
loadFactor.value = null
priority.value = 1
rateMultiplier.value = 1
status.value = 'active'

View File

@@ -1749,11 +1749,17 @@
<ProxySelector v-model="form.proxy_id" :proxies="proxies" />
</div>
<div class="grid grid-cols-2 gap-4 lg:grid-cols-3">
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
<div>
<label class="input-label">{{ t('admin.accounts.concurrency') }}</label>
<input v-model.number="form.concurrency" type="number" min="1" class="input" />
</div>
<div>
<label class="input-label">{{ t('admin.accounts.loadFactor') }}</label>
<input v-model.number="form.load_factor" type="number" min="1"
class="input" :placeholder="String(form.concurrency || 1)" />
<p class="input-hint">{{ t('admin.accounts.loadFactorHint') }}</p>
</div>
<div>
<label class="input-label">{{ t('admin.accounts.priority') }}</label>
<input
@@ -2633,6 +2639,7 @@ const form = reactive({
credentials: {} as Record<string, unknown>,
proxy_id: null as number | null,
concurrency: 10,
load_factor: null as number | null,
priority: 1,
rate_multiplier: 1,
group_ids: [] as number[],
@@ -3112,6 +3119,7 @@ const resetForm = () => {
form.credentials = {}
form.proxy_id = null
form.concurrency = 10
form.load_factor = null
form.priority = 1
form.rate_multiplier = 1
form.group_ids = []
@@ -3483,6 +3491,7 @@ const handleImportAccessToken = async (accessTokenInput: string) => {
extra: soraExtra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -3542,6 +3551,7 @@ const createAccountAndFinish = async (
extra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -3597,6 +3607,7 @@ const handleOpenAIExchange = async (authCode: string) => {
extra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -3626,6 +3637,7 @@ const handleOpenAIExchange = async (authCode: string) => {
extra: soraExtra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -3703,6 +3715,7 @@ const handleOpenAIValidateRT = async (refreshTokenInput: string) => {
extra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -3730,6 +3743,7 @@ const handleOpenAIValidateRT = async (refreshTokenInput: string) => {
extra: soraExtra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -3818,6 +3832,7 @@ const handleSoraValidateST = async (sessionTokenInput: string) => {
extra: soraExtra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -3906,6 +3921,7 @@ const handleAntigravityValidateRT = async (refreshTokenInput: string) => {
extra: {},
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,
@@ -4064,8 +4080,11 @@ const handleAnthropicExchange = async (authCode: string) => {
}
// Add RPM limit settings
if (rpmLimitEnabled.value && baseRpm.value != null && baseRpm.value > 0) {
extra.base_rpm = baseRpm.value
if (rpmLimitEnabled.value) {
const DEFAULT_BASE_RPM = 15
extra.base_rpm = (baseRpm.value != null && baseRpm.value > 0)
? baseRpm.value
: DEFAULT_BASE_RPM
extra.rpm_strategy = rpmStrategy.value
if (rpmStickyBuffer.value != null && rpmStickyBuffer.value > 0) {
extra.rpm_sticky_buffer = rpmStickyBuffer.value
@@ -4176,8 +4195,11 @@ const handleCookieAuth = async (sessionKey: string) => {
}
// Add RPM limit settings
if (rpmLimitEnabled.value && baseRpm.value != null && baseRpm.value > 0) {
extra.base_rpm = baseRpm.value
if (rpmLimitEnabled.value) {
const DEFAULT_BASE_RPM = 15
extra.base_rpm = (baseRpm.value != null && baseRpm.value > 0)
? baseRpm.value
: DEFAULT_BASE_RPM
extra.rpm_strategy = rpmStrategy.value
if (rpmStickyBuffer.value != null && rpmStickyBuffer.value > 0) {
extra.rpm_sticky_buffer = rpmStickyBuffer.value
@@ -4223,6 +4245,7 @@ const handleCookieAuth = async (sessionKey: string) => {
extra,
proxy_id: form.proxy_id,
concurrency: form.concurrency,
load_factor: form.load_factor || undefined,
priority: form.priority,
rate_multiplier: form.rate_multiplier,
group_ids: form.group_ids,

View File

@@ -650,11 +650,17 @@
<ProxySelector v-model="form.proxy_id" :proxies="proxies" />
</div>
<div class="grid grid-cols-2 gap-4 lg:grid-cols-3">
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
<div>
<label class="input-label">{{ t('admin.accounts.concurrency') }}</label>
<input v-model.number="form.concurrency" type="number" min="1" class="input" />
</div>
<div>
<label class="input-label">{{ t('admin.accounts.loadFactor') }}</label>
<input v-model.number="form.load_factor" type="number" min="1"
class="input" :placeholder="String(form.concurrency || 1)" />
<p class="input-hint">{{ t('admin.accounts.loadFactorHint') }}</p>
</div>
<div>
<label class="input-label">{{ t('admin.accounts.priority') }}</label>
<input
@@ -1465,6 +1471,7 @@ const form = reactive({
notes: '',
proxy_id: null as number | null,
concurrency: 1,
load_factor: null as number | null,
priority: 1,
rate_multiplier: 1,
status: 'active' as 'active' | 'inactive',
@@ -1498,6 +1505,7 @@ watch(
form.notes = newAccount.notes || ''
form.proxy_id = newAccount.proxy_id
form.concurrency = newAccount.concurrency
form.load_factor = newAccount.load_factor ?? null
form.priority = newAccount.priority
form.rate_multiplier = newAccount.rate_multiplier ?? 1
form.status = newAccount.status as 'active' | 'inactive'
@@ -2049,6 +2057,10 @@ const handleSubmit = async () => {
if (form.expires_at === null) {
updatePayload.expires_at = 0
}
// load_factor: 空值/0/NaN 时发送 0后端约定 0 = 清除)
if (!form.load_factor || form.load_factor <= 0) {
updatePayload.load_factor = 0
}
updatePayload.auto_pause_on_expired = autoPauseOnExpired.value
// For apikey type, handle credentials update
@@ -2188,8 +2200,11 @@ const handleSubmit = async () => {
}
// RPM limit settings
if (rpmLimitEnabled.value && baseRpm.value != null && baseRpm.value > 0) {
newExtra.base_rpm = baseRpm.value
if (rpmLimitEnabled.value) {
const DEFAULT_BASE_RPM = 15
newExtra.base_rpm = (baseRpm.value != null && baseRpm.value > 0)
? baseRpm.value
: DEFAULT_BASE_RPM
newExtra.rpm_strategy = rpmStrategy.value
if (rpmStickyBuffer.value != null && rpmStickyBuffer.value > 0) {
newExtra.rpm_sticky_buffer = rpmStickyBuffer.value