display models that have not been fully downloaded in Downloads page, even if the program is restarted
This commit is contained in:
parent
447f4572b1
commit
97f6af595e
@ -126,7 +126,7 @@ export const RunButton: FC<{ onClickRun?: MouseEventHandler, iconMode?: boolean
|
|||||||
showDownloadPrompt(t('Model file not found'), modelName);
|
showDownloadPrompt(t('Model file not found'), modelName);
|
||||||
commonStore.setStatus({ status: ModelStatus.Offline });
|
commonStore.setStatus({ status: ModelStatus.Offline });
|
||||||
return;
|
return;
|
||||||
} else if (!currentModelSource?.isLocal) {
|
} else if (!currentModelSource?.isComplete) {
|
||||||
showDownloadPrompt(t('Model file download is not complete'), modelName);
|
showDownloadPrompt(t('Model file download is not complete'), modelName);
|
||||||
commonStore.setStatus({ status: ModelStatus.Offline });
|
commonStore.setStatus({ status: ModelStatus.Offline });
|
||||||
return;
|
return;
|
||||||
|
@ -224,12 +224,12 @@ export const Configs: FC = observer(() => {
|
|||||||
modelName: data.value
|
modelName: data.value
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
{!commonStore.modelSourceList.find(item => item.name === selectedConfig.modelParameters.modelName)?.isLocal
|
{!commonStore.modelSourceList.find(item => item.name === selectedConfig.modelParameters.modelName)?.isComplete
|
||||||
&& <option key={-1}
|
&& <option key={-1}
|
||||||
value={selectedConfig.modelParameters.modelName}>{selectedConfig.modelParameters.modelName}
|
value={selectedConfig.modelParameters.modelName}>{selectedConfig.modelParameters.modelName}
|
||||||
</option>}
|
</option>}
|
||||||
{commonStore.modelSourceList.map((modelItem, index) =>
|
{commonStore.modelSourceList.map((modelItem, index) =>
|
||||||
modelItem.isLocal && <option key={index} value={modelItem.name}>{modelItem.name}</option>
|
modelItem.isComplete && <option key={index} value={modelItem.name}>{modelItem.name}</option>
|
||||||
)}
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
<ToolTipButton desc={t('Manage Models')} icon={<DataUsageSettings20Regular />} onClick={() => {
|
<ToolTipButton desc={t('Manage Models')} icon={<DataUsageSettings20Regular />} onClick={() => {
|
||||||
|
@ -7,7 +7,7 @@ import { Divider, Field, ProgressBar } from '@fluentui/react-components';
|
|||||||
import { bytesToGb, bytesToKb, bytesToMb, refreshLocalModels } from '../utils';
|
import { bytesToGb, bytesToKb, bytesToMb, refreshLocalModels } from '../utils';
|
||||||
import { ToolTipButton } from '../components/ToolTipButton';
|
import { ToolTipButton } from '../components/ToolTipButton';
|
||||||
import { Folder20Regular, Pause20Regular, Play20Regular } from '@fluentui/react-icons';
|
import { Folder20Regular, Pause20Regular, Play20Regular } from '@fluentui/react-icons';
|
||||||
import { ContinueDownload, OpenFileFolder, PauseDownload } from '../../wailsjs/go/backend_golang/App';
|
import { AddToDownloadList, OpenFileFolder, PauseDownload } from '../../wailsjs/go/backend_golang/App';
|
||||||
|
|
||||||
export type DownloadStatus = {
|
export type DownloadStatus = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -30,10 +30,27 @@ export const Downloads: FC = observer(() => {
|
|||||||
console.log('finishedModelsLen:', finishedModelsLen);
|
console.log('finishedModelsLen:', finishedModelsLen);
|
||||||
}, [finishedModelsLen]);
|
}, [finishedModelsLen]);
|
||||||
|
|
||||||
|
let displayList = commonStore.downloadList.slice();
|
||||||
|
const downloadListNames = displayList.map(s => s.name);
|
||||||
|
commonStore.lastUnfinishedModelDownloads.forEach((status) => {
|
||||||
|
const unfinishedIndex = downloadListNames.indexOf(status.name);
|
||||||
|
if (unfinishedIndex === -1) {
|
||||||
|
displayList.push(status);
|
||||||
|
} else {
|
||||||
|
const unfinishedStatus = displayList[unfinishedIndex];
|
||||||
|
if (unfinishedStatus.transferred < status.transferred) {
|
||||||
|
status.downloading = unfinishedStatus.downloading;
|
||||||
|
delete displayList[unfinishedIndex];
|
||||||
|
displayList.push(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
displayList = displayList.reverse();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title={t('Downloads')} content={
|
<Page title={t('Downloads')} content={
|
||||||
<div className="flex flex-col gap-2 overflow-y-auto overflow-x-hidden p-1">
|
<div className="flex flex-col gap-2 overflow-y-auto overflow-x-hidden p-1">
|
||||||
{commonStore.downloadList.slice().reverse().map((status, index) => {
|
{displayList.map((status, index) => {
|
||||||
const downloadProgress = `${status.progress.toFixed(2)}%`;
|
const downloadProgress = `${status.progress.toFixed(2)}%`;
|
||||||
const downloadSpeed = `${status.downloading ? bytesToMb(status.speed) : '0'}MB/s`;
|
const downloadSpeed = `${status.downloading ? bytesToMb(status.speed) : '0'}MB/s`;
|
||||||
let downloadDetails: string;
|
let downloadDetails: string;
|
||||||
@ -59,7 +76,7 @@ export const Downloads: FC = observer(() => {
|
|||||||
if (status.downloading)
|
if (status.downloading)
|
||||||
PauseDownload(status.url);
|
PauseDownload(status.url);
|
||||||
else
|
else
|
||||||
ContinueDownload(status.url);
|
AddToDownloadList(status.path, status.url);
|
||||||
}} />}
|
}} />}
|
||||||
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular />} onClick={() => {
|
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular />} onClick={() => {
|
||||||
OpenFileFolder(status.path, false);
|
OpenFileFolder(status.path, false);
|
||||||
|
@ -31,7 +31,9 @@ export type ModelSourceItem = {
|
|||||||
SHA256?: string;
|
SHA256?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
downloadUrl?: string;
|
downloadUrl?: string;
|
||||||
|
isComplete?: boolean;
|
||||||
isLocal?: boolean;
|
isLocal?: boolean;
|
||||||
|
localSize?: number;
|
||||||
lastUpdatedMs?: number;
|
lastUpdatedMs?: number;
|
||||||
hide?: boolean;
|
hide?: boolean;
|
||||||
};
|
};
|
||||||
@ -125,7 +127,7 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
createTableColumn<ModelSourceItem>({
|
createTableColumn<ModelSourceItem>({
|
||||||
columnId: 'actions',
|
columnId: 'actions',
|
||||||
compare: (a, b) => {
|
compare: (a, b) => {
|
||||||
return a.isLocal ? -1 : 1;
|
return a.isComplete ? -1 : 1;
|
||||||
},
|
},
|
||||||
renderHeaderCell: () => {
|
renderHeaderCell: () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -140,12 +142,12 @@ const columns: TableColumnDefinition<ModelSourceItem>[] = [
|
|||||||
<TableCellLayout>
|
<TableCellLayout>
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
{
|
{
|
||||||
item.isLocal &&
|
item.isComplete &&
|
||||||
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular />} onClick={() => {
|
<ToolTipButton desc={t('Open Folder')} icon={<Folder20Regular />} onClick={() => {
|
||||||
OpenFileFolder(`${commonStore.settings.customModelsPath}/${item.name}`, true);
|
OpenFileFolder(`${commonStore.settings.customModelsPath}/${item.name}`, true);
|
||||||
}} />
|
}} />
|
||||||
}
|
}
|
||||||
{item.downloadUrl && !item.isLocal &&
|
{item.downloadUrl && !item.isComplete &&
|
||||||
<ToolTipButton desc={t('Download')} icon={<ArrowDownload20Regular />} onClick={() => {
|
<ToolTipButton desc={t('Download')} icon={<ArrowDownload20Regular />} onClick={() => {
|
||||||
toastWithButton(`${t('Downloading')} ${item.name}`, t('Check'), () => {
|
toastWithButton(`${t('Downloading')} ${item.name}`, t('Check'), () => {
|
||||||
navigate({ pathname: '/downloads' });
|
navigate({ pathname: '/downloads' });
|
||||||
@ -203,7 +205,7 @@ export const Models: FC = observer(() => {
|
|||||||
<div className="overflow-y-auto overflow-x-hidden">
|
<div className="overflow-y-auto overflow-x-hidden">
|
||||||
<DataGridBody<ModelSourceItem>>
|
<DataGridBody<ModelSourceItem>>
|
||||||
{({ item, rowId }) => (
|
{({ item, rowId }) => (
|
||||||
(!item.hide || item.isLocal) &&
|
(!item.hide || item.isComplete) &&
|
||||||
<DataGridRow<ModelSourceItem> key={rowId}>
|
<DataGridRow<ModelSourceItem> key={rowId}>
|
||||||
{({ renderCell }) => (
|
{({ renderCell }) => (
|
||||||
<DataGridCell>{renderCell(item)}</DataGridCell>
|
<DataGridCell>{renderCell(item)}</DataGridCell>
|
||||||
|
@ -16,7 +16,7 @@ export async function startup() {
|
|||||||
await GetPlatform().then(p => commonStore.setPlatform(p as Platform));
|
await GetPlatform().then(p => commonStore.setPlatform(p as Platform));
|
||||||
await initConfig();
|
await initConfig();
|
||||||
|
|
||||||
initCache().then(initRemoteText); // depends on config customModelsPath
|
initCache(true).then(initRemoteText); // depends on config customModelsPath
|
||||||
|
|
||||||
if (commonStore.settings.autoUpdatesCheck) // depends on config settings
|
if (commonStore.settings.autoUpdatesCheck) // depends on config settings
|
||||||
checkUpdate();
|
checkUpdate();
|
||||||
@ -58,11 +58,11 @@ async function initConfig() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initCache() {
|
async function initCache(initUnfinishedModels: boolean) {
|
||||||
await ReadJson('cache.json').then((cacheData: Cache) => {
|
await ReadJson('cache.json').then((cacheData: Cache) => {
|
||||||
if (cacheData.depComplete)
|
if (cacheData.depComplete)
|
||||||
commonStore.setDepComplete(cacheData.depComplete);
|
commonStore.setDepComplete(cacheData.depComplete);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
});
|
});
|
||||||
await refreshModels(false);
|
await refreshModels(false, initUnfinishedModels);
|
||||||
}
|
}
|
@ -55,6 +55,7 @@ class CommonStore {
|
|||||||
modelSourceList: ModelSourceItem[] = [];
|
modelSourceList: ModelSourceItem[] = [];
|
||||||
// downloads
|
// downloads
|
||||||
downloadList: DownloadStatus[] = [];
|
downloadList: DownloadStatus[] = [];
|
||||||
|
lastUnfinishedModelDownloads: DownloadStatus[] = [];
|
||||||
// settings
|
// settings
|
||||||
advancedCollapsed: boolean = true;
|
advancedCollapsed: boolean = true;
|
||||||
settings: SettingsType = {
|
settings: SettingsType = {
|
||||||
@ -197,6 +198,10 @@ class CommonStore {
|
|||||||
setAdvancedCollapsed(value: boolean) {
|
setAdvancedCollapsed(value: boolean) {
|
||||||
this.advancedCollapsed = value;
|
this.advancedCollapsed = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setLastUnfinishedModelDownloads(value: DownloadStatus[]) {
|
||||||
|
this.lastUnfinishedModelDownloads = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new CommonStore();
|
export default new CommonStore();
|
@ -16,6 +16,7 @@ import { Button } from '@fluentui/react-components';
|
|||||||
import { Language, Languages, SettingsType } from '../pages/Settings';
|
import { Language, Languages, SettingsType } from '../pages/Settings';
|
||||||
import { ModelSourceItem } from '../pages/Models';
|
import { ModelSourceItem } from '../pages/Models';
|
||||||
import { ModelConfig, ModelParameters } from '../pages/Configs';
|
import { ModelConfig, ModelParameters } from '../pages/Configs';
|
||||||
|
import { DownloadStatus } from '../pages/Downloads';
|
||||||
|
|
||||||
export type Cache = {
|
export type Cache = {
|
||||||
models: ModelSourceItem[]
|
models: ModelSourceItem[]
|
||||||
@ -47,9 +48,11 @@ export async function refreshBuiltInModels(readCache: boolean = false) {
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function refreshLocalModels(cache: { models: ModelSourceItem[] }, filter: boolean = true) {
|
export async function refreshLocalModels(cache: {
|
||||||
|
models: ModelSourceItem[]
|
||||||
|
}, filter: boolean = true, initUnfinishedModels: boolean = false) {
|
||||||
if (filter)
|
if (filter)
|
||||||
cache.models = cache.models.filter(m => !m.isLocal); //TODO BUG cause local but in manifest files to be removed, so currently cache is disabled
|
cache.models = cache.models.filter(m => !m.isComplete); //TODO BUG cause local but in manifest files to be removed, so currently cache is disabled
|
||||||
|
|
||||||
await ListDirFiles(commonStore.settings.customModelsPath).then((data) => {
|
await ListDirFiles(commonStore.settings.customModelsPath).then((data) => {
|
||||||
cache.models.push(...data.flatMap(d => {
|
cache.models.push(...data.flatMap(d => {
|
||||||
@ -58,8 +61,9 @@ export async function refreshLocalModels(cache: { models: ModelSourceItem[] }, f
|
|||||||
name: d.name,
|
name: d.name,
|
||||||
size: d.size,
|
size: d.size,
|
||||||
lastUpdated: d.modTime,
|
lastUpdated: d.modTime,
|
||||||
|
isComplete: true,
|
||||||
isLocal: true
|
isLocal: true
|
||||||
}];
|
}] as ModelSourceItem[];
|
||||||
return [];
|
return [];
|
||||||
}));
|
}));
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
@ -80,17 +84,43 @@ export async function refreshLocalModels(cache: { models: ModelSourceItem[] }, f
|
|||||||
} else {
|
} else {
|
||||||
cache.models[i] = Object.assign({}, cache.models[j], cache.models[i]);
|
cache.models[i] = Object.assign({}, cache.models[j], cache.models[i]);
|
||||||
}
|
}
|
||||||
} // else is bad local file
|
} // else is not complete local file
|
||||||
|
cache.models[i].isLocal = true;
|
||||||
|
cache.models[i].localSize = cache.models[j].size;
|
||||||
cache.models.splice(j, 1);
|
cache.models.splice(j, 1);
|
||||||
j--;
|
j--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commonStore.setModelSourceList(cache.models);
|
commonStore.setModelSourceList(cache.models);
|
||||||
|
if (initUnfinishedModels)
|
||||||
|
initLastUnfinishedModelDownloads();
|
||||||
await saveCache().catch(() => {
|
await saveCache().catch(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initLastUnfinishedModelDownloads() {
|
||||||
|
const list: DownloadStatus[] = [];
|
||||||
|
commonStore.modelSourceList.forEach((item) => {
|
||||||
|
if (item.isLocal && !item.isComplete) {
|
||||||
|
list.push(
|
||||||
|
{
|
||||||
|
name: item.name,
|
||||||
|
path: `${commonStore.settings.customModelsPath}/${item.name}`,
|
||||||
|
url: item.downloadUrl!,
|
||||||
|
transferred: item.localSize!,
|
||||||
|
size: item.size,
|
||||||
|
speed: 0,
|
||||||
|
progress: item.localSize! / item.size * 100,
|
||||||
|
downloading: false,
|
||||||
|
done: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
commonStore.setLastUnfinishedModelDownloads(list);
|
||||||
|
}
|
||||||
|
|
||||||
export async function refreshRemoteModels(cache: { models: ModelSourceItem[] }) {
|
export async function refreshRemoteModels(cache: { models: ModelSourceItem[] }) {
|
||||||
const manifestUrls = commonStore.modelSourceManifestList.split(/[,,;;\n]/);
|
const manifestUrls = commonStore.modelSourceManifestList.split(/[,,;;\n]/);
|
||||||
const requests = manifestUrls.filter(url => url.endsWith('.json')).map(
|
const requests = manifestUrls.filter(url => url.endsWith('.json')).map(
|
||||||
@ -116,9 +146,9 @@ export async function refreshRemoteModels(cache: { models: ModelSourceItem[] })
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const refreshModels = async (readCache: boolean = false) => {
|
export const refreshModels = async (readCache: boolean = false, initUnfinishedModels: boolean = false) => {
|
||||||
const cache = await refreshBuiltInModels(readCache);
|
const cache = await refreshBuiltInModels(readCache);
|
||||||
await refreshLocalModels(cache);
|
await refreshLocalModels(cache, false, initUnfinishedModels);
|
||||||
await refreshRemoteModels(cache);
|
await refreshRemoteModels(cache);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user