mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
fix(frontend): stabilize image generation overrides in model forms
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:class="checkboxClass"
|
:class="checkboxClass"
|
||||||
:checked="isChecked"
|
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
:checked="isChecked"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -543,6 +543,7 @@ const defaultForm = (): FormData => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const form = ref<FormData>(defaultForm())
|
const form = ref<FormData>(defaultForm())
|
||||||
|
const imageGenerationExplicitOverride = ref<boolean | null>(null)
|
||||||
|
|
||||||
const isEmbeddingEnabled = computed(() => {
|
const isEmbeddingEnabled = computed(() => {
|
||||||
return form.value.supported_capabilities?.includes('embedding') === true
|
return form.value.supported_capabilities?.includes('embedding') === true
|
||||||
@@ -551,11 +552,15 @@ const isEmbeddingEnabled = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const isImageGenerationEnabled = computed(() => {
|
const isImageGenerationEnabled = computed(() => {
|
||||||
|
if (imageGenerationExplicitOverride.value !== null) {
|
||||||
|
return imageGenerationExplicitOverride.value
|
||||||
|
}
|
||||||
return form.value.supported_capabilities?.includes('image_generation') === true
|
return form.value.supported_capabilities?.includes('image_generation') === true
|
||||||
|| form.value.config?.image_generation === true
|
|| form.value.config?.image_generation === true
|
||||||
|| form.value.config?.model_type === 'image'
|
|| form.value.config?.model_type === 'image'
|
||||||
|| (Array.isArray(form.value.config?.api_formats)
|
|| (Array.isArray(form.value.config?.api_formats)
|
||||||
&& form.value.config.api_formats.some((format) => String(format).endsWith(':image')))
|
&& form.value.config.api_formats.some((format) => String(format).endsWith(':image')))
|
||||||
|
|| tieredPricingHasImageOutputPricing(tieredPricing.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
const KEEP_FALSE_CONFIG_KEYS = new Set(['streaming'])
|
const KEEP_FALSE_CONFIG_KEYS = new Set(['streaming'])
|
||||||
@@ -602,6 +607,7 @@ function setEmbeddingEnabled(enabled: boolean) {
|
|||||||
|
|
||||||
function setImageGenerationEnabled(value: boolean | 'indeterminate') {
|
function setImageGenerationEnabled(value: boolean | 'indeterminate') {
|
||||||
const enabled = value === true
|
const enabled = value === true
|
||||||
|
imageGenerationExplicitOverride.value = enabled
|
||||||
const caps = new Set(form.value.supported_capabilities || [])
|
const caps = new Set(form.value.supported_capabilities || [])
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
caps.add('image_generation')
|
caps.add('image_generation')
|
||||||
@@ -767,6 +773,7 @@ watch(() => props.open, (isOpen) => {
|
|||||||
|
|
||||||
// 选择模型并填充表单
|
// 选择模型并填充表单
|
||||||
function selectModel(model: ModelsDevModelItem) {
|
function selectModel(model: ModelsDevModelItem) {
|
||||||
|
imageGenerationExplicitOverride.value = null
|
||||||
selectedModel.value = model
|
selectedModel.value = model
|
||||||
expandedProvider.value = model.providerId
|
expandedProvider.value = model.providerId
|
||||||
form.value.name = model.modelId
|
form.value.name = model.modelId
|
||||||
@@ -815,6 +822,7 @@ function selectModel(model: ModelsDevModelItem) {
|
|||||||
|
|
||||||
// 清除选择(手动填写)
|
// 清除选择(手动填写)
|
||||||
function clearSelection() {
|
function clearSelection() {
|
||||||
|
imageGenerationExplicitOverride.value = null
|
||||||
selectedModel.value = null
|
selectedModel.value = null
|
||||||
form.value = defaultForm()
|
form.value = defaultForm()
|
||||||
tieredPricing.value = null
|
tieredPricing.value = null
|
||||||
@@ -828,6 +836,7 @@ function handleLogoError(event: Event) {
|
|||||||
|
|
||||||
// 重置表单
|
// 重置表单
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
|
imageGenerationExplicitOverride.value = null
|
||||||
form.value = defaultForm()
|
form.value = defaultForm()
|
||||||
tieredPricing.value = null
|
tieredPricing.value = null
|
||||||
videoResolutionPrices.value = []
|
videoResolutionPrices.value = []
|
||||||
@@ -839,6 +848,7 @@ function resetForm() {
|
|||||||
// 加载模型数据(编辑模式)
|
// 加载模型数据(编辑模式)
|
||||||
function loadModelData() {
|
function loadModelData() {
|
||||||
if (!props.model) return
|
if (!props.model) return
|
||||||
|
imageGenerationExplicitOverride.value = null
|
||||||
// 先重置创建模式的残留状态
|
// 先重置创建模式的残留状态
|
||||||
selectedModel.value = null
|
selectedModel.value = null
|
||||||
searchQuery.value = ''
|
searchQuery.value = ''
|
||||||
@@ -937,10 +947,19 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
function tieredPricingHasImageOutputPricing(pricing: TieredPricingConfig | null | undefined): boolean {
|
function tieredPricingHasImageOutputPricing(pricing: TieredPricingConfig | null | undefined): boolean {
|
||||||
if (!pricing) return false
|
if (!pricing) return false
|
||||||
if (pricing.image_output_price_default != null) return true
|
if (toFinitePrice(pricing.image_output_price_default) !== null) return true
|
||||||
return Object.values(pricing.image_output_prices || {}).some((prices) => {
|
return Object.values(pricing.image_output_prices || {}).some((prices) => {
|
||||||
if (!prices || typeof prices !== 'object') return false
|
if (!prices || typeof prices !== 'object') return false
|
||||||
return Object.values(prices).some((price) => typeof price === 'number' && Number.isFinite(price))
|
return Object.values(prices).some((price) => toFinitePrice(price) !== null)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toFinitePrice(value: unknown): number | null {
|
||||||
|
if (typeof value === 'number' && Number.isFinite(value)) return value
|
||||||
|
if (typeof value === 'string' && value.trim()) {
|
||||||
|
const parsed = Number(value)
|
||||||
|
return Number.isFinite(parsed) ? parsed : null
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -353,12 +353,16 @@ const editingModelSupportsImageGeneration = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const isImageGenerationEnabled = computed(() => {
|
const isImageGenerationEnabled = computed(() => {
|
||||||
|
if (imageGenerationExplicitOverride.value !== null) {
|
||||||
|
return imageGenerationExplicitOverride.value
|
||||||
|
}
|
||||||
if (form.value.supports_image_generation !== undefined) {
|
if (form.value.supports_image_generation !== undefined) {
|
||||||
return form.value.supports_image_generation === true
|
return form.value.supports_image_generation === true
|
||||||
}
|
}
|
||||||
return isEditing.value
|
const supportsImageGeneration = isEditing.value
|
||||||
? editingModelSupportsImageGeneration.value
|
? editingModelSupportsImageGeneration.value
|
||||||
: selectedGlobalModelSupportsImageGeneration.value
|
: selectedGlobalModelSupportsImageGeneration.value
|
||||||
|
return supportsImageGeneration || tieredPricingHasImageOutputPricing(tieredPricing.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 1h 缓存定价始终显示
|
// 1h 缓存定价始终显示
|
||||||
@@ -422,6 +426,7 @@ const form = ref({
|
|||||||
supports_image_generation: undefined as boolean | undefined,
|
supports_image_generation: undefined as boolean | undefined,
|
||||||
is_active: true
|
is_active: true
|
||||||
})
|
})
|
||||||
|
const imageGenerationExplicitOverride = ref<boolean | null>(null)
|
||||||
|
|
||||||
const canSubmitCreate = computed(() => {
|
const canSubmitCreate = computed(() => {
|
||||||
if (isEditing.value) return true
|
if (isEditing.value) return true
|
||||||
@@ -502,6 +507,7 @@ watch(tieredPricing, (newValue) => {
|
|||||||
|
|
||||||
// 重置表单
|
// 重置表单
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
|
imageGenerationExplicitOverride.value = null
|
||||||
form.value = {
|
form.value = {
|
||||||
global_model_id: '',
|
global_model_id: '',
|
||||||
provider_model_name: '',
|
provider_model_name: '',
|
||||||
@@ -526,6 +532,8 @@ function resetForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleGlobalModelSelect(value: string) {
|
function handleGlobalModelSelect(value: string) {
|
||||||
|
imageGenerationExplicitOverride.value = null
|
||||||
|
form.value.supports_image_generation = undefined
|
||||||
form.value.global_model_id = value
|
form.value.global_model_id = value
|
||||||
const selectedModel = availableGlobalModels.value.find(model => model.id === value)
|
const selectedModel = availableGlobalModels.value.find(model => model.id === value)
|
||||||
form.value.provider_model_name = selectedModel?.name || form.value.provider_model_name
|
form.value.provider_model_name = selectedModel?.name || form.value.provider_model_name
|
||||||
@@ -565,15 +573,26 @@ function modelSupportsImageGeneration(model: {
|
|||||||
|
|
||||||
function tieredPricingHasImageOutputPricing(pricing: TieredPricingConfig | null | undefined): boolean {
|
function tieredPricingHasImageOutputPricing(pricing: TieredPricingConfig | null | undefined): boolean {
|
||||||
if (!pricing) return false
|
if (!pricing) return false
|
||||||
if (pricing.image_output_price_default != null) return true
|
if (toFinitePrice(pricing.image_output_price_default) !== null) return true
|
||||||
return Object.values(pricing.image_output_prices || {}).some((prices) => {
|
return Object.values(pricing.image_output_prices || {}).some((prices) => {
|
||||||
if (!prices || typeof prices !== 'object') return false
|
if (!prices || typeof prices !== 'object') return false
|
||||||
return Object.values(prices).some((price) => typeof price === 'number' && Number.isFinite(price))
|
return Object.values(prices).some((price) => toFinitePrice(price) !== null)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toFinitePrice(value: unknown): number | null {
|
||||||
|
if (typeof value === 'number' && Number.isFinite(value)) return value
|
||||||
|
if (typeof value === 'string' && value.trim()) {
|
||||||
|
const parsed = Number(value)
|
||||||
|
return Number.isFinite(parsed) ? parsed : null
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
function setImageGenerationEnabled(value: boolean | 'indeterminate') {
|
function setImageGenerationEnabled(value: boolean | 'indeterminate') {
|
||||||
form.value.supports_image_generation = value === true
|
const enabled = value === true
|
||||||
|
imageGenerationExplicitOverride.value = enabled
|
||||||
|
form.value.supports_image_generation = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNested(obj: Record<string, unknown>, path: string): unknown {
|
function getNested(obj: Record<string, unknown>, path: string): unknown {
|
||||||
|
|||||||
Reference in New Issue
Block a user