fix: gate video models by runtime availability
This commit is contained in:
@@ -202,6 +202,7 @@ const localModel = ref(props.data?.model || DEFAULT_VIDEO_MODEL)
|
||||
const localRatio = ref(props.data?.ratio || '16:9')
|
||||
const localDuration = ref(props.data?.dur || 5)
|
||||
const localResolution = ref(props.data?.resolution || currentModelDefaultResolution(props.data?.model || DEFAULT_VIDEO_MODEL))
|
||||
const availableVideoModels = computed(() => Array.isArray(modelStore.availableVideoModels) ? modelStore.availableVideoModels : [])
|
||||
|
||||
// Label editing state | Label 编辑状态
|
||||
const isEditingLabel = ref(false)
|
||||
@@ -245,10 +246,11 @@ const imagesByRole = computed(() => {
|
||||
// Get current model config | 获取当前模型配置
|
||||
const currentModelConfig = computed(() => getModelConfig(localModel.value))
|
||||
const isConfigured = computed(() => !!modelStore.currentApiKey)
|
||||
const canGenerate = computed(() => isConfigured.value && currentModelConfig.value?.available !== false)
|
||||
const currentModelAvailable = computed(() => availableVideoModels.value.some(model => model.key === localModel.value))
|
||||
const canGenerate = computed(() => isConfigured.value && currentModelAvailable.value && currentModelConfig.value?.available !== false)
|
||||
|
||||
// Model options from Pinia store (filtered by provider) | 从 Pinia store 获取模型选项(根据渠道过滤)
|
||||
const modelOptions = computed(() => modelStore.allVideoModelOptions)
|
||||
const modelOptions = computed(() => modelStore.videoModelOptions)
|
||||
|
||||
// Display model name | 显示模型名称
|
||||
const displayModelName = computed(() => {
|
||||
@@ -277,7 +279,8 @@ const resolutionOptions = computed(() => {
|
||||
})
|
||||
|
||||
// Handle model selection | 处理模型选择
|
||||
const handleModelSelect = (key) => {
|
||||
const applyModelSelection = (key) => {
|
||||
if (!key) return
|
||||
localModel.value = key
|
||||
// Update ratio and duration to model's default | 更新为模型默认比例和时长
|
||||
const config = getModelConfig(key)
|
||||
@@ -296,6 +299,28 @@ const handleModelSelect = (key) => {
|
||||
updateNode(props.id, updates)
|
||||
}
|
||||
|
||||
const syncModelWithAvailableOptions = () => {
|
||||
const availableModels = availableVideoModels.value
|
||||
if (!availableModels.length) return
|
||||
|
||||
const isModelAvailable = availableModels.some(model => model.key === localModel.value)
|
||||
if (!localModel.value || !isModelAvailable) {
|
||||
const selected = availableModels.find(model => model.key === modelStore.selectedVideoModel)?.key
|
||||
applyModelSelection(selected || availableModels[0]?.key || DEFAULT_VIDEO_MODEL)
|
||||
return
|
||||
}
|
||||
|
||||
const nextResolution = normalizeResolutionForModel(localModel.value, localResolution.value)
|
||||
if (nextResolution !== localResolution.value || !props.data?.resolution) {
|
||||
localResolution.value = nextResolution
|
||||
updateNode(props.id, { resolution: nextResolution })
|
||||
}
|
||||
}
|
||||
|
||||
const handleModelSelect = (key) => {
|
||||
applyModelSelection(key)
|
||||
}
|
||||
|
||||
// Handle duplicate | 处理复制
|
||||
const handleDuplicate = () => {
|
||||
const newNodeId = duplicateNode(props.id)
|
||||
@@ -530,23 +555,7 @@ const handleDelete = () => {
|
||||
|
||||
// Initialize on mount | 挂载时初始化
|
||||
onMounted(() => {
|
||||
// 检查当前模型是否在可用模型列表中
|
||||
const availableModels = modelStore.availableVideoModels
|
||||
const isModelAvailable = availableModels.some(m => m.key === localModel.value)
|
||||
|
||||
if (!localModel.value || !isModelAvailable) {
|
||||
// 使用 store 中的默认模型或第一个可用模型
|
||||
const selected = availableModels.find(m => m.key === modelStore.selectedVideoModel)?.key
|
||||
localModel.value = selected || availableModels[0]?.key || DEFAULT_VIDEO_MODEL
|
||||
localResolution.value = normalizeResolutionForModel(localModel.value, localResolution.value)
|
||||
updateNode(props.id, { model: localModel.value, resolution: localResolution.value })
|
||||
} else {
|
||||
const nextResolution = normalizeResolutionForModel(localModel.value, localResolution.value)
|
||||
if (nextResolution !== localResolution.value || !props.data?.resolution) {
|
||||
localResolution.value = nextResolution
|
||||
updateNode(props.id, { resolution: nextResolution })
|
||||
}
|
||||
}
|
||||
syncModelWithAvailableOptions()
|
||||
})
|
||||
|
||||
// Watch for model changes from props | 监听 props 中模型变化
|
||||
@@ -554,9 +563,16 @@ watch(() => props.data?.model, (newModel) => {
|
||||
if (newModel && newModel !== localModel.value) {
|
||||
localModel.value = newModel
|
||||
localResolution.value = normalizeResolutionForModel(newModel, props.data?.resolution || localResolution.value)
|
||||
syncModelWithAvailableOptions()
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => availableVideoModels.value.map(model => model.key).join('|'),
|
||||
() => syncModelWithAvailableOptions(),
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(() => props.data?.resolution, (newResolution) => {
|
||||
if (newResolution && newResolution !== localResolution.value) {
|
||||
localResolution.value = normalizeResolutionForModel(localModel.value, newResolution)
|
||||
|
||||
@@ -264,6 +264,7 @@ export const useModelStore = defineStore('model', () => {
|
||||
const customVideoModelsByProvider = ref(getStoredJson(STORAGE_KEYS.CUSTOM_VIDEO_MODELS_BY_PROVIDER, {}))
|
||||
const runtimeImageModels = ref([])
|
||||
const runtimeVideoModels = ref([])
|
||||
const runtimeVideoModelsLoaded = ref(false)
|
||||
|
||||
// 选中的模型
|
||||
const selectedChatModel = ref(getStored(STORAGE_KEYS.SELECTED_CHAT_MODEL, DEFAULT_CHAT_MODEL))
|
||||
@@ -317,7 +318,9 @@ export const useModelStore = defineStore('model', () => {
|
||||
)
|
||||
|
||||
const allVideoModels = computed(() =>
|
||||
mergeModels(VIDEO_MODELS, runtimeVideoModels.value)
|
||||
runtimeVideoModelsLoaded.value
|
||||
? runtimeVideoModels.value
|
||||
: mergeModels(VIDEO_MODELS, runtimeVideoModels.value)
|
||||
)
|
||||
|
||||
// ============ Computed: Available Models (filtered by provider) ============
|
||||
@@ -463,6 +466,10 @@ export const useModelStore = defineStore('model', () => {
|
||||
.filter(item => item?.id && item.available !== false)
|
||||
.map(normalizeRuntimeVideoModel)
|
||||
.filter(Boolean)
|
||||
runtimeVideoModelsLoaded.value = true
|
||||
if (!availableVideoModels.value.some(model => model.key === selectedVideoModel.value)) {
|
||||
selectedVideoModel.value = availableVideoModels.value[0]?.key || DEFAULT_VIDEO_MODEL
|
||||
}
|
||||
return true
|
||||
} catch (err) {
|
||||
console.warn('[model store] runtime model load failed', err)
|
||||
@@ -513,7 +520,7 @@ export const useModelStore = defineStore('model', () => {
|
||||
const image = allImageModels.value
|
||||
.filter(m => isModelSupported(m, provider))
|
||||
.map(m => ({ ...m, isCustom: false }))
|
||||
const video = VIDEO_MODELS
|
||||
const video = allVideoModels.value
|
||||
.filter(m => isModelSupported(m, provider))
|
||||
.map(m => ({ ...m, isCustom: false }))
|
||||
return { chat, image, video }
|
||||
@@ -629,6 +636,7 @@ export const useModelStore = defineStore('model', () => {
|
||||
allVideoModels,
|
||||
runtimeImageModels,
|
||||
runtimeVideoModels,
|
||||
runtimeVideoModelsLoaded,
|
||||
|
||||
// Available models filtered by provider
|
||||
availableChatModels,
|
||||
|
||||
Reference in New Issue
Block a user