🐛fix: immediately show download progress (#5308)
This commit is contained in:
parent
a745d24fbe
commit
f0ec3e03d1
@ -19,7 +19,13 @@ export function DownloadManagement() {
|
||||
const { setProviders } = useModelProvider()
|
||||
const { open: isLeftPanelOpen } = useLeftPanel()
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false)
|
||||
const { downloads, updateProgress, removeDownload } = useDownloadStore()
|
||||
const {
|
||||
downloads,
|
||||
updateProgress,
|
||||
localDownloadingModels,
|
||||
removeDownload,
|
||||
removeLocalDownloadingModel,
|
||||
} = useDownloadStore()
|
||||
const { updateState } = useAppUpdater()
|
||||
|
||||
const [appUpdateState, setAppUpdateState] = useState({
|
||||
@ -76,23 +82,36 @@ export function DownloadManagement() {
|
||||
})
|
||||
}, [])
|
||||
|
||||
const downloadCount = useMemo(() => {
|
||||
const modelDownloads = Object.keys(downloads).length
|
||||
const appUpdateDownload = appUpdateState.isDownloading ? 1 : 0
|
||||
const total = modelDownloads + appUpdateDownload
|
||||
return total
|
||||
}, [downloads, appUpdateState.isDownloading])
|
||||
const downloadProcesses = useMemo(
|
||||
() =>
|
||||
Object.values(downloads).map((download) => ({
|
||||
const downloadProcesses = useMemo(() => {
|
||||
// Get downloads with progress data
|
||||
const downloadsWithProgress = Object.values(downloads).map((download) => ({
|
||||
id: download.name,
|
||||
name: download.name,
|
||||
progress: download.progress,
|
||||
current: download.current,
|
||||
total: download.total,
|
||||
})),
|
||||
[downloads]
|
||||
)
|
||||
}))
|
||||
|
||||
// Add local downloading models that don't have progress data yet
|
||||
const localDownloadsWithoutProgress = Array.from(localDownloadingModels)
|
||||
.filter((modelId) => !downloads[modelId]) // Only include models not in downloads
|
||||
.map((modelId) => ({
|
||||
id: modelId,
|
||||
name: modelId,
|
||||
progress: 0,
|
||||
current: 0,
|
||||
total: 0,
|
||||
}))
|
||||
|
||||
return [...downloadsWithProgress, ...localDownloadsWithoutProgress]
|
||||
}, [downloads, localDownloadingModels])
|
||||
|
||||
const downloadCount = useMemo(() => {
|
||||
const modelDownloads = downloadProcesses.length
|
||||
const appUpdateDownload = appUpdateState.isDownloading ? 1 : 0
|
||||
const total = modelDownloads + appUpdateDownload
|
||||
return total
|
||||
}, [downloadProcesses, appUpdateState.isDownloading])
|
||||
|
||||
const overallProgress = useMemo(() => {
|
||||
const modelTotal = downloadProcesses.reduce((acc, download) => {
|
||||
@ -139,29 +158,32 @@ export function DownloadManagement() {
|
||||
(state: DownloadState) => {
|
||||
console.debug('onFileDownloadError', state)
|
||||
removeDownload(state.modelId)
|
||||
removeLocalDownloadingModel(state.modelId)
|
||||
},
|
||||
[removeDownload]
|
||||
[removeDownload, removeLocalDownloadingModel]
|
||||
)
|
||||
|
||||
const onFileDownloadStopped = useCallback(
|
||||
(state: DownloadState) => {
|
||||
console.debug('onFileDownloadError', state)
|
||||
removeDownload(state.modelId)
|
||||
removeLocalDownloadingModel(state.modelId)
|
||||
},
|
||||
[removeDownload]
|
||||
[removeDownload, removeLocalDownloadingModel]
|
||||
)
|
||||
|
||||
const onFileDownloadSuccess = useCallback(
|
||||
async (state: DownloadState) => {
|
||||
console.debug('onFileDownloadSuccess', state)
|
||||
removeDownload(state.modelId)
|
||||
removeLocalDownloadingModel(state.modelId)
|
||||
getProviders().then(setProviders)
|
||||
toast.success('Download Complete', {
|
||||
id: 'download-complete',
|
||||
description: `The model ${state.modelId} has been downloaded`,
|
||||
})
|
||||
},
|
||||
[removeDownload, setProviders]
|
||||
[removeDownload, removeLocalDownloadingModel, setProviders]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
@ -264,12 +286,16 @@ export function DownloadManagement() {
|
||||
/>
|
||||
<p className="text-main-view-fg/60 text-xs">
|
||||
{`${renderGB(appUpdateState.downloadedBytes)} / ${renderGB(appUpdateState.totalBytes)}`}{' '}
|
||||
GB ({Math.round(appUpdateState.downloadProgress * 100)}%)
|
||||
GB ({Math.round(appUpdateState.downloadProgress * 100)}
|
||||
%)
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{downloadProcesses.map((download) => (
|
||||
<div className="bg-main-view-fg/4 rounded-md p-2">
|
||||
<div
|
||||
key={download.id}
|
||||
className="bg-main-view-fg/4 rounded-md p-2"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="truncate text-main-view-fg/80">
|
||||
{download.name}
|
||||
@ -299,8 +325,9 @@ export function DownloadManagement() {
|
||||
className="my-2"
|
||||
/>
|
||||
<p className="text-main-view-fg/60 text-xs">
|
||||
{`${renderGB(download.current)} / ${renderGB(download.total)}`}{' '}
|
||||
GB ({Math.round(download.progress * 100)}%)
|
||||
{download.total > 0
|
||||
? `${renderGB(download.current)} / ${renderGB(download.total)} GB (${Math.round(download.progress * 100)}%)`
|
||||
: 'Initializing download...'}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@ -11,6 +11,7 @@ export interface DownloadProgressProps {
|
||||
// Zustand store for thinking block state
|
||||
export type DownloadState = {
|
||||
downloads: { [id: string]: DownloadProgressProps }
|
||||
localDownloadingModels: Set<string>
|
||||
removeDownload: (id: string) => void
|
||||
updateProgress: (
|
||||
id: string,
|
||||
@ -19,6 +20,8 @@ export type DownloadState = {
|
||||
current?: number,
|
||||
total?: number
|
||||
) => void
|
||||
addLocalDownloadingModel: (modelId: string) => void
|
||||
removeLocalDownloadingModel: (modelId: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,6 +29,7 @@ export type DownloadState = {
|
||||
*/
|
||||
export const useDownloadStore = create<DownloadState>((set) => ({
|
||||
downloads: {},
|
||||
localDownloadingModels: new Set(),
|
||||
removeDownload: (id: string) =>
|
||||
set((state) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@ -46,4 +50,18 @@ export const useDownloadStore = create<DownloadState>((set) => ({
|
||||
},
|
||||
},
|
||||
})),
|
||||
|
||||
addLocalDownloadingModel: (modelId: string) =>
|
||||
set((state) => ({
|
||||
localDownloadingModels: new Set(state.localDownloadingModels).add(
|
||||
modelId
|
||||
),
|
||||
})),
|
||||
|
||||
removeLocalDownloadingModel: (modelId: string) =>
|
||||
set((state) => {
|
||||
const newSet = new Set(state.localDownloadingModels)
|
||||
newSet.delete(modelId)
|
||||
return { localDownloadingModels: newSet }
|
||||
}),
|
||||
}))
|
||||
|
||||
@ -182,7 +182,8 @@ function Hub() {
|
||||
}
|
||||
}
|
||||
|
||||
const { downloads } = useDownloadStore()
|
||||
const { downloads, localDownloadingModels, addLocalDownloadingModel } =
|
||||
useDownloadStore()
|
||||
|
||||
const downloadProcesses = useMemo(
|
||||
() =>
|
||||
@ -225,7 +226,9 @@ function Hub() {
|
||||
model.models.find((e) =>
|
||||
defaultModelQuantizations.some((m) => e.id.toLowerCase().includes(m))
|
||||
)?.id ?? model.models[0]?.id
|
||||
const isDownloading = downloadProcesses.some((e) => e.id === modelId)
|
||||
const isDownloading =
|
||||
localDownloadingModels.has(modelId) ||
|
||||
downloadProcesses.some((e) => e.id === modelId)
|
||||
const downloadProgress =
|
||||
downloadProcesses.find((e) => e.id === modelId)?.progress || 0
|
||||
const isDownloaded = llamaProvider?.models.some(
|
||||
@ -233,6 +236,12 @@ function Hub() {
|
||||
)
|
||||
const isRecommended = isRecommendedModel(model.metadata?.id)
|
||||
|
||||
const handleDownload = () => {
|
||||
// Immediately set local downloading state
|
||||
addLocalDownloadingModel(modelId)
|
||||
downloadModel(modelId)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@ -255,7 +264,7 @@ function Hub() {
|
||||
) : (
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => downloadModel(modelId)}
|
||||
onClick={handleDownload}
|
||||
className={cn(isDownloading && 'hidden')}
|
||||
ref={isRecommended ? downloadButtonRef : undefined}
|
||||
>
|
||||
@ -271,6 +280,8 @@ function Hub() {
|
||||
handleUseModel,
|
||||
isRecommendedModel,
|
||||
downloadButtonRef,
|
||||
localDownloadingModels,
|
||||
addLocalDownloadingModel,
|
||||
])
|
||||
|
||||
const { step } = useSearch({ from: Route.id })
|
||||
@ -320,7 +331,8 @@ function Hub() {
|
||||
}
|
||||
|
||||
// Check if any model is currently downloading
|
||||
const isDownloading = downloadProcesses.length > 0
|
||||
const isDownloading =
|
||||
localDownloadingModels.size > 0 || downloadProcesses.length > 0
|
||||
|
||||
const steps = [
|
||||
{
|
||||
@ -553,6 +565,9 @@ function Hub() {
|
||||
</p>
|
||||
{(() => {
|
||||
const isDownloading =
|
||||
localDownloadingModels.has(
|
||||
variant.id
|
||||
) ||
|
||||
downloadProcesses.some(
|
||||
(e) => e.id === variant.id
|
||||
)
|
||||
@ -607,9 +622,12 @@ function Hub() {
|
||||
<div
|
||||
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
||||
title="Download model"
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
addLocalDownloadingModel(
|
||||
variant.id
|
||||
)
|
||||
downloadModel(variant.id)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<IconDownload
|
||||
size={16}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user