feat(openai): port /responses/compact account support flow (PR #1555)
将 vansour/sub2api#1555 的 OpenAI compact 能力建模手工移植到当前 main:账号 级 compact 状态/auto-force_on-force_off 模式、compact-only 模型映射、调度器 tier 分层(已支持 > 未知 > 已知不支持)、管理后台 compact 主动探测,以及对应 i18n/状态徽章。普通 /responses 流量行为不变,无数据库迁移。
This commit is contained in:
@@ -2449,6 +2449,45 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- OpenAI Compact 能力配置 -->
|
||||
<div
|
||||
v-if="form.platform === 'openai' && (accountCategory === 'oauth-based' || accountCategory === 'apikey')"
|
||||
class="border-t border-gray-200 pt-4 dark:border-dark-600 space-y-4"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="input-label mb-0">{{ t('admin.accounts.openai.compactMode') }}</label>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.accounts.openai.compactModeDesc') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-44">
|
||||
<Select v-model="openAICompactMode" :options="openAICompactModeOptions" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.accounts.openai.compactModelMapping') }}</label>
|
||||
<p class="input-hint">{{ t('admin.accounts.openai.compactModelMappingDesc') }}</p>
|
||||
<div v-if="openAICompactModelMappings.length > 0" class="mb-3 space-y-2">
|
||||
<div
|
||||
v-for="(mapping, index) in openAICompactModelMappings"
|
||||
:key="getOpenAICompactModelMappingKey(mapping)"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<input v-model="mapping.from" type="text" class="input flex-1" :placeholder="t('admin.accounts.fromModel')" />
|
||||
<span class="text-gray-400">→</span>
|
||||
<input v-model="mapping.to" type="text" class="input flex-1" :placeholder="t('admin.accounts.toModel')" />
|
||||
<button type="button" @click="removeOpenAICompactModelMapping(index)" class="text-red-500 hover:text-red-700">
|
||||
<Icon name="trash" size="sm" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" @click="addOpenAICompactModelMapping" class="btn btn-secondary text-sm">
|
||||
+ {{ t('admin.accounts.addMapping') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -2918,7 +2957,8 @@ import type {
|
||||
AccountPlatform,
|
||||
AccountType,
|
||||
CheckMixedChannelResponse,
|
||||
CreateAccountRequest
|
||||
CreateAccountRequest,
|
||||
OpenAICompactMode
|
||||
} from '@/types'
|
||||
import BaseDialog from '@/components/common/BaseDialog.vue'
|
||||
import ConfirmDialog from '@/components/common/ConfirmDialog.vue'
|
||||
@@ -3059,6 +3099,7 @@ const editWeeklyResetDay = ref<number | null>(null)
|
||||
const editWeeklyResetHour = ref<number | null>(null)
|
||||
const editResetTimezone = ref<string | null>(null)
|
||||
const modelMappings = ref<ModelMapping[]>([])
|
||||
const openAICompactModelMappings = ref<ModelMapping[]>([])
|
||||
const modelRestrictionMode = ref<'whitelist' | 'mapping'>('whitelist')
|
||||
const allowedModels = ref<string[]>([])
|
||||
const DEFAULT_POOL_MODE_RETRY_COUNT = 3
|
||||
@@ -3071,6 +3112,7 @@ const customErrorCodeInput = ref<number | null>(null)
|
||||
const interceptWarmupRequests = ref(false)
|
||||
const autoPauseOnExpired = ref(true)
|
||||
const openaiPassthroughEnabled = ref(false)
|
||||
const openAICompactMode = ref<OpenAICompactMode>('auto')
|
||||
const openaiOAuthResponsesWebSocketV2Mode = ref<OpenAIWSMode>(OPENAI_WS_MODE_OFF)
|
||||
const openaiAPIKeyResponsesWebSocketV2Mode = ref<OpenAIWSMode>(OPENAI_WS_MODE_OFF)
|
||||
const codexCLIOnlyEnabled = ref(false)
|
||||
@@ -3112,10 +3154,16 @@ const bedrockApiKeyValue = ref('')
|
||||
const tempUnschedEnabled = ref(false)
|
||||
const tempUnschedRules = ref<TempUnschedRuleForm[]>([])
|
||||
const getModelMappingKey = createStableObjectKeyResolver<ModelMapping>('create-model-mapping')
|
||||
const getOpenAICompactModelMappingKey = createStableObjectKeyResolver<ModelMapping>('create-openai-compact-model-mapping')
|
||||
const getAntigravityModelMappingKey = createStableObjectKeyResolver<ModelMapping>('create-antigravity-model-mapping')
|
||||
const getTempUnschedRuleKey = createStableObjectKeyResolver<TempUnschedRuleForm>('create-temp-unsched-rule')
|
||||
const geminiOAuthType = ref<'code_assist' | 'google_one' | 'ai_studio'>('google_one')
|
||||
const geminiAIStudioOAuthEnabled = ref(false)
|
||||
const openAICompactModeOptions = computed(() => [
|
||||
{ value: 'auto', label: t('admin.accounts.openai.compactModeAuto') },
|
||||
{ value: 'force_on', label: t('admin.accounts.openai.compactModeForceOn') },
|
||||
{ value: 'force_off', label: t('admin.accounts.openai.compactModeForceOff') }
|
||||
])
|
||||
|
||||
function buildAntigravityExtra(): Record<string, unknown> | undefined {
|
||||
const extra: Record<string, unknown> = {}
|
||||
@@ -3124,6 +3172,9 @@ function buildAntigravityExtra(): Record<string, unknown> | undefined {
|
||||
return Object.keys(extra).length > 0 ? extra : undefined
|
||||
}
|
||||
|
||||
const buildOpenAICompactModelMapping = () =>
|
||||
buildModelMappingObject('mapping', [], openAICompactModelMappings.value)
|
||||
|
||||
const showMixedChannelWarning = ref(false)
|
||||
const mixedChannelWarningDetails = ref<{ groupName: string; currentPlatform: string; otherPlatform: string } | null>(
|
||||
null
|
||||
@@ -3489,6 +3540,14 @@ const addModelMapping = () => {
|
||||
modelMappings.value.push({ from: '', to: '' })
|
||||
}
|
||||
|
||||
const addOpenAICompactModelMapping = () => {
|
||||
openAICompactModelMappings.value.push({ from: '', to: '' })
|
||||
}
|
||||
|
||||
const removeOpenAICompactModelMapping = (index: number) => {
|
||||
openAICompactModelMappings.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const removeModelMapping = (index: number) => {
|
||||
modelMappings.value.splice(index, 1)
|
||||
}
|
||||
@@ -3781,6 +3840,7 @@ const resetForm = () => {
|
||||
editWeeklyResetHour.value = null
|
||||
editResetTimezone.value = null
|
||||
modelMappings.value = []
|
||||
openAICompactModelMappings.value = []
|
||||
modelRestrictionMode.value = 'whitelist'
|
||||
allowedModels.value = [...claudeModels] // Default fill related models
|
||||
|
||||
@@ -3797,6 +3857,7 @@ const resetForm = () => {
|
||||
interceptWarmupRequests.value = false
|
||||
autoPauseOnExpired.value = true
|
||||
openaiPassthroughEnabled.value = false
|
||||
openAICompactMode.value = 'auto'
|
||||
openaiOAuthResponsesWebSocketV2Mode.value = OPENAI_WS_MODE_OFF
|
||||
openaiAPIKeyResponsesWebSocketV2Mode.value = OPENAI_WS_MODE_OFF
|
||||
codexCLIOnlyEnabled.value = false
|
||||
@@ -3874,6 +3935,11 @@ const buildOpenAIExtra = (base?: Record<string, unknown>): Record<string, unknow
|
||||
} else {
|
||||
delete extra.codex_cli_only
|
||||
}
|
||||
if (openAICompactMode.value !== 'auto') {
|
||||
extra.openai_compact_mode = openAICompactMode.value
|
||||
} else {
|
||||
delete extra.openai_compact_mode
|
||||
}
|
||||
|
||||
return Object.keys(extra).length > 0 ? extra : undefined
|
||||
}
|
||||
@@ -4086,6 +4152,12 @@ const handleSubmit = async () => {
|
||||
credentials.model_mapping = modelMapping
|
||||
}
|
||||
}
|
||||
if (form.platform === 'openai') {
|
||||
const compactModelMapping = buildOpenAICompactModelMapping()
|
||||
if (compactModelMapping) {
|
||||
credentials.compact_model_mapping = compactModelMapping
|
||||
}
|
||||
}
|
||||
|
||||
// Add pool mode if enabled
|
||||
if (poolModeEnabled.value) {
|
||||
@@ -4198,6 +4270,14 @@ const createAccountAndFinish = async (
|
||||
finalExtra = quotaExtra
|
||||
}
|
||||
}
|
||||
if (platform === 'openai') {
|
||||
const compactModelMapping = buildOpenAICompactModelMapping()
|
||||
if (compactModelMapping) {
|
||||
credentials.compact_model_mapping = compactModelMapping
|
||||
} else {
|
||||
delete credentials.compact_model_mapping
|
||||
}
|
||||
}
|
||||
await doCreateAccount({
|
||||
name: form.name,
|
||||
notes: form.notes,
|
||||
@@ -4252,6 +4332,12 @@ const handleOpenAIExchange = async (authCode: string) => {
|
||||
credentials.model_mapping = modelMapping
|
||||
}
|
||||
}
|
||||
if (shouldCreateOpenAI) {
|
||||
const compactModelMapping = buildOpenAICompactModelMapping()
|
||||
if (compactModelMapping) {
|
||||
credentials.compact_model_mapping = compactModelMapping
|
||||
}
|
||||
}
|
||||
|
||||
// 应用临时不可调度配置
|
||||
if (!applyTempUnschedConfig(credentials)) {
|
||||
@@ -4344,6 +4430,12 @@ const handleOpenAIBatchRT = async (refreshTokenInput: string, clientId?: string)
|
||||
credentials.model_mapping = modelMapping
|
||||
}
|
||||
}
|
||||
if (shouldCreateOpenAI) {
|
||||
const compactModelMapping = buildOpenAICompactModelMapping()
|
||||
if (compactModelMapping) {
|
||||
credentials.compact_model_mapping = compactModelMapping
|
||||
}
|
||||
}
|
||||
|
||||
// Generate account name; fallback to email if name is empty (ent schema requires NotEmpty)
|
||||
const baseName = form.name || tokenInfo.email || 'OpenAI OAuth Account'
|
||||
|
||||
Reference in New Issue
Block a user