diff --git a/web-app/src/routes/settings/providers/$providerName.tsx b/web-app/src/routes/settings/providers/$providerName.tsx index 6290e803b..cf95646f9 100644 --- a/web-app/src/routes/settings/providers/$providerName.tsx +++ b/web-app/src/routes/settings/providers/$providerName.tsx @@ -4,6 +4,8 @@ import ProvidersMenu from '@/containers/ProvidersMenu' import { useModelProvider } from '@/hooks/useModelProvider' import { cn, getProviderTitle } from '@/lib/utils' import { Switch } from '@/components/ui/switch' +import { open } from '@tauri-apps/plugin-dialog' +import { importModel } from '@/services/models' import { createFileRoute, Link, @@ -24,6 +26,10 @@ import { CustomTooltipJoyRide } from '@/containers/CustomeTooltipJoyRide' import { route } from '@/constants/routes' import DeleteProvider from '@/containers/dialogs/DeleteProvider' import { updateSettings } from '@/services/providers' +import { Button } from '@/components/ui/button' +import { IconFolderPlus } from '@tabler/icons-react' +import { getProviders } from '@/services/providers' +import { toast } from 'sonner' // as route.threadsDetail export const Route = createFileRoute('/settings/providers/$providerName')({ @@ -62,7 +68,7 @@ const steps = [ function ProviderDetail() { const { step } = useSearch({ from: Route.id }) const { providerName } = useParams({ from: Route.id }) - const { getProviderByName, updateProvider } = useModelProvider() + const { getProviderByName, setProviders, updateProvider } = useModelProvider() const provider = getProviderByName(providerName) const isSetup = step === 'setup_remote_provider' const navigate = useNavigate() @@ -167,7 +173,10 @@ function ProviderDetail() { ) { updateObj.base_url = newValue } - updateSettings(providerName, updateObj.settings ?? []) + updateSettings( + providerName, + updateObj.settings ?? [] + ) updateProvider(providerName, { ...provider, ...updateObj, @@ -229,7 +238,51 @@ function ProviderDetail() { Models
- {provider && } + {provider && provider.provider !== 'llama.cpp' && ( + + )} + {provider && provider.provider === 'llama.cpp' && ( + + )}
} diff --git a/web-app/src/services/models.ts b/web-app/src/services/models.ts index 296ca79fe..f5b3a243c 100644 --- a/web-app/src/services/models.ts +++ b/web-app/src/services/models.ts @@ -168,6 +168,42 @@ export const deleteModel = async (id: string) => { } } +/** + * Imports a model from a file path. + * @param filePath The path to the model file or an array of file paths. + * @param modelId Optional model ID. If not provided, it will be derived from the file name. + * @param provider The provider for the model (default: 'llama.cpp'). + * @returns A promise that resolves when the model is imported. + */ +export const importModel = async ( + filePath: string | string[], + modelId?: string, + provider: string = 'llama.cpp' +) => { + const extension = ExtensionManager.getInstance().get( + ExtensionTypeEnum.Model + ) + + if (!extension) throw new Error('Model extension not found') + + try { + // If filePath is an array, use the first element + const path = Array.isArray(filePath) ? filePath[0] : filePath + + // If no path was selected, throw an error + if (!path) throw new Error('No file selected') + + // Extract filename from path to use as model ID if not provided + const defaultModelId = path.split('/').pop()?.split('.')[0] || path + const modelIdToUse = modelId || defaultModelId + + return await extension.importModel(modelIdToUse, path, provider) + } catch (error) { + console.error('Failed to import model:', error) + throw error + } +} + /** * Configures the proxy options for model downloads. * @param param0