9090</template >
9191
9292<script setup lang="ts">
93- import { computed , ref , watch , reactive } from ' vue'
93+ import { computed , reactive , ref , watch } from ' vue'
9494import { useProviderStore } from ' @/stores/providerStore'
9595import { useModelStore } from ' @/stores/modelStore'
9696import type { LLM_PROVIDER , RENDERER_MODEL_META , VERTEX_PROVIDER } from ' @shared/presenter'
@@ -107,7 +107,6 @@ import { useModelCheckStore } from '@/stores/modelCheck'
107107import { levelToValueMap , safetyCategories } from ' @/lib/gemini'
108108import { Separator } from ' @shadcn/components/ui/separator'
109109import type { SafetyCategoryKey , SafetySettingValue } from ' @/lib/gemini'
110- import { useThrottleFn } from ' @vueuse/core'
111110import VoiceAIProviderConfig from ' ./VoiceAIProviderConfig.vue'
112111
113112interface ProviderWebsites {
@@ -118,8 +117,6 @@ interface ProviderWebsites {
118117 defaultBaseUrl: string
119118}
120119
121- // Types are imported from @/lib/gemini
122-
123120// Value to level mapping for Gemini safety settings
124121const valueToLevelMap: Record <SafetySettingValue , number > = {
125122 BLOCK_NONE: 0 ,
@@ -136,11 +133,11 @@ const props = defineProps<{
136133const providerStore = useProviderStore ()
137134const modelStore = useModelStore ()
138135const modelCheckStore = useModelCheckStore ()
139- const apiKey = ref (props .provider .apiKey || ' ' )
140- const apiHost = ref (props .provider .baseUrl || ' ' )
141136const azureApiVersion = ref (' ' )
142137const geminiSafetyLevels = reactive <Record <string , number >>({})
143138
139+ const emptyModels: RENDERER_MODEL_META [] = []
140+
144141const providerModels = ref <RENDERER_MODEL_META []>([])
145142const customModels = ref <RENDERER_MODEL_META []>([])
146143const isModelListLoading = ref (true )
@@ -168,15 +165,22 @@ const enabledModels = computed(() => {
168165const checkResult = ref <boolean >(false )
169166const showCheckModelDialog = ref (false )
170167
171- const providerWebsites = computed <ProviderWebsites | undefined >(() => {
172- const providerConfig = providerStore .defaultProviders .find ((provider ) => {
173- return provider .id === props .provider .id
174- })
175- if (providerConfig && providerConfig .websites ) {
176- return providerConfig .websites as ProviderWebsites
177- }
178- return undefined
179- })
168+ const providerWebsites = computed <ProviderWebsites | undefined >(
169+ () =>
170+ providerStore .defaultProviders .find ((provider ) => provider .id === props .provider .id )
171+ ?.websites as ProviderWebsites | undefined
172+ )
173+
174+ const providerModelsSource = computed (
175+ () =>
176+ modelStore .allProviderModels .find ((p ) => p .providerId === props .provider .id )?.models ??
177+ emptyModels
178+ )
179+
180+ const customModelsSource = computed (
181+ () =>
182+ modelStore .customModels .find ((p ) => p .providerId === props .provider .id )?.models ?? emptyModels
183+ )
180184
181185const validateApiKey = async () => {
182186 try {
@@ -199,122 +203,98 @@ const validateApiKey = async () => {
199203 }
200204}
201205
202- // Original initData implementation without debouncing
203- const _initData = async () => {
206+ const syncModels = () => {
204207 if (! hasInitializedModelList .value ) {
205208 isModelListLoading .value = true
206209 }
207210
208- try {
209- console .log (' initData for provider:' , props .provider .id )
210- const providerData = modelStore .allProviderModels .find (
211- (p ) => p .providerId === props .provider .id
212- )
213- if (providerData ) {
214- providerModels .value = providerData .models
215- } else {
216- providerModels .value = [] // Reset if provider data not found
217- }
218- const customModelData = modelStore .customModels .find ((p ) => p .providerId === props .provider .id )
219- if (customModelData ) {
220- customModels .value = customModelData .models
221- } else {
222- customModels .value = [] // Reset if custom data not found
211+ providerModels .value = providerModelsSource .value
212+ customModels .value = customModelsSource .value
213+
214+ if (! hasInitializedModelList .value ) {
215+ hasInitializedModelList .value = true
216+ }
217+ isModelListLoading .value = false
218+ }
219+
220+ watch (
221+ [providerModelsSource , customModelsSource ],
222+ () => {
223+ syncModels ()
224+ },
225+ { immediate: true }
226+ )
227+
228+ const initProviderSettings = async () => {
229+ console .log (' initData for provider:' , props .provider .id )
230+
231+ // Fetch Azure API Version if applicable
232+ if (props .provider .id === ' azure-openai' ) {
233+ try {
234+ azureApiVersion .value = await providerStore .getAzureApiVersion ()
235+ console .log (' Azure API Version fetched:' , azureApiVersion .value )
236+ } catch (error ) {
237+ console .error (' Failed to fetch Azure API Version:' , error )
238+ azureApiVersion .value = ' 2024-02-01' // Default value on error
223239 }
240+ }
224241
225- // Fetch Azure API Version if applicable
226- if (props .provider .id === ' azure-openai' ) {
242+ // Fetch Gemini Safety Settings if applicable
243+ if (props .provider .id === ' gemini' ) {
244+ console .log (' Fetching Gemini safety settings...' )
245+
246+ // 先清空现有数据
247+ Object .keys (geminiSafetyLevels ).forEach ((key ) => {
248+ delete geminiSafetyLevels [key ]
249+ })
250+
251+ for (const key in safetyCategories ) {
252+ const categoryKey = key as string
227253 try {
228- azureApiVersion .value = await providerStore .getAzureApiVersion ()
229- console .log (' Azure API Version fetched:' , azureApiVersion .value )
254+ const savedValue = (await providerStore .getGeminiSafety (categoryKey )) as
255+ | string
256+ | ' HARM_BLOCK_THRESHOLD_UNSPECIFIED'
257+ console .log (` Fetched Gemini safety for ${categoryKey }: ` , savedValue )
258+ geminiSafetyLevels [categoryKey ] =
259+ valueToLevelMap [savedValue as SafetySettingValue ] ??
260+ safetyCategories [categoryKey as SafetyCategoryKey ].defaultLevel
261+ console .log (` Set Gemini level for ${categoryKey }: ` , geminiSafetyLevels [categoryKey ])
230262 } catch (error ) {
231- console .error (' Failed to fetch Azure API Version:' , error )
232- azureApiVersion .value = ' 2024-02-01' // Default value on error
263+ console .error (` Failed to fetch Gemini safety setting for ${categoryKey }: ` , error )
264+ geminiSafetyLevels [categoryKey ] =
265+ safetyCategories [categoryKey as SafetyCategoryKey ].defaultLevel // Default on error
233266 }
234267 }
235268
236- // Fetch Gemini Safety Settings if applicable
237- if (props .provider .id === ' gemini' ) {
238- console .log (' Fetching Gemini safety settings...' )
239-
240- // 先清空现有数据
241- Object .keys (geminiSafetyLevels ).forEach ((key ) => {
242- delete geminiSafetyLevels [key ]
243- })
244-
245- for (const key in safetyCategories ) {
246- const categoryKey = key as string
247- try {
248- const savedValue = (await providerStore .getGeminiSafety (categoryKey )) as
249- | string
250- | ' HARM_BLOCK_THRESHOLD_UNSPECIFIED'
251- console .log (` Fetched Gemini safety for ${categoryKey }: ` , savedValue )
252- geminiSafetyLevels [categoryKey ] =
253- valueToLevelMap [savedValue as SafetySettingValue ] ??
254- safetyCategories [categoryKey as SafetyCategoryKey ].defaultLevel
255- console .log (` Set Gemini level for ${categoryKey }: ` , geminiSafetyLevels [categoryKey ])
256- } catch (error ) {
257- console .error (` Failed to fetch Gemini safety setting for ${categoryKey }: ` , error )
258- geminiSafetyLevels [categoryKey ] =
259- safetyCategories [categoryKey as SafetyCategoryKey ].defaultLevel // Default on error
260- }
261- }
262-
263- console .log (' All Gemini safety levels initialized:' , JSON .stringify (geminiSafetyLevels ))
264- }
265- } finally {
266- if (! hasInitializedModelList .value ) {
267- hasInitializedModelList .value = true
268- }
269- isModelListLoading .value = false
269+ console .log (' All Gemini safety levels initialized:' , JSON .stringify (geminiSafetyLevels ))
270270 }
271271}
272272
273- // Debounced version of initData to reduce frequent calls within 1 second
274- // Ensures the final call is always executed
275- const initData = useThrottleFn (_initData , 1000 , true , true )
276-
277- // Immediate version for scenarios that require instant initialization
278- const initDataImmediate = _initData
279-
280- // Flag to track if this is the first initialization
281- let isFirstInit = true
282-
283273watch (
284- () => props .provider ,
285- async () => {
286- apiKey .value = props .provider .apiKey || ' '
287- apiHost .value = props .provider .baseUrl || ' '
288-
289- // Use immediate version for first initialization, debounced version for subsequent changes
290- if (isFirstInit ) {
291- await initDataImmediate ()
292- isFirstInit = false
293- } else {
294- initData () // Use debounced version for frequent changes
295- }
274+ () => props .provider .id ,
275+ () => {
276+ initProviderSettings ()
296277 },
297- { immediate: true } // Removed deep: true as provider object itself changes
278+ { immediate: true }
298279)
299280
300- const handleApiKeyChange = async (value : string ) => {
301- await providerStore .updateProviderApi (props .provider .id , value , undefined )
302- }
281+ const handleApiKeyChange = (value : string ) =>
282+ providerStore .updateProviderApi (props .provider .id , value , undefined )
303283
304- const handleApiHostChange = async (value : string ) => {
305- await providerStore .updateProviderApi (props .provider .id , undefined , value )
306- }
284+ const handleApiHostChange = (value : string ) =>
285+ providerStore .updateProviderApi (props .provider .id , undefined , value )
307286
308287const handleModelEnabledChange = async (
309288 model : RENDERER_MODEL_META ,
310289 enabled : boolean ,
311- comfirm : boolean = false
290+ confirm : boolean = false
312291) => {
313- if (! enabled && comfirm ) {
292+ if (! enabled && confirm ) {
314293 disableModel (model )
315- } else {
316- await modelStore .updateModelStatus (props .provider .id , model .id , enabled )
294+ return
317295 }
296+
297+ await modelStore .updateModelStatus (props .provider .id , model .id , enabled )
318298}
319299
320300const disableModel = (model : RENDERER_MODEL_META ) => {
@@ -323,15 +303,18 @@ const disableModel = (model: RENDERER_MODEL_META) => {
323303}
324304
325305const confirmDisable = async () => {
326- if (modelToDisable .value ) {
327- try {
328- await modelStore .updateModelStatus (props .provider .id , modelToDisable .value .id , false )
329- } catch (error ) {
330- console .error (' Failed to disable model:' , error )
331- }
332- showConfirmDialog .value = false
333- modelToDisable .value = null
306+ if (! modelToDisable .value ) {
307+ return
334308 }
309+
310+ try {
311+ await modelStore .updateModelStatus (props .provider .id , modelToDisable .value .id , false )
312+ } catch (error ) {
313+ console .error (' Failed to disable model:' , error )
314+ }
315+
316+ showConfirmDialog .value = false
317+ modelToDisable .value = null
335318}
336319
337320const disableAllModelsConfirm = () => {
@@ -356,22 +339,6 @@ const confirmDeleteProvider = async () => {
356339 }
357340}
358341
359- watch (
360- () => modelStore .allProviderModels ,
361- () => {
362- initData ()
363- },
364- { deep: true }
365- )
366-
367- watch (
368- () => modelStore .customModels ,
369- () => {
370- initData ()
371- },
372- { deep: true }
373- )
374-
375342// Handler for Azure API Version change
376343const handleAzureApiVersionChange = async (value : string ) => {
377344 const trimmedValue = value .trim ()
@@ -395,8 +362,8 @@ const handleSafetySettingChange = async (key: SafetyCategoryKey, level: number)
395362// Handler for OAuth success
396363const handleOAuthSuccess = async () => {
397364 console .log (' OAuth authentication successful' )
398- // OAuth成功后立即刷新provider数据 (使用立即版本以快速显示结果 )
399- await initDataImmediate ()
365+ await initProviderSettings ( )
366+ syncModels ()
400367 // 可以自动验证一次
401368 await validateApiKey ()
402369}
@@ -409,22 +376,16 @@ const handleOAuthError = (error: string) => {
409376
410377// Handler for config changes
411378const handleConfigChanged = () => {
412- // 模型配置变更后重新初始化数据 (使用防抖版本)
413- initData ( )
379+ // 模型配置变更后先刷新provider模型数据,确保能看到最新的模型能力
380+ return modelStore . refreshProviderModels ( props . provider . id )
414381}
415382
416383const openModelCheckDialog = () => {
417384 modelCheckStore .openDialog (props .provider .id )
418385}
419386
420- const handleAddModelSaved = async () => {
421- await modelStore .refreshCustomModels (props .provider .id )
422- await initDataImmediate ()
423- }
387+ const handleAddModelSaved = () => modelStore .refreshProviderModels (props .provider .id )
424388
425389// 使用 computed 确保响应性正确传递
426- const geminiSafetyLevelsForChild = computed (() => {
427- // 创建一个新的对象确保响应性
428- return { ... geminiSafetyLevels }
429- })
390+ const geminiSafetyLevelsForChild = computed (() => ({ ... geminiSafetyLevels }))
430391 </script >
0 commit comments