mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-21 03:01:27 -03:00
feat(ui): show live scan progress and ETA for cache refresh
Broadcast typed scan_progress messages over /ws/fetch-progress from the manual refresh/rebuild paths of ModelScanner and RecipeScanner, and render percent, processed/total, current file name and an EMA-smoothed ETA in the loading overlay. Hardcoded refresh strings move to i18n (common.scanProgress); WS connection failure falls back to the previous static loading behavior.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { translate } from './i18nHelpers.js';
|
||||
|
||||
/**
|
||||
* Format a remaining-time estimate for scan progress display.
|
||||
* @param {number} remainingMs - Estimated remaining time in milliseconds
|
||||
* @returns {string} Localized ETA text
|
||||
*/
|
||||
export function formatScanRemainingTime(remainingMs) {
|
||||
if (remainingMs < 60000) {
|
||||
return translate('common.scanProgress.eta.lessThanMinute', {}, 'Less than a minute remaining');
|
||||
}
|
||||
if (remainingMs < 3600000) {
|
||||
const minutes = Math.round(remainingMs / 60000);
|
||||
return translate('common.scanProgress.eta.minutes', { minutes }, `~${minutes} min remaining`);
|
||||
}
|
||||
const hours = Math.floor(remainingMs / 3600000);
|
||||
const minutes = Math.round((remainingMs % 3600000) / 60000);
|
||||
return translate('common.scanProgress.eta.hours', { hours, minutes }, `~${hours} hr ${minutes} min remaining`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ETA tracker for scan progress. Uses an exponential moving
|
||||
* average (0.7/0.3) over the observed per-file processing time, mirroring
|
||||
* the estimator in components/initialization.js.
|
||||
* @returns {{ update: (processed: number, total: number) => (string|null) }}
|
||||
*/
|
||||
export function createScanEtaTracker() {
|
||||
let startTime = null;
|
||||
let lastProcessed = 0;
|
||||
let averageMsPerFile = null;
|
||||
|
||||
return {
|
||||
/**
|
||||
* Update with the latest counters.
|
||||
* @returns {string|null} Localized ETA text, or null when not applicable
|
||||
*/
|
||||
update(processed, total) {
|
||||
if (!total || total <= 0 || processed >= total) {
|
||||
return null;
|
||||
}
|
||||
const now = Date.now();
|
||||
if (startTime === null) {
|
||||
// First sample only anchors the timer; not enough data yet
|
||||
startTime = now;
|
||||
lastProcessed = processed;
|
||||
return translate('initialization.estimatingTime', {}, 'Estimating time...');
|
||||
}
|
||||
if (processed > lastProcessed) {
|
||||
const msPerFile = (now - startTime) / processed;
|
||||
averageMsPerFile = averageMsPerFile === null
|
||||
? msPerFile
|
||||
: averageMsPerFile * 0.7 + msPerFile * 0.3;
|
||||
lastProcessed = processed;
|
||||
}
|
||||
if (averageMsPerFile === null) {
|
||||
return translate('initialization.estimatingTime', {}, 'Estimating time...');
|
||||
}
|
||||
return formatScanRemainingTime((total - lastProcessed) * averageMsPerFile);
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user