feat: 按上游计费倍率调度 OpenAI 账号

This commit is contained in:
Tian Lee
2026-07-16 00:40:46 +08:00
parent 0765d10c1d
commit 90ee85f3ef
34 changed files with 2299 additions and 252 deletions
+110 -2
View File
@@ -4020,7 +4020,61 @@
<Toggle v-model="form.allow_ungrouped_key_scheduling" />
</div>
<div class="flex items-center justify-between">
<div
v-if="!form.openai_advanced_scheduler_enabled"
class="flex items-center justify-between border-t border-gray-100 pt-5 dark:border-dark-700"
>
<div>
<label
class="text-sm font-medium text-gray-700 dark:text-gray-300"
>
{{ t("admin.settings.openaiExperimentalScheduler.lowRatePriorityTitle") }}
</label>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
{{
t("admin.settings.openaiExperimentalScheduler.lowRatePriorityDescription")
}}
</p>
</div>
<Toggle
v-model="form.openai_low_upstream_rate_priority_enabled"
data-testid="openai-low-rate-priority-toggle"
/>
</div>
<div
v-if="!form.openai_advanced_scheduler_enabled && form.openai_low_upstream_rate_priority_enabled"
class="flex flex-col items-stretch gap-3 border-t border-gray-100 pt-5 sm:flex-row sm:items-start sm:justify-between sm:gap-6 dark:border-dark-700"
>
<div class="min-w-0">
<label
class="text-sm font-medium text-gray-700 dark:text-gray-300"
for="openai-oauth-scheduling-rate-multiplier"
>
{{ t("admin.settings.openaiExperimentalScheduler.oauthRateTitle") }}
</label>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
{{ t("admin.settings.openaiExperimentalScheduler.oauthRatePriorityDescription") }}
</p>
</div>
<div class="relative w-full shrink-0 sm:w-32">
<input
id="openai-oauth-scheduling-rate-multiplier"
v-model.number="form.openai_oauth_scheduling_rate_multiplier"
class="input pr-8"
data-testid="openai-oauth-scheduling-rate-multiplier"
min="0"
required
step="0.01"
type="number"
/>
<span
class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-sm text-gray-400"
>x</span>
</div>
</div>
<div class="flex items-center justify-between border-t border-gray-100 pt-5 dark:border-dark-700">
<div>
<label
class="text-sm font-medium text-gray-700 dark:text-gray-300"
@@ -4033,7 +4087,10 @@
}}
</p>
</div>
<Toggle v-model="form.openai_advanced_scheduler_enabled" />
<Toggle
v-model="form.openai_advanced_scheduler_enabled"
data-testid="openai-advanced-scheduler-toggle"
/>
</div>
<div
@@ -4074,6 +4131,38 @@
<Toggle v-model="form.openai_advanced_scheduler_subscription_priority_enabled" />
</div>
<div
v-if="form.openai_advanced_scheduler_enabled"
class="flex flex-col items-stretch gap-3 border-t border-gray-100 pt-5 sm:flex-row sm:items-start sm:justify-between sm:gap-6 dark:border-dark-700"
>
<div class="min-w-0">
<label
class="text-sm font-medium text-gray-700 dark:text-gray-300"
for="openai-oauth-scheduling-rate-multiplier"
>
{{ t("admin.settings.openaiExperimentalScheduler.oauthRateTitle") }}
</label>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400">
{{ t("admin.settings.openaiExperimentalScheduler.oauthRateWeightedDescription") }}
</p>
</div>
<div class="relative w-full shrink-0 sm:w-32">
<input
id="openai-oauth-scheduling-rate-multiplier"
v-model.number="form.openai_oauth_scheduling_rate_multiplier"
class="input pr-8"
data-testid="openai-oauth-scheduling-rate-multiplier"
min="0"
required
step="0.01"
type="number"
/>
<span
class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-sm text-gray-400"
>x</span>
</div>
</div>
<div
v-if="form.openai_advanced_scheduler_enabled"
class="border-t border-gray-100 pt-5 dark:border-dark-700"
@@ -8039,6 +8128,8 @@ type SettingsForm = Omit<
github_oauth_client_secret: string;
google_oauth_client_secret: string;
force_email_on_third_party_signup: boolean;
openai_low_upstream_rate_priority_enabled: boolean;
openai_oauth_scheduling_rate_multiplier: number;
openai_advanced_scheduler_enabled: boolean;
openai_advanced_scheduler_sticky_weighted_enabled: boolean;
openai_advanced_scheduler_subscription_priority_enabled: boolean;
@@ -8050,6 +8141,7 @@ type SettingsForm = Omit<
openai_advanced_scheduler_weight_ttft: string;
openai_advanced_scheduler_weight_reset: string;
openai_advanced_scheduler_weight_quota_headroom: string;
openai_advanced_scheduler_weight_upstream_cost: string;
openai_advanced_scheduler_weight_previous_response: string;
openai_advanced_scheduler_weight_session_sticky: string;
// 系统全局平台限额 map;form 内始终归一化为全 4 平台对象(模板非空绑定依赖此不变量)
@@ -8244,6 +8336,8 @@ const form = reactive<SettingsForm>({
max_claude_code_version: "",
// 分组隔离
allow_ungrouped_key_scheduling: false,
openai_low_upstream_rate_priority_enabled: false,
openai_oauth_scheduling_rate_multiplier: 1,
openai_advanced_scheduler_enabled: false,
openai_advanced_scheduler_sticky_weighted_enabled: false,
openai_advanced_scheduler_subscription_priority_enabled: false,
@@ -8255,6 +8349,7 @@ const form = reactive<SettingsForm>({
openai_advanced_scheduler_weight_ttft: "",
openai_advanced_scheduler_weight_reset: "",
openai_advanced_scheduler_weight_quota_headroom: "",
openai_advanced_scheduler_weight_upstream_cost: "",
openai_advanced_scheduler_weight_previous_response: "",
openai_advanced_scheduler_weight_session_sticky: "",
// Gateway forwarding behavior
@@ -8303,6 +8398,7 @@ type OpenAIAdvancedSchedulerOverrideKey =
| "openai_advanced_scheduler_weight_ttft"
| "openai_advanced_scheduler_weight_reset"
| "openai_advanced_scheduler_weight_quota_headroom"
| "openai_advanced_scheduler_weight_upstream_cost"
| "openai_advanced_scheduler_weight_previous_response"
| "openai_advanced_scheduler_weight_session_sticky";
@@ -8315,6 +8411,7 @@ type OpenAIAdvancedSchedulerEffectiveKey =
| "openai_advanced_scheduler_effective_weight_ttft"
| "openai_advanced_scheduler_effective_weight_reset"
| "openai_advanced_scheduler_effective_weight_quota_headroom"
| "openai_advanced_scheduler_effective_weight_upstream_cost"
| "openai_advanced_scheduler_effective_weight_previous_response"
| "openai_advanced_scheduler_effective_weight_session_sticky";
@@ -8378,6 +8475,11 @@ const openAIAdvancedSchedulerWeightFields = computed<
label: t("admin.settings.openaiExperimentalScheduler.quotaHeadroomWeight"),
placeholder: placeholder("openai_advanced_scheduler_effective_weight_quota_headroom", "0"),
},
{
key: "openai_advanced_scheduler_weight_upstream_cost",
label: t("admin.settings.openaiExperimentalScheduler.upstreamCostWeight"),
placeholder: placeholder("openai_advanced_scheduler_effective_weight_upstream_cost", "0"),
},
{
key: "openai_advanced_scheduler_weight_previous_response",
label: t("admin.settings.openaiExperimentalScheduler.previousResponseWeight"),
@@ -9622,6 +9724,10 @@ async function saveSettings() {
payment_cancel_rate_limit_window_mode:
form.payment_cancel_rate_limit_window_mode,
payment_alipay_force_qrcode: form.payment_alipay_force_qrcode,
openai_low_upstream_rate_priority_enabled:
form.openai_low_upstream_rate_priority_enabled,
openai_oauth_scheduling_rate_multiplier:
form.openai_oauth_scheduling_rate_multiplier,
openai_advanced_scheduler_enabled: form.openai_advanced_scheduler_enabled,
openai_advanced_scheduler_sticky_weighted_enabled:
form.openai_advanced_scheduler_sticky_weighted_enabled,
@@ -9643,6 +9749,8 @@ async function saveSettings() {
form.openai_advanced_scheduler_weight_reset.trim(),
openai_advanced_scheduler_weight_quota_headroom:
form.openai_advanced_scheduler_weight_quota_headroom.trim(),
openai_advanced_scheduler_weight_upstream_cost:
form.openai_advanced_scheduler_weight_upstream_cost.trim(),
openai_advanced_scheduler_weight_previous_response:
form.openai_advanced_scheduler_weight_previous_response.trim(),
openai_advanced_scheduler_weight_session_sticky: