Merge pull request #6233 from menloresearch/fix/import-model
fix: improve ux import model
This commit is contained in:
commit
6203a93325
55
src-tauri/Cargo.lock
generated
55
src-tauri/Cargo.lock
generated
@ -854,8 +854,18 @@ version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
"darling_core 0.20.11",
|
||||
"darling_macro 0.20.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08440b3dd222c3d0433e63e097463969485f112baff337dfdaca043a0d760570"
|
||||
dependencies = [
|
||||
"darling_core 0.21.2",
|
||||
"darling_macro 0.21.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -872,13 +882,38 @@ dependencies = [
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d25b7912bc28a04ab1b7715a68ea03aaa15662b43a1a4b2c480531fd19f8bf7e"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_core 0.20.11",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.21.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce154b9bea7fb0c8e8326e62d00354000c36e79770ff21b8c84e3aa267d9d531"
|
||||
dependencies = [
|
||||
"darling_core 0.21.2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
@ -3984,8 +4019,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmcp"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/modelcontextprotocol/rust-sdk?rev=3196c95f1dfafbffbdcdd6d365c94969ac975e6a#3196c95f1dfafbffbdcdd6d365c94969ac975e6a"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/modelcontextprotocol/rust-sdk?rev=209dbac50f51737ad953c3a2c8e28f3619b6c277#209dbac50f51737ad953c3a2c8e28f3619b6c277"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
@ -4010,10 +4045,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmcp-macros"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/modelcontextprotocol/rust-sdk?rev=3196c95f1dfafbffbdcdd6d365c94969ac975e6a#3196c95f1dfafbffbdcdd6d365c94969ac975e6a"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/modelcontextprotocol/rust-sdk?rev=209dbac50f51737ad953c3a2c8e28f3619b6c277#209dbac50f51737ad953c3a2c8e28f3619b6c277"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"darling 0.21.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_json",
|
||||
@ -4408,7 +4443,7 @@ version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"darling 0.20.11",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
@ -6868,7 +6903,7 @@ version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a76ff259533532054cfbaefb115c613203c73707017459206380f03b3b3f266e"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"darling 0.20.11",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
|
||||
@ -79,6 +79,7 @@ function ProviderDetail() {
|
||||
const [activeModels, setActiveModels] = useState<string[]>([])
|
||||
const [loadingModels, setLoadingModels] = useState<string[]>([])
|
||||
const [refreshingModels, setRefreshingModels] = useState(false)
|
||||
const [importingModel, setImportingModel] = useState(false)
|
||||
const { providerName } = useParams({ from: Route.id })
|
||||
const { getProviderByName, setProviders, updateProvider } = useModelProvider()
|
||||
const provider = getProviderByName(providerName)
|
||||
@ -95,6 +96,72 @@ function ProviderDetail() {
|
||||
!setting.controller_props.value)
|
||||
)
|
||||
|
||||
const handleImportModel = async () => {
|
||||
if (!provider) {
|
||||
return
|
||||
}
|
||||
|
||||
setImportingModel(true)
|
||||
const selectedFile = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [
|
||||
{
|
||||
name: 'GGUF',
|
||||
extensions: ['gguf'],
|
||||
},
|
||||
],
|
||||
})
|
||||
// If the dialog returns a file path, extract just the file name
|
||||
const fileName =
|
||||
typeof selectedFile === 'string'
|
||||
? selectedFile
|
||||
.split(/[\\/]/)
|
||||
.pop()
|
||||
?.replace(/\s/g, '-')
|
||||
: undefined
|
||||
|
||||
if (selectedFile && fileName) {
|
||||
// Check if model already exists
|
||||
const modelExists = provider.models.some(
|
||||
(model) => model.name === fileName
|
||||
)
|
||||
|
||||
if (modelExists) {
|
||||
toast.error('Model already exists', {
|
||||
description: `${fileName} already imported`,
|
||||
})
|
||||
setImportingModel(false)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await pullModel(fileName, selectedFile)
|
||||
// Refresh the provider to update the models list
|
||||
await getProviders().then(setProviders)
|
||||
toast.success(t('providers:import'), {
|
||||
id: `import-model-${provider.provider}`,
|
||||
description: t(
|
||||
'providers:importModelSuccess',
|
||||
{ provider: fileName }
|
||||
),
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(
|
||||
t('providers:importModelError'),
|
||||
error
|
||||
)
|
||||
toast.error(t('providers:importModelError'), {
|
||||
description: error instanceof Error ? error.message : 'Unknown error occurred',
|
||||
})
|
||||
} finally {
|
||||
setImportingModel(false)
|
||||
}
|
||||
} else {
|
||||
setImportingModel(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// Initial data fetch
|
||||
getActiveModels().then((models) => setActiveModels(models || []))
|
||||
@ -482,52 +549,23 @@ function ProviderDetail() {
|
||||
variant="link"
|
||||
size="sm"
|
||||
className="hover:no-underline"
|
||||
onClick={async () => {
|
||||
const selectedFile = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [
|
||||
{
|
||||
name: 'GGUF',
|
||||
extensions: ['gguf'],
|
||||
},
|
||||
],
|
||||
})
|
||||
// If the dialog returns a file path, extract just the file name
|
||||
const fileName =
|
||||
typeof selectedFile === 'string'
|
||||
? selectedFile.split(/[\\/]/).pop()
|
||||
: undefined
|
||||
|
||||
if (selectedFile && fileName) {
|
||||
try {
|
||||
await pullModel(fileName, selectedFile)
|
||||
} catch (error) {
|
||||
console.error(
|
||||
t('providers:importModelError'),
|
||||
error
|
||||
)
|
||||
} finally {
|
||||
// Refresh the provider to update the models list
|
||||
getProviders().then(setProviders)
|
||||
toast.success(t('providers:import'), {
|
||||
id: `import-model-${provider.provider}`,
|
||||
description: t(
|
||||
'providers:importModelSuccess',
|
||||
{ provider: provider.provider }
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
}}
|
||||
disabled={importingModel}
|
||||
onClick={handleImportModel}
|
||||
>
|
||||
<div className="cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/15 bg-main-view-fg/10 transition-all duration-200 ease-in-out p-1.5 py-1 gap-1 -mr-2">
|
||||
<IconFolderPlus
|
||||
size={18}
|
||||
className="text-main-view-fg/50"
|
||||
/>
|
||||
{importingModel ? (
|
||||
<IconLoader
|
||||
size={18}
|
||||
className="text-main-view-fg/50 animate-spin"
|
||||
/>
|
||||
) : (
|
||||
<IconFolderPlus
|
||||
size={18}
|
||||
className="text-main-view-fg/50"
|
||||
/>
|
||||
)}
|
||||
<span className="text-main-view-fg/70">
|
||||
{t('providers:import')}
|
||||
{importingModel ? 'Importing...' : t('providers:import')}
|
||||
</span>
|
||||
</div>
|
||||
</Button>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user