feat: Painting 平台接入模型配置 API

将模型配置从代码内硬编码切换为后端 API 动态加载,使用 modelConfigHelper 共享工具函数。
This commit is contained in:
王佑琳 2026-06-09 18:00:16 +08:00
parent 33094e675c
commit 308581e2e4

View File

@ -1,23 +1,13 @@
import { ref, reactive, markRaw } from 'vue'
import { fetchPlatformModels, getPlatformCode } from '@/utils/modelApi'
import { getModelConfig } from './models/index.js'
import PaintingModelSelector from './modelSelector.vue'
import PaintingProportion from './controls/proportion.vue'
import { markRaw, reactive, ref } from 'vue'
import { fetchPlatformModels, getModelConfig, getModelId, getPlatformCode, preloadModelConfigs } from '@/utils/modelApi'
import { syncDefaults as _syncDefaults, syncParamValues as _syncParamValues, checkShowWhen, getDimConfig } from '@/utils/modelConfigHelper.js'
import { registerPlatform } from '../registry.js'
import DimensionInput from './controls/dimension.vue'
import PaintingProportion from './controls/proportion.vue'
import QualitySelect from './controls/quality.vue'
import Quantity from './controls/quantity.vue'
import ImageUploader from './imageUploader.vue'
import { registerPlatform } from '../registry.js'
function getDimConfig(config) {
if (!config) return null
const dimParam = config.params.find(p => p.ui === 'dimension')
if (dimParam) return { type: 'combined', config: dimParam.dimension, paramName: dimParam.name }
const wParam = config.params.find(p => p.ui === 'dimensionWidth')
const hParam = config.params.find(p => p.ui === 'dimensionHeight')
if (wParam && hParam) return { type: 'split', wParam, hParam }
return null
}
import PaintingModelSelector from './modelSelector.vue'
export function definePaintingPlatform() {
const model = ref('Flux 2')
@ -35,142 +25,118 @@ export function definePaintingPlatform() {
const paramValues = reactive({})
const state = {
model, modelType,
proportion, resolution,
customWidth, customHight,
dimWidth, dimHeight,
quantity, quality,
paramValues, modelConfig,
model,
modelType,
proportion,
resolution,
customWidth,
customHight,
dimWidth,
dimHeight,
quantity,
quality,
paramValues,
modelConfig
}
// state 对象供 helper 函数使用
const paintingState = {
modelConfig,
paramValues,
proportion,
resolution,
quantity,
quality,
customWidth,
customHight,
dimWidth,
dimHeight,
promptPlaceholder
}
function syncDefaults(config) {
modelConfig.value = config
if (!config) return
config.params.forEach(p => {
if (!(p.name in paramValues)) {
paramValues[p.name] = p.default ?? (p.name === 'outputFormat' ? 'png' : '')
}
})
const ratioParam = config.params.find(p => p.ui === 'proportion')
if (ratioParam) proportion.value = ratioParam.default || '1:1'
const resParam = config.params.find(p => p.ui === 'resolution')
if (resParam) resolution.value = resParam.default || '2k'
const qtyParam = config.params.find(p => p.ui === 'quantity')
if (qtyParam) quantity.value = qtyParam.default || 1
const cwParam = config.params.find(p => p.name === 'customWidth')
if (cwParam) customWidth.value = cwParam.default || 1024
const chParam = config.params.find(p => p.name === 'customHight')
if (chParam) customHight.value = chParam.default || 1024
const qualityParam = config.params.find(p => p.name === 'quality')
if (qualityParam) quality.value = qualityParam.default || 'medium'
const dc = getDimConfig(config)
if (dc?.type === 'split') {
dimWidth.value = dc.wParam.default || 1024
dimHeight.value = dc.hParam.default || 1024
} else if (dc?.type === 'combined') {
const dimParam = config.params.find(p => p.name === dc.paramName)
const raw = dimParam?.default || ''
const parsed = dc.config.parse(raw)
dimWidth.value = parsed.width
dimHeight.value = parsed.height
}
_syncDefaults(config, paintingState)
}
function syncParamValues() {
const ratioParam = modelConfig.value?.params?.find(p => p.ui === 'proportion')
if (ratioParam) paramValues[ratioParam.name] = proportion.value
const resParam = modelConfig.value?.params?.find(p => p.ui === 'resolution')
if (resParam) paramValues[resParam.name] = resolution.value
const qtyParam = modelConfig.value?.params?.find(p => p.ui === 'quantity')
if (qtyParam) paramValues[qtyParam.name] = quantity.value
if (modelConfig.value?.params?.find(p => p.name === 'customWidth')) {
paramValues.customWidth = customWidth.value
}
if (modelConfig.value?.params?.find(p => p.name === 'customHight')) {
paramValues.customHight = customHight.value
}
if (modelConfig.value?.params?.find(p => p.name === 'quality')) {
paramValues.quality = quality.value
}
const dc = getDimConfig(modelConfig.value)
if (dc?.type === 'split') {
paramValues[dc.wParam.name] = dimWidth.value
paramValues[dc.hParam.name] = dimHeight.value
} else if (dc?.type === 'combined') {
paramValues[dc.paramName] = dc.config.format(dimWidth.value, dimHeight.value)
}
_syncParamValues(modelConfig.value, paintingState)
}
const controls = [
{
name: 'proportion',
component: markRaw(PaintingProportion),
show: (config) => !!config?.params?.find(p => p.ui === 'proportion'),
show: (config) => !!config?.params?.find((p) => p.ui === 'proportion'),
props: (config) => {
const ratioParam = config?.params?.find(p => p.ui === 'proportion')
const resParam = config?.params?.find(p => p.ui === 'resolution')
const ratioParam = config?.params?.find((p) => p.ui === 'proportion')
const resParam = config?.params?.find((p) => p.ui === 'resolution')
return {
modelValue: proportion.value,
'modelValue': proportion.value,
'onUpdate:modelValue': (v) => { proportion.value = v },
resolution: resolution.value,
'resolution': resolution.value,
'onUpdate:resolution': (v) => { resolution.value = v },
width: customWidth.value,
'width': customWidth.value,
'onUpdate:width': (v) => { customWidth.value = v },
height: customHight.value,
'height': customHight.value,
'onUpdate:height': (v) => { customHight.value = v },
proportionOptions: ratioParam?.options
?.filter(o => o !== 'custom')
.map(o => ({ value: o, label: o })) || [],
resolutionOptions: resParam?.options
?.map(o => ({ value: o, label: o.toUpperCase() })) || [],
allowCustom: ratioParam?.options?.includes('custom') || false,
'proportionOptions': ratioParam?.options
?.filter((o) => o !== 'custom')
.map((o) => ({ value: o, label: o })) || [],
'resolutionOptions': resParam?.options
?.map((o) => ({ value: o, label: o.toUpperCase() })) || [],
'allowCustom': ratioParam?.options?.includes('custom') || false
}
},
}
},
{
name: 'dimension',
component: markRaw(DimensionInput),
show: (config) => !!config?.params?.find(p => p.ui === 'dimension' || p.ui === 'dimensionWidth'),
show: (config) => {
const hasDim = config?.params?.find((p) =>
(p.ui === 'dimension' || p.ui === 'dimensionWidth') && checkShowWhen(p, paramValues)
)
return !!hasDim
},
props: (config) => {
const dc = getDimConfig(config)
return {
width: dimWidth.value,
'width': dimWidth.value,
'onUpdate:width': (v) => { dimWidth.value = v },
height: dimHeight.value,
'height': dimHeight.value,
'onUpdate:height': (v) => { dimHeight.value = v },
minW: dc?.config?.width?.min || dc?.wParam?.min || 256,
maxW: dc?.config?.width?.max || dc?.wParam?.max || 6197,
minH: dc?.config?.height?.min || dc?.hParam?.min || 256,
maxH: dc?.config?.height?.max || dc?.hParam?.max || 4096,
'minW': dc?.config?.width?.min || dc?.wParam?.min || 256,
'maxW': dc?.config?.width?.max || dc?.wParam?.max || 6197,
'minH': dc?.config?.height?.min || dc?.hParam?.min || 256,
'maxH': dc?.config?.height?.max || dc?.hParam?.max || 4096
}
},
}
},
{
name: 'quality',
component: markRaw(QualitySelect),
show: (config) => !!config?.params?.find(p => p.name === 'quality'),
show: (config) => !!config?.params?.find((p) => p.name === 'quality'),
props: (config) => {
const q = config?.params?.find(p => p.name === 'quality')
const q = config?.params?.find((p) => p.name === 'quality')
return {
modelValue: quality.value,
'modelValue': quality.value,
'onUpdate:modelValue': (v) => { quality.value = v },
options: q?.options?.map(o => ({ value: o, label: o })) || [],
'options': q?.options?.map((o) => ({ value: o, label: o })) || []
}
},
}
},
{
name: 'quantity',
component: markRaw(Quantity),
show: (config) => !!config?.params?.find(p => p.ui === 'quantity'),
show: (config) => !!config?.params?.find((p) => p.ui === 'quantity'),
props: (config) => {
const qtyParam = config?.params?.find(p => p.ui === 'quantity')
const qtyParam = config?.params?.find((p) => p.ui === 'quantity')
return {
modelValue: quantity.value,
'modelValue': quantity.value,
'onUpdate:modelValue': (v) => { quantity.value = v },
max: qtyParam?.options?.length ? Math.max(...qtyParam.options) : 4,
'max': qtyParam?.options?.length ? Math.max(...qtyParam.options) : 4
}
},
},
}
}
]
const platform = {
@ -188,11 +154,18 @@ export function definePaintingPlatform() {
async loadModels() {
const code = getPlatformCode('Painting')
return fetchPlatformModels(code)
const models = await fetchPlatformModels(code)
if (models?.length) {
const modelIds = models.map((m) => m.id)
await preloadModelConfigs(modelIds)
}
return models
},
async loadConfig(modelName, _modelType) {
const config = getModelConfig(modelName)
const modelId = await getModelId('Painting', modelName)
if (!modelId) return null
const config = await getModelConfig(modelId)
syncDefaults(config)
return config
},
@ -216,12 +189,12 @@ export function definePaintingPlatform() {
imageUploadLimit() {
if (!modelConfig.value) return 4
const imageParam = modelConfig.value.params.find(p => p.ui === 'imageUpload')
const imageParam = modelConfig.value.params.find((p) => p.ui === 'imageUpload')
return imageParam?.maxCount || modelConfig.value.maxImages || 4
},
isImageRequired() {
return !!(modelConfig.value?.params?.find(p => p.ui === 'imageUpload'))
return !!(modelConfig.value?.params?.find((p) => p.ui === 'imageUpload'))
},
buildTaskBody(shared) {
@ -252,7 +225,7 @@ export function definePaintingPlatform() {
}
}
if (paramValues.quality !== undefined) quality.value = paramValues.quality
},
}
}
return platform