feat: 支持后台设置是否启用整流开关
This commit is contained in:
@@ -273,6 +273,41 @@ export async function updateStreamTimeoutSettings(
|
||||
return data
|
||||
}
|
||||
|
||||
// ==================== Rectifier Settings ====================
|
||||
|
||||
/**
|
||||
* Rectifier settings interface
|
||||
*/
|
||||
export interface RectifierSettings {
|
||||
enabled: boolean
|
||||
thinking_signature_enabled: boolean
|
||||
thinking_budget_enabled: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rectifier settings
|
||||
* @returns Rectifier settings
|
||||
*/
|
||||
export async function getRectifierSettings(): Promise<RectifierSettings> {
|
||||
const { data } = await apiClient.get<RectifierSettings>('/admin/settings/rectifier')
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Update rectifier settings
|
||||
* @param settings - Rectifier settings to update
|
||||
* @returns Updated settings
|
||||
*/
|
||||
export async function updateRectifierSettings(
|
||||
settings: RectifierSettings
|
||||
): Promise<RectifierSettings> {
|
||||
const { data } = await apiClient.put<RectifierSettings>(
|
||||
'/admin/settings/rectifier',
|
||||
settings
|
||||
)
|
||||
return data
|
||||
}
|
||||
|
||||
// ==================== Sora S3 Settings ====================
|
||||
|
||||
export interface SoraS3Settings {
|
||||
@@ -419,6 +454,8 @@ export const settingsAPI = {
|
||||
deleteAdminApiKey,
|
||||
getStreamTimeoutSettings,
|
||||
updateStreamTimeoutSettings,
|
||||
getRectifierSettings,
|
||||
updateRectifierSettings,
|
||||
getSoraS3Settings,
|
||||
updateSoraS3Settings,
|
||||
testSoraS3Connection,
|
||||
|
||||
@@ -3976,6 +3976,18 @@ export default {
|
||||
saved: 'Stream timeout settings saved',
|
||||
saveFailed: 'Failed to save stream timeout settings'
|
||||
},
|
||||
rectifier: {
|
||||
title: 'Request Rectifier',
|
||||
description: 'Automatically fix request parameters and retry when upstream returns specific errors',
|
||||
enabled: 'Enable Request Rectifier',
|
||||
enabledHint: 'Master switch - disabling turns off all rectification features',
|
||||
thinkingSignature: 'Thinking Signature Rectifier',
|
||||
thinkingSignatureHint: 'Automatically strip signatures and retry when upstream returns thinking block signature validation errors',
|
||||
thinkingBudget: 'Thinking Budget Rectifier',
|
||||
thinkingBudgetHint: 'Automatically set budget to 32000 and retry when upstream returns budget_tokens constraint error (≥1024)',
|
||||
saved: 'Rectifier settings saved',
|
||||
saveFailed: 'Failed to save rectifier settings'
|
||||
},
|
||||
saveSettings: 'Save Settings',
|
||||
saving: 'Saving...',
|
||||
settingsSaved: 'Settings saved successfully',
|
||||
|
||||
@@ -4150,6 +4150,18 @@ export default {
|
||||
saved: '流超时设置保存成功',
|
||||
saveFailed: '保存流超时设置失败'
|
||||
},
|
||||
rectifier: {
|
||||
title: '请求整流器',
|
||||
description: '当上游返回特定错误时,自动修正请求参数并重试,提高请求成功率',
|
||||
enabled: '启用请求整流器',
|
||||
enabledHint: '总开关,关闭后所有整流功能均不生效',
|
||||
thinkingSignature: 'Thinking 签名整流',
|
||||
thinkingSignatureHint: '当上游返回 thinking block 签名校验错误时,自动去除签名并重试',
|
||||
thinkingBudget: 'Thinking Budget 整流',
|
||||
thinkingBudgetHint: '当上游返回 budget_tokens 约束错误(≥1024)时,自动将 budget 设为 32000 并重试',
|
||||
saved: '整流器设置保存成功',
|
||||
saveFailed: '保存整流器设置失败'
|
||||
},
|
||||
saveSettings: '保存设置',
|
||||
saving: '保存中...',
|
||||
settingsSaved: '设置保存成功',
|
||||
|
||||
@@ -307,7 +307,105 @@
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /Tab: Gateway — Stream Timeout (continued below with Claude Code & Scheduling) -->
|
||||
|
||||
<!-- Request Rectifier Settings -->
|
||||
<div class="card">
|
||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{{ t('admin.settings.rectifier.title') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.rectifier.description') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-5 p-6">
|
||||
<!-- Loading State -->
|
||||
<div v-if="rectifierLoading" class="flex items-center gap-2 text-gray-500">
|
||||
<div class="h-4 w-4 animate-spin rounded-full border-b-2 border-primary-600"></div>
|
||||
{{ t('common.loading') }}
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<!-- Master Toggle -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="font-medium text-gray-900 dark:text-white">{{
|
||||
t('admin.settings.rectifier.enabled')
|
||||
}}</label>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.rectifier.enabledHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="rectifierForm.enabled" />
|
||||
</div>
|
||||
|
||||
<!-- Sub-toggles (only show when master is enabled) -->
|
||||
<div
|
||||
v-if="rectifierForm.enabled"
|
||||
class="space-y-4 border-t border-gray-100 pt-4 dark:border-dark-700"
|
||||
>
|
||||
<!-- Thinking Signature Rectifier -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">{{
|
||||
t('admin.settings.rectifier.thinkingSignature')
|
||||
}}</label>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.rectifier.thinkingSignatureHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="rectifierForm.thinking_signature_enabled" />
|
||||
</div>
|
||||
|
||||
<!-- Thinking Budget Rectifier -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">{{
|
||||
t('admin.settings.rectifier.thinkingBudget')
|
||||
}}</label>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.rectifier.thinkingBudgetHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="rectifierForm.thinking_budget_enabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Save Button -->
|
||||
<div class="flex justify-end border-t border-gray-100 pt-4 dark:border-dark-700">
|
||||
<button
|
||||
type="button"
|
||||
@click="saveRectifierSettings"
|
||||
:disabled="rectifierSaving"
|
||||
class="btn btn-primary btn-sm"
|
||||
>
|
||||
<svg
|
||||
v-if="rectifierSaving"
|
||||
class="mr-1 h-4 w-4 animate-spin"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
class="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
stroke-width="4"
|
||||
></circle>
|
||||
<path
|
||||
class="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
{{ rectifierSaving ? t('common.saving') : t('common.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /Tab: Gateway -->
|
||||
|
||||
<!-- Tab: Security — Registration, Turnstile, LinuxDo -->
|
||||
<div v-show="activeTab === 'security'" class="space-y-6">
|
||||
@@ -1520,6 +1618,15 @@ const streamTimeoutForm = reactive({
|
||||
threshold_window_minutes: 10
|
||||
})
|
||||
|
||||
// Rectifier 状态
|
||||
const rectifierLoading = ref(true)
|
||||
const rectifierSaving = ref(false)
|
||||
const rectifierForm = reactive({
|
||||
enabled: true,
|
||||
thinking_signature_enabled: true,
|
||||
thinking_budget_enabled: true
|
||||
})
|
||||
|
||||
interface DefaultSubscriptionGroupOption {
|
||||
value: number
|
||||
label: string
|
||||
@@ -2026,11 +2133,44 @@ async function saveStreamTimeoutSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
// Rectifier 方法
|
||||
async function loadRectifierSettings() {
|
||||
rectifierLoading.value = true
|
||||
try {
|
||||
const settings = await adminAPI.settings.getRectifierSettings()
|
||||
Object.assign(rectifierForm, settings)
|
||||
} catch (error: any) {
|
||||
console.error('Failed to load rectifier settings:', error)
|
||||
} finally {
|
||||
rectifierLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function saveRectifierSettings() {
|
||||
rectifierSaving.value = true
|
||||
try {
|
||||
const updated = await adminAPI.settings.updateRectifierSettings({
|
||||
enabled: rectifierForm.enabled,
|
||||
thinking_signature_enabled: rectifierForm.thinking_signature_enabled,
|
||||
thinking_budget_enabled: rectifierForm.thinking_budget_enabled
|
||||
})
|
||||
Object.assign(rectifierForm, updated)
|
||||
appStore.showSuccess(t('admin.settings.rectifier.saved'))
|
||||
} catch (error: any) {
|
||||
appStore.showError(
|
||||
t('admin.settings.rectifier.saveFailed') + ': ' + (error.message || t('common.unknownError'))
|
||||
)
|
||||
} finally {
|
||||
rectifierSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSettings()
|
||||
loadSubscriptionGroups()
|
||||
loadAdminApiKey()
|
||||
loadStreamTimeoutSettings()
|
||||
loadRectifierSettings()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user