{{ model.active_provider_count || 0 }}/{{ model.provider_count || 0 }}
@@ -358,26 +337,6 @@
${{ getFirstTierPrice(model, 'input')?.toFixed(2) || '-' }}/${{ getFirstTierPrice(model, 'output')?.toFixed(2) || '-' }}
-
-
- {{ t('models.pricingSource.label') }}
-
-
@@ -782,7 +741,6 @@ import {
} from 'lucide-vue-next'
import ModelDetailDrawer from '@/features/models/components/ModelDetailDrawer.vue'
import GlobalModelFormDialog from '@/features/models/components/GlobalModelFormDialog.vue'
-import GlobalModelPricingSourceSelect from '@/features/models/components/GlobalModelPricingSourceSelect.vue'
import ExternalModelsAccessControl from '@/features/models/components/ExternalModelsAccessControl.vue'
import ProviderModelFormDialog from '@/features/providers/components/ProviderModelFormDialog.vue'
import type { Model } from '@/api/endpoints'
@@ -889,7 +847,6 @@ const batchManageModels = ref([])
const batchManageLoading = ref(false)
const batchManageOnlineModels = ref([])
const batchManageOnlineLoading = ref(false)
-const modelPricingSourceSyncingIds = ref>(new Set())
const GLOBAL_MODELS_BATCH_FETCH_PAGE_SIZE = 1000
let globalModelsRequestId = 0
let modelSelectionRequestId = 0
@@ -1508,53 +1465,6 @@ const filteredBatchManageModels = computed(() => {
})
})
-const onlinePricingCandidatesByModelName = computed(() => {
- const candidatesByName = new Map()
- for (const onlineModel of batchManageOnlineModels.value) {
- const normalizedName = onlineModel.modelId.trim().toLowerCase()
- const existing = candidatesByName.get(normalizedName) ?? []
- const normalizedProviderId = onlineModel.providerId.trim().toLowerCase()
- if (!existing.some(candidate => (
- candidate.providerId.trim().toLowerCase() === normalizedProviderId
- ))) {
- existing.push(onlineModel)
- candidatesByName.set(normalizedName, existing)
- }
- }
- for (const candidates of candidatesByName.values()) {
- candidates.sort((left, right) => (
- Number(right.official === true) - Number(left.official === true)
- || left.providerName.localeCompare(right.providerName)
- || left.providerId.localeCompare(right.providerId)
- ))
- }
- return candidatesByName
-})
-
-function getModelPricingCandidates(model: GlobalModelResponse): ModelsDevModelItem[] {
- return onlinePricingCandidatesByModelName.value.get(model.name.trim().toLowerCase()) ?? []
-}
-
-function getModelPricingSource(model: GlobalModelResponse) {
- return getModelsDevPricingSource(model.id, model.config)
-}
-
-function isModelPricingSourceLocalOnly(model: GlobalModelResponse): boolean {
- return !getModelsDevPricingSourceFromConfig(model.config)
- && !!getLocalModelsDevPricingSource(model.id)
-}
-
-function isModelPricingSourceSyncing(modelId: string): boolean {
- return modelPricingSourceSyncingIds.value.has(modelId)
-}
-
-function setModelPricingSourceSyncing(modelId: string, syncing: boolean) {
- const nextIds = new Set(modelPricingSourceSyncingIds.value)
- if (syncing) nextIds.add(modelId)
- else nextIds.delete(modelId)
- modelPricingSourceSyncingIds.value = nextIds
-}
-
function applyGlobalModelUpdate(updatedModel: GlobalModelResponse) {
for (const models of [globalModels.value, batchManageModels.value]) {
const current = models.find(model => model.id === updatedModel.id)
@@ -1580,7 +1490,6 @@ function migrateLegacyModelsDevPricingSources(models: GlobalModelResponse[]) {
}
pricingSourceMigrationAttemptedIds.add(model.id)
return [async () => {
- setModelPricingSourceSyncing(model.id, true)
const nextConfig = withModelsDevPricingSource(model.config, localSource)
try {
const updatedModel = await updateGlobalModel(model.id, { config: nextConfig })
@@ -1588,84 +1497,12 @@ function migrateLegacyModelsDevPricingSources(models: GlobalModelResponse[]) {
} catch (err: unknown) {
pricingSourceMigrationAttemptedIds.delete(model.id)
log.warn('迁移本地模型价格来源失败:', err)
- } finally {
- setModelPricingSourceSyncing(model.id, false)
}
}]
})
if (tasks.length > 0) void runBatchTasksWithConcurrency(tasks, 4)
}
-async function handleModelPricingSourceOpen(_model: GlobalModelResponse, open: boolean) {
- if (open) await loadBatchManageOnlineModels()
-}
-
-async function syncModelPricingSource(model: GlobalModelResponse, providerId: string) {
- if (!providerId || providerId.startsWith('__') || isModelPricingSourceSyncing(model.id)) return
- if (batchManageOnlineModels.value.length === 0) await loadBatchManageOnlineModels()
- const normalizedProviderId = providerId.trim().toLowerCase()
- const candidate = getModelPricingCandidates(model).find(item => (
- item.providerId.trim().toLowerCase() === normalizedProviderId
- ))
- if (!candidate) {
- showError(
- t('models.pricingSource.sourceGone'),
- t('models.pricingSource.cannotSync'),
- )
- return
- }
- if (candidate.pricingUnsupportedFields?.length) {
- showError(
- t('models.pricingSource.unsupported', { fields: formatBatchUnsupportedPricingFields(candidate) }),
- t('models.pricingSource.incompatible'),
- )
- return
- }
- if (!candidate.tieredPricing?.tiers?.length) {
- showError(
- t('models.pricingSource.noUsablePrice'),
- t('models.pricingSource.cannotSync'),
- )
- return
- }
-
- const source = {
- provider_id: candidate.providerId,
- provider_name: candidate.providerName,
- }
- const pricing = cloneTieredPricingConfig(candidate.tieredPricing)
- const nextConfig = withModelsDevPricingSource(model.config, source)
- setModelPricingSourceSyncing(model.id, true)
- try {
- const updatedModel = await updateGlobalModel(model.id, {
- default_tiered_pricing: pricing,
- config: nextConfig,
- })
- setModelsDevPricingSource(model.id, source)
- applyGlobalModelUpdate({
- ...updatedModel,
- default_tiered_pricing: pricing,
- config: nextConfig,
- })
- success(t('models.pricingSource.selectedAndSynced', { provider: candidate.providerName }))
- } catch (err: unknown) {
- log.error('更新模型价格来源失败:', err)
- showError(
- parseApiError(err, t('models.pricingSource.updateFailed')),
- t('models.pricingSource.syncFailed'),
- )
- } finally {
- setModelPricingSourceSyncing(model.id, false)
- }
-}
-
-async function resyncModelPricingSource(model: GlobalModelResponse) {
- const source = getModelPricingSource(model)
- if (!source) return
- await loadBatchManageOnlineModels()
- await syncModelPricingSource(model, source.provider_id)
-}
-
const batchPricingProviderOptions = computed(() => {
const existingModelNames = new Set(batchManageModels.value.map(model => model.name.trim().toLowerCase()))
const providers = new Map {
})
})
- it('renders the new source and selection controls in English', async () => {
+ it('does not render the pricing source in the model list', async () => {
mountView()
await settle()
setI18nLocale('en-US')
await settle()
- expect(document.body.textContent).toContain('Online pricing source')
+ expect(document.body.textContent).not.toContain('Online pricing source')
expect(document.body.textContent).toContain('Batch manage')
expect(document.body.querySelector(
'[aria-label="Select model Test Model"]',
)).not.toBeNull()
expect(document.body.querySelector(
'[data-testid="model-pricing-source-model-1"]',
- )?.getAttribute('aria-label')).toContain('Current source: Old OpenAI label')
+ )).toBeNull()
})
it('migrates a legacy browser-only source into the model database config', async () => {