From 5c60cb76612ce75e0cd9f0fa431167288eedf63f Mon Sep 17 00:00:00 2001 From: Doji Date: Thu, 18 Jun 2026 05:21:00 +0200 Subject: [PATCH] fix(stage-ui): sync module selections to active character card (#1979) --- packages/i18n/src/locales/en/settings.yaml | 3 + packages/i18n/src/locales/es/settings.yaml | 3 + packages/i18n/src/locales/fr/settings.yaml | 3 + packages/i18n/src/locales/ja/settings.yaml | 3 + packages/i18n/src/locales/ko/settings.yaml | 3 + packages/i18n/src/locales/ru/settings.yaml | 3 + packages/i18n/src/locales/vi/settings.yaml | 3 + .../i18n/src/locales/zh-Hans/settings.yaml | 3 + .../i18n/src/locales/zh-Hant/settings.yaml | 3 + .../components/CardCreationDialog.vue | 73 ++++++++++++++++++- .../airi-card/components/CardDetailDialog.vue | 41 +++++++++++ .../pages/settings/modules/consciousness.vue | 6 ++ .../src/pages/settings/modules/speech.vue | 4 + .../src/pages/settings/modules/vision.vue | 6 ++ .../stage-ui/src/stores/character.test.ts | 4 + .../character/orchestrator/index.test.ts | 4 + .../src/stores/modules/airi-card.test.ts | 31 ++++++-- .../stage-ui/src/stores/modules/airi-card.ts | 71 ++++++++++++++++-- 18 files changed, 253 insertions(+), 14 deletions(-) diff --git a/packages/i18n/src/locales/en/settings.yaml b/packages/i18n/src/locales/en/settings.yaml index f9c97a1e2..21d5bb848 100644 --- a/packages/i18n/src/locales/en/settings.yaml +++ b/packages/i18n/src/locales/en/settings.yaml @@ -324,6 +324,9 @@ pages: provider: Chat / Provider consciousness: model: Consciousness / Model + vision: + provider: Vision / Provider + model: Vision / Model created_by: created by creator_notes: Creator Notes delete: Delete diff --git a/packages/i18n/src/locales/es/settings.yaml b/packages/i18n/src/locales/es/settings.yaml index 4219b6db8..0652717ca 100644 --- a/packages/i18n/src/locales/es/settings.yaml +++ b/packages/i18n/src/locales/es/settings.yaml @@ -310,6 +310,9 @@ pages: provider: Chat / Proveedor consciousness: model: Consciencia / Modelo + vision: + provider: Visión / Proveedor + model: Visión / Modelo created_by: creado por creator_notes: Notas del Creador delete: Eliminar diff --git a/packages/i18n/src/locales/fr/settings.yaml b/packages/i18n/src/locales/fr/settings.yaml index d206c1a61..160e98645 100644 --- a/packages/i18n/src/locales/fr/settings.yaml +++ b/packages/i18n/src/locales/fr/settings.yaml @@ -310,6 +310,9 @@ pages: provider: Chat / Fournisseur consciousness: model: Conscience / Modèle + vision: + provider: Vision / Fournisseur + model: Vision / Modèle created_by: créé par creator_notes: Notes du créateur delete: Supprimer diff --git a/packages/i18n/src/locales/ja/settings.yaml b/packages/i18n/src/locales/ja/settings.yaml index 9f735c871..677d46982 100644 --- a/packages/i18n/src/locales/ja/settings.yaml +++ b/packages/i18n/src/locales/ja/settings.yaml @@ -310,6 +310,9 @@ pages: provider: チャット / プロバイダー consciousness: model: 意識 / モデル + vision: + provider: ビジョン / プロバイダー + model: ビジョン / モデル created_by: 作成者 creator_notes: 作成者のメモ delete: 削除 diff --git a/packages/i18n/src/locales/ko/settings.yaml b/packages/i18n/src/locales/ko/settings.yaml index 5d9353136..d08801173 100644 --- a/packages/i18n/src/locales/ko/settings.yaml +++ b/packages/i18n/src/locales/ko/settings.yaml @@ -310,6 +310,9 @@ pages: provider: 채팅 / 제공자 consciousness: model: 의식 / 모델 + vision: + provider: 비전 / 제공자 + model: 비전 / 모델 created_by: 만든이 creator_notes: 제작자 노트 delete: 삭제 diff --git a/packages/i18n/src/locales/ru/settings.yaml b/packages/i18n/src/locales/ru/settings.yaml index c853e2f82..6c6433d5e 100644 --- a/packages/i18n/src/locales/ru/settings.yaml +++ b/packages/i18n/src/locales/ru/settings.yaml @@ -310,6 +310,9 @@ pages: provider: Чат / провайдеры consciousness: model: Сознание / Модель + vision: + provider: Зрение / Провайдер + model: Зрение / Модель created_by: создано creator_notes: Заметки автора delete: Удалить diff --git a/packages/i18n/src/locales/vi/settings.yaml b/packages/i18n/src/locales/vi/settings.yaml index 1beae3ff5..6971b9cb5 100644 --- a/packages/i18n/src/locales/vi/settings.yaml +++ b/packages/i18n/src/locales/vi/settings.yaml @@ -310,6 +310,9 @@ pages: provider: Trò chuyện / Nhà cung cấp consciousness: model: Ý thức / Mô hình + vision: + provider: Thị giác / Nhà cung cấp + model: Thị giác / Mô hình created_by: được tạo bởi creator_notes: Ghi chú của tác giả delete: Xóa diff --git a/packages/i18n/src/locales/zh-Hans/settings.yaml b/packages/i18n/src/locales/zh-Hans/settings.yaml index 0f04934c9..82c8f1f6e 100644 --- a/packages/i18n/src/locales/zh-Hans/settings.yaml +++ b/packages/i18n/src/locales/zh-Hans/settings.yaml @@ -310,6 +310,9 @@ pages: provider: 聊天 / 提供商 consciousness: model: 意识 / 模型 + vision: + provider: 视觉 / 提供商 + model: 视觉 / 模型 created_by: 创建者 creator_notes: 创建者笔记 delete: 删除 diff --git a/packages/i18n/src/locales/zh-Hant/settings.yaml b/packages/i18n/src/locales/zh-Hant/settings.yaml index 32b022d79..06cbb6408 100644 --- a/packages/i18n/src/locales/zh-Hant/settings.yaml +++ b/packages/i18n/src/locales/zh-Hant/settings.yaml @@ -310,6 +310,9 @@ pages: provider: 聊天 / 供應商 consciousness: model: 意識 / 模型 + vision: + provider: 視覺 / 供應商 + model: 視覺 / 模型 created_by: 建立者 creator_notes: 建立者筆記 delete: 刪除 diff --git a/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue b/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue index 2f2647787..a57628456 100644 --- a/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue +++ b/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue @@ -11,6 +11,7 @@ import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card' import { useArtistryStore } from '@proj-airi/stage-ui/stores/modules/artistry' import { useConsciousnessStore } from '@proj-airi/stage-ui/stores/modules/consciousness' import { useSpeechStore } from '@proj-airi/stage-ui/stores/modules/speech' +import { useVisionStore } from '@proj-airi/stage-ui/stores/modules/vision' import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers' import { useSettingsStageModel } from '@proj-airi/stage-ui/stores/settings/stage-model' import { Button, FieldInput, FieldValues } from '@proj-airi/ui' @@ -59,6 +60,7 @@ const modelValue = defineModel() const { t } = useI18n() const cardStore = useAiriCardStore() const consciousnessStore = useConsciousnessStore() +const visionStore = useVisionStore() const speechStore = useSpeechStore() const providersStore = useProvidersStore() const displayModelsStore = useDisplayModelsStore() @@ -66,6 +68,7 @@ const stageModelStore = useSettingsStageModel() const artistryStore = useArtistryStore() const { activeProvider: consciousnessProvider, activeModel: defaultConsciousnessModel } = storeToRefs(consciousnessStore) +const { activeProvider: visionProvider, activeModel: defaultVisionModel } = storeToRefs(visionStore) const { activeSpeechProvider: speechProvider, activeSpeechModel: defaultSpeechModel, activeSpeechVoiceId: defaultSpeechVoiceId } = storeToRefs(speechStore) const { displayModels } = storeToRefs(displayModelsStore) const { stageModelSelected: defaultDisplayModelId } = storeToRefs(stageModelStore) @@ -77,6 +80,8 @@ const isEditMode = computed(() => !!props.cardId) // Modules configuration const selectedConsciousnessProvider = ref('') const selectedConsciousnessModel = ref('') +const selectedVisionProvider = ref('') +const selectedVisionModel = ref('') const selectedSpeechProvider = ref('') const selectedSpeechModel = ref('') const selectedSpeechVoiceId = ref('') @@ -120,6 +125,26 @@ const consciousnessModelOptions = computed(() => { })) }) +// Computed: available vision provider options +const visionProviderOptions = computed(() => { + return providersStore.configuredVisionProvidersMetadata.map(provider => ({ + value: provider.id, + label: provider.localizedName || provider.name, + })) +}) + +// Computed: available vision models options +const visionModelOptions = computed(() => { + const provider = selectedVisionProvider.value || visionProvider.value + if (!provider) + return [] + const models = providersStore.getModelsForProvider(provider) + return models.map(model => ({ + value: model.id, + label: model.name || model.id, + })) +}) + // Computed: available speech provider options const speechProviderOptions = computed(() => { return providersStore.configuredSpeechProvidersMetadata.map(provider => ({ @@ -167,10 +192,13 @@ const artistryProviderOptions = computed(() => { }) // Load models for current providers on init -watch(() => [consciousnessProvider.value, speechProvider.value], async ([consProvider, spProvider]) => { +watch(() => [consciousnessProvider.value, visionProvider.value, speechProvider.value], async ([consProvider, visProvider, spProvider]) => { if (consProvider) { await consciousnessStore.loadModelsForProvider(consProvider) } + if (visProvider) { + await visionStore.loadModelsForProvider(visProvider) + } if (spProvider) { await speechStore.loadVoicesForProvider(spProvider) const metadata = providersStore.getProviderMetadata(spProvider) @@ -189,6 +217,14 @@ watch(selectedConsciousnessProvider, async (newProvider, oldProvider) => { } }) +// Watch vision provider changes and reload models +watch(selectedVisionProvider, async (newProvider, oldProvider) => { + if (oldProvider !== undefined && newProvider !== oldProvider && newProvider) { + await visionStore.loadModelsForProvider(newProvider) + selectedVisionModel.value = '' + } +}) + // Watch speech provider changes and reload models/voices watch(selectedSpeechProvider, async (newProvider, oldProvider) => { if (oldProvider !== undefined && newProvider !== oldProvider && newProvider) { @@ -353,6 +389,10 @@ function saveCard(card: Card): boolean { provider: selectedConsciousnessProvider.value || consciousnessProvider.value, model: selectedConsciousnessModel.value || defaultConsciousnessModel.value, }, + vision: { + provider: selectedVisionProvider.value || visionProvider.value, + model: selectedVisionModel.value || defaultVisionModel.value, + }, speech: { provider: selectedSpeechProvider.value || speechProvider.value, model: selectedSpeechModel.value || defaultSpeechModel.value, @@ -398,6 +438,8 @@ function initializeCard(): Card { // Initialize module selections with fallback logic (handles all cases: create, edit with/without extension) selectedConsciousnessProvider.value = airiExt?.modules?.consciousness?.provider || consciousnessProvider.value selectedConsciousnessModel.value = airiExt?.modules?.consciousness?.model || defaultConsciousnessModel.value + selectedVisionProvider.value = airiExt?.modules?.vision?.provider || visionProvider.value + selectedVisionModel.value = airiExt?.modules?.vision?.model || defaultVisionModel.value selectedSpeechProvider.value = airiExt?.modules?.speech?.provider || speechProvider.value selectedSpeechModel.value = airiExt?.modules?.speech?.model || defaultSpeechModel.value selectedSpeechVoiceId.value = airiExt?.modules?.speech?.voice_id || defaultSpeechVoiceId.value @@ -594,6 +636,35 @@ function getDefaultPlaceholder(defaultValue: string | undefined): string { /> + +
+