| import { DownloadState } from '@janhq/core' |
| import { atom } from 'jotai' |
|
|
| import { toaster } from '@/containers/Toast' |
|
|
| import { |
| configuredModelsAtom, |
| downloadedModelsAtom, |
| removeDownloadingModelAtom, |
| } from '@/helpers/atoms/Model.atom' |
|
|
| |
| export const modelDownloadStateAtom = atom<Record<string, DownloadState>>({}) |
|
|
| |
| |
| |
| export const setDownloadStateAtom = atom( |
| null, |
| (get, set, state: DownloadState) => { |
| try { |
| const currentState = { ...get(modelDownloadStateAtom) } |
|
|
| if (state.downloadState === 'end') { |
| const modelDownloadState = currentState[state.modelId] |
|
|
| const updatedChildren: DownloadState[] = ( |
| modelDownloadState.children ?? [] |
| ).filter((m) => m.fileName !== state.fileName) |
| updatedChildren.push(state) |
| modelDownloadState.children = updatedChildren |
| currentState[state.modelId] = modelDownloadState |
|
|
| const isAllChildrenDownloadEnd = modelDownloadState.children?.every( |
| (m) => m.downloadState === 'end' |
| ) |
|
|
| if (isAllChildrenDownloadEnd) { |
| |
| delete currentState[state.modelId] |
| set(removeDownloadingModelAtom, state.modelId) |
|
|
| const model = get(configuredModelsAtom).find( |
| (e) => e.id === state.modelId |
| ) |
| if (model) set(downloadedModelsAtom, (prev) => [...prev, model]) |
| toaster({ |
| title: 'Download Completed', |
| description: `Download ${state.modelId} completed`, |
| type: 'success', |
| }) |
| } |
| } else if (state.downloadState === 'error') { |
| |
| delete currentState[state.modelId] |
| set(removeDownloadingModelAtom, state.modelId) |
| if (state.error === 'aborted') { |
| toaster({ |
| title: 'Cancel Download', |
| description: `Model ${state.modelId} download cancelled`, |
| type: 'warning', |
| }) |
| } else { |
| let error = state.error |
| if ( |
| typeof error?.includes === 'function' && |
| state.error?.includes('certificate') |
| ) { |
| error += |
| '. To fix enable "Ignore SSL Certificates" in Advanced settings.' |
| } |
| toaster({ |
| title: 'Download Failed', |
| description: `Model ${state.modelId} download failed: ${error}`, |
| type: 'error', |
| }) |
| } |
| } else { |
| |
| if (state.size.total === 0) { |
| |
| currentState[state.modelId] = state |
| set(modelDownloadStateAtom, currentState) |
| return |
| } |
|
|
| const modelDownloadState = currentState[state.modelId] |
| if (!modelDownloadState) { |
| console.debug('setDownloadStateAtom: modelDownloadState not found') |
| return |
| } |
|
|
| |
| const updatedChildren: DownloadState[] = ( |
| modelDownloadState.children ?? [] |
| ).filter((m) => m.fileName !== state.fileName) |
|
|
| updatedChildren.push(state) |
|
|
| |
| const isAnyChildDownloadNotReady = updatedChildren.some( |
| (m) => |
| m.size.total === 0 && |
| !modelDownloadState.children?.some( |
| (e) => e.fileName === m.fileName && e.downloadState === 'end' |
| ) && |
| modelDownloadState.children?.some((e) => e.fileName === m.fileName) |
| ) |
|
|
| modelDownloadState.children = updatedChildren |
| if (isAnyChildDownloadNotReady) { |
| |
| currentState[state.modelId] = modelDownloadState |
| set(modelDownloadStateAtom, currentState) |
| return |
| } |
|
|
| const parentTotalSize = modelDownloadState.size.total |
| if (parentTotalSize === 0) { |
| |
| const totalSize = updatedChildren.reduce( |
| (acc, m) => acc + m.size.total, |
| 0 |
| ) |
|
|
| modelDownloadState.size.total = totalSize |
| } |
|
|
| |
| const transferredSize = updatedChildren.reduce( |
| (acc, m) => acc + m.size.transferred, |
| 0 |
| ) |
| modelDownloadState.size.transferred = transferredSize |
| modelDownloadState.percent = |
| parentTotalSize === 0 ? 0 : transferredSize / parentTotalSize |
| currentState[state.modelId] = modelDownloadState |
| } |
|
|
| set(modelDownloadStateAtom, currentState) |
| } catch (e) { |
| console.debug('setDownloadStateAtom: state', state) |
| console.debug('setDownloadStateAtom: error', e) |
| } |
| } |
| ) |
|
|