From 8046f95b672bcdb181f329a1a4524953dfb3877d Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Thu, 29 May 2025 22:06:25 +0700 Subject: [PATCH] feat: add refresh button list model remote provider (#5136) --- .../settings/providers/$providerName.tsx | 88 ++++++++++++++++++- web-app/src/services/providers.ts | 54 ++++++++++++ 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/web-app/src/routes/settings/providers/$providerName.tsx b/web-app/src/routes/settings/providers/$providerName.tsx index 9a88d19b7..e727c37c9 100644 --- a/web-app/src/routes/settings/providers/$providerName.tsx +++ b/web-app/src/routes/settings/providers/$providerName.tsx @@ -30,9 +30,9 @@ import Joyride, { CallBackProps, STATUS } from 'react-joyride' import { CustomTooltipJoyRide } from '@/containers/CustomeTooltipJoyRide' import { route } from '@/constants/routes' import DeleteProvider from '@/containers/dialogs/DeleteProvider' -import { updateSettings } from '@/services/providers' +import { updateSettings, fetchModelsFromProvider } from '@/services/providers' import { Button } from '@/components/ui/button' -import { IconFolderPlus, IconLoader } from '@tabler/icons-react' +import { IconFolderPlus, IconLoader, IconRefresh } from '@tabler/icons-react' import { getProviders } from '@/services/providers' import { toast } from 'sonner' import { ActiveModel } from '@/types/models' @@ -76,6 +76,7 @@ function ProviderDetail() { const { step } = useSearch({ from: Route.id }) const [activeModels, setActiveModels] = useState([]) const [loadingModels, setLoadingModels] = useState([]) + const [refreshingModels, setRefreshingModels] = useState(false) const { providerName } = useParams({ from: Route.id }) const { getProviderByName, setProviders, updateProvider } = useModelProvider() const provider = getProviderByName(providerName) @@ -104,6 +105,61 @@ function ProviderDetail() { } } + const handleRefreshModels = async () => { + if (!provider || !provider.base_url) { + toast.error('Refresh Models', { + description: + 'Provider must have base URL and API key configured to fetch models.', + }) + return + } + + setRefreshingModels(true) + try { + const modelIds = await fetchModelsFromProvider(provider) + + // Create new models from the fetched IDs + const newModels: Model[] = modelIds.map((id) => ({ + id, + model: id, + name: id, + capabilities: ['completion'], // Default capability + version: '1.0', + })) + + // Filter out models that already exist + const existingModelIds = provider.models.map((m) => m.id) + const modelsToAdd = newModels.filter( + (model) => !existingModelIds.includes(model.id) + ) + + if (modelsToAdd.length > 0) { + // Update the provider with new models + const updatedModels = [...provider.models, ...modelsToAdd] + updateProvider(providerName, { + ...provider, + models: updatedModels, + }) + + toast.success('Refresh Models', { + description: `Added ${modelsToAdd.length} new model(s) from ${provider.provider}.`, + }) + } else { + toast.success('Refresh Models', { + description: + 'No new models found. All available models are already added.', + }) + } + } catch (error) { + console.error('Failed to refresh models:', error) + toast.error('Refresh Models', { + description: `Failed to fetch models from ${provider.provider}. Please check your API key and base URL.`, + }) + } finally { + setRefreshingModels(false) + } + } + const handleStartModel = (modelId: string) => { // Add model to loading state setLoadingModels((prev) => [...prev, modelId]) @@ -292,7 +348,33 @@ function ProviderDetail() {
{provider && provider.provider !== 'llama.cpp' && ( - + <> + + + )} {provider && provider.provider === 'llama.cpp' && (