mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-20 18:51:26 -03:00
14da8a6f17
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.
62 lines
2.4 KiB
JavaScript
62 lines
2.4 KiB
JavaScript
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);
|
|
}
|
|
};
|
|
}
|