Skip to content

Commit 7a90f8f

Browse files
authored
fix: fix model list refresh failed (#1297)
1 parent f8266ba commit 7a90f8f

File tree

2 files changed

+108
-141
lines changed

2 files changed

+108
-141
lines changed

src/renderer/settings/components/ModelProviderSettingsDetail.vue

Lines changed: 102 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
</template>
9191

9292
<script setup lang="ts">
93-
import { computed, ref, watch, reactive } from 'vue'
93+
import { computed, reactive, ref, watch } from 'vue'
9494
import { useProviderStore } from '@/stores/providerStore'
9595
import { useModelStore } from '@/stores/modelStore'
9696
import type { LLM_PROVIDER, RENDERER_MODEL_META, VERTEX_PROVIDER } from '@shared/presenter'
@@ -107,7 +107,6 @@ import { useModelCheckStore } from '@/stores/modelCheck'
107107
import { levelToValueMap, safetyCategories } from '@/lib/gemini'
108108
import { Separator } from '@shadcn/components/ui/separator'
109109
import type { SafetyCategoryKey, SafetySettingValue } from '@/lib/gemini'
110-
import { useThrottleFn } from '@vueuse/core'
111110
import VoiceAIProviderConfig from './VoiceAIProviderConfig.vue'
112111
113112
interface 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
124121
const valueToLevelMap: Record<SafetySettingValue, number> = {
125122
BLOCK_NONE: 0,
@@ -136,11 +133,11 @@ const props = defineProps<{
136133
const providerStore = useProviderStore()
137134
const modelStore = useModelStore()
138135
const modelCheckStore = useModelCheckStore()
139-
const apiKey = ref(props.provider.apiKey || '')
140-
const apiHost = ref(props.provider.baseUrl || '')
141136
const azureApiVersion = ref('')
142137
const geminiSafetyLevels = reactive<Record<string, number>>({})
143138
139+
const emptyModels: RENDERER_MODEL_META[] = []
140+
144141
const providerModels = ref<RENDERER_MODEL_META[]>([])
145142
const customModels = ref<RENDERER_MODEL_META[]>([])
146143
const isModelListLoading = ref(true)
@@ -168,15 +165,22 @@ const enabledModels = computed(() => {
168165
const checkResult = ref<boolean>(false)
169166
const 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
181185
const 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-
283273
watch(
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
308287
const 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
320300
const disableModel = (model: RENDERER_MODEL_META) => {
@@ -323,15 +303,18 @@ const disableModel = (model: RENDERER_MODEL_META) => {
323303
}
324304
325305
const 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
337320
const 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
376343
const 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
396363
const 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
411378
const handleConfigChanged = () => {
412-
// 模型配置变更后重新初始化数据 (使用防抖版本)
413-
initData()
379+
// 模型配置变更后先刷新provider模型数据,确保能看到最新的模型能力
380+
return modelStore.refreshProviderModels(props.provider.id)
414381
}
415382
416383
const 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>

src/renderer/src/stores/modelStore.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ export const useModelStore = defineStore('model', () => {
260260
const query = getCustomModelsQuery(providerId)
261261
await query.refetch()
262262
const customModelsList = query.data.value ?? []
263+
const existingCustom =
264+
customModels.value.find((item) => item.providerId === providerId)?.models ?? []
265+
266+
if (customModelsList.length === 0 && existingCustom.length === 0) {
267+
return
268+
}
263269

264270
const modelIds = customModelsList.map((model) => model.id)
265271
const modelStatusMap =

0 commit comments

Comments
 (0)