fix: show partial download progress on initial dashboard load (#1706)
## Summary - Dashboard now shows partial download progress for models that were partially downloaded in a previous session, instead of showing 0% - Both `getModelDownloadStatus()` and `getInstanceDownloadStatus()` now handle `DownloadPending` entries that carry non-zero `downloaded`/`total` bytes Fixes #1042 ## Root cause When exo restarts with partially downloaded models, the `DownloadCoordinator` emits `DownloadPending` events (because `downloaded_this_session` is 0, even though real bytes exist on disk). The main page dashboard only checked for `DownloadOngoing` entries, so these partially downloaded models showed as 0%. The dedicated `/downloads` page already handled this correctly — it renders `DownloadPending` entries with a progress bar when `downloaded > 0`. This fix brings the same behavior to the main page. ## Changes For both `getModelDownloadStatus()` and `getInstanceDownloadStatus()` in `+page.svelte`: - Accept `DownloadPending` in addition to `DownloadOngoing` - For `DownloadPending` entries with `downloaded > 0` or `total > 0`, synthesize a `DownloadProgress` object from the top-level fields (with `speed: 0` and `etaMs: 0` since no active download is in progress) - Skip `DownloadPending` entries where both `downloaded` and `total` are 0 (truly pending, not yet started) ## Test plan - [ ] Partially download a model, quit exo, relaunch — dashboard should show partial progress instead of 0% - [ ] Fully downloaded models still show as complete - [ ] Active downloads still show real-time progress with speed/ETA - [ ] Models never downloaded show as not started (not falsely showing progress) - [ ] Dashboard builds without errors (`cd dashboard && npm run build`) --------- Co-authored-by: Evan <evanev7@gmail.com>
This commit is contained in:
@@ -1527,7 +1527,11 @@
|
||||
downloadKind
|
||||
] as Record<string, unknown>;
|
||||
|
||||
if (downloadKind !== "DownloadOngoing") continue;
|
||||
if (
|
||||
downloadKind !== "DownloadOngoing" &&
|
||||
downloadKind !== "DownloadPending"
|
||||
)
|
||||
continue;
|
||||
if (!downloadPayload) continue;
|
||||
|
||||
const downloadModelId = extractModelIdFromDownload(downloadPayload);
|
||||
@@ -1542,9 +1546,38 @@
|
||||
if (downloadModelId !== modelId) continue;
|
||||
}
|
||||
|
||||
isDownloading = true;
|
||||
// For DownloadPending with partial bytes (paused/resumed downloads),
|
||||
// synthesize a progress object from the top-level downloaded/total fields
|
||||
let progress: DownloadProgress | null;
|
||||
if (downloadKind === "DownloadPending") {
|
||||
const pendingDownloaded = getBytes(
|
||||
downloadPayload.downloaded ??
|
||||
downloadPayload.downloaded_bytes ??
|
||||
downloadPayload.downloadedBytes,
|
||||
);
|
||||
const pendingTotal = getBytes(
|
||||
downloadPayload.total ??
|
||||
downloadPayload.total_bytes ??
|
||||
downloadPayload.totalBytes,
|
||||
);
|
||||
if (pendingDownloaded <= 0 && pendingTotal <= 0) continue;
|
||||
isDownloading = true;
|
||||
progress = {
|
||||
totalBytes: pendingTotal,
|
||||
downloadedBytes: pendingDownloaded,
|
||||
speed: 0,
|
||||
etaMs: 0,
|
||||
percentage:
|
||||
pendingTotal > 0 ? (pendingDownloaded / pendingTotal) * 100 : 0,
|
||||
completedFiles: 0,
|
||||
totalFiles: 0,
|
||||
files: [],
|
||||
};
|
||||
} else {
|
||||
isDownloading = true;
|
||||
progress = parseDownloadProgress(downloadPayload);
|
||||
}
|
||||
|
||||
const progress = parseDownloadProgress(downloadPayload);
|
||||
if (progress) {
|
||||
// Sum all values across nodes - each node downloads independently
|
||||
totalBytes += progress.totalBytes;
|
||||
@@ -1696,7 +1729,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadKind !== "DownloadOngoing") continue;
|
||||
if (
|
||||
downloadKind !== "DownloadOngoing" &&
|
||||
downloadKind !== "DownloadPending"
|
||||
)
|
||||
continue;
|
||||
if (!downloadPayload) continue;
|
||||
|
||||
// Check if this download is for this instance's model
|
||||
@@ -1706,9 +1743,37 @@
|
||||
downloadModelId &&
|
||||
downloadModelId === instanceModelId
|
||||
) {
|
||||
isDownloading = true;
|
||||
// For DownloadPending with partial bytes, synthesize progress
|
||||
let progress: DownloadProgress | null;
|
||||
if (downloadKind === "DownloadPending") {
|
||||
const pendingDownloaded = getBytes(
|
||||
downloadPayload.downloaded ??
|
||||
downloadPayload.downloaded_bytes ??
|
||||
downloadPayload.downloadedBytes,
|
||||
);
|
||||
const pendingTotal = getBytes(
|
||||
downloadPayload.total ??
|
||||
downloadPayload.total_bytes ??
|
||||
downloadPayload.totalBytes,
|
||||
);
|
||||
if (pendingDownloaded <= 0 && pendingTotal <= 0) continue;
|
||||
isDownloading = true;
|
||||
progress = {
|
||||
totalBytes: pendingTotal,
|
||||
downloadedBytes: pendingDownloaded,
|
||||
speed: 0,
|
||||
etaMs: 0,
|
||||
percentage:
|
||||
pendingTotal > 0 ? (pendingDownloaded / pendingTotal) * 100 : 0,
|
||||
completedFiles: 0,
|
||||
totalFiles: 0,
|
||||
files: [],
|
||||
};
|
||||
} else {
|
||||
isDownloading = true;
|
||||
progress = parseDownloadProgress(downloadPayload);
|
||||
}
|
||||
|
||||
const progress = parseDownloadProgress(downloadPayload);
|
||||
if (progress) {
|
||||
// Sum all values across nodes - each node downloads independently
|
||||
totalBytes += progress.totalBytes;
|
||||
|
||||
Reference in New Issue
Block a user