File size: 2,797 Bytes
06d399d
 
 
 
 
 
 
 
 
 
 
 
 
dc0cc96
3656858
06d399d
 
 
 
 
 
 
 
 
 
dc0cc96
 
 
 
 
 
 
 
 
 
06d399d
dc0cc96
06d399d
 
 
 
 
 
dc0cc96
 
 
 
 
06d399d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dc0cc96
06d399d
 
 
 
 
 
dc0cc96
06d399d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
const root = element.querySelector(".labs-progress");
const label = root.querySelector(".labs-progress-label");
const track = root.querySelector(".labs-progress-track");
const fill = root.querySelector(".labs-progress-fill");
const {op, source, done} = root.dataset;
const stages = JSON.parse(root.dataset.stages);
const LEVEL = /([^/]+?)\s+-\s+([\d.]+)%/g;
let timer = null;
let started = 0;
let seconds = Number(root.dataset.seconds);
let shown = 0;
let floor = 0;
let stageLabel = null;
let waiting = false;
const WAITING_LABEL = "Spinning up GPU cluster…";

function serverProgress() {
    const text = source ? document.querySelector(source)?.textContent || "" : "";
    for (const [, desc, pct] of text.matchAll(LEVEL)) {
        const name = desc.replace(/[.…\s]+$/, "").trim();
        if (name && !/zero\s*gpu|hugging/i.test(name)) return {name, pct: Number(pct)};
    }
    return null;
}

function showWaiting() {
    label.textContent = WAITING_LABEL;
    track.hidden = true;
}

function beginGpuWork() {
    waiting = false;
    started = performance.now();
}

function draw(text, pct) {
    track.hidden = false;
    label.textContent = `${text} ${Math.floor(pct)}%`;
    fill.style.width = `${pct}%`;
    track.setAttribute("aria-valuenow", String(Math.floor(pct)));
}

function tick() {
    const server = serverProgress();
    if (waiting) {
        if (!server) return showWaiting();
        beginGpuWork();
    }
    const elapsed = (performance.now() - started) / 1000;
    const estimate = 95 * (1 - Math.exp(-2 * elapsed / seconds));
    if (server) stageLabel = server.name;
    shown = Math.min(99, Math.max(shown, floor, estimate, server ? Math.min(server.pct, 95) : 0));
    const fallback = stages.filter(([at]) => shown >= at).pop()[1];
    draw(`${stageLabel || fallback}…`, shown);
}

function stop() {
    clearInterval(timer);
    timer = null;
}

const bar = {
    get running() { return timer !== null; },
    start(options = {}) {
        stop();
        seconds = options.seconds || Number(root.dataset.seconds);
        started = performance.now();
        shown = floor = 0;
        stageLabel = null;
        waiting = root.dataset.gpu === "1";
        root.hidden = false;
        tick();
        timer = setInterval(tick, 200);
    },
    stage(name, pct) {
        if (!timer) return;
        if (waiting) beginGpuWork();
        stageLabel = name;
        floor = pct;
        tick();
    },
    finish(ok) {
        if (!timer) return;
        stop();
        if (!ok) {
            root.hidden = true;
            return;
        }
        draw(done, 100);
        setTimeout(() => { if (!timer) root.hidden = true; }, 900);
    },
    cancel() {
        stop();
        root.hidden = true;
    },
};
(window.labsProgressBars ||= {})[op] = bar;