Skip to content

Commit a89d780

Browse files
localai-botmudler
andauthored
fix(gallery): keep multi-file HF install progress proportional during verify (#10908)
The artifact progress bridge mapped every PhaseVerifying event to a flat 95%. The materializer emits PhaseVerifying once per file (from each file's AfterDownload hook) and downloads run sequentially, so the first small file to finish pinned the bar at 95% - and, because progress is monotonic, it stayed at 95% for the entire remaining download (e.g. a 70GB checkpoint reporting 95% at 410MB / 69.7GB). Track per-file verify proportionally to the running aggregate bytes, the same way downloading does. CurrentBytes already reflects "completed files + this file", so the percentage advances honestly. The flat 95%/99% is now reserved for the genuinely once-per-install Committing/Persisting phases. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
1 parent 55e2726 commit a89d780

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

core/services/galleryop/artifact_progress.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,15 @@ func (b *artifactProgressBridge) Sink(event modelartifacts.ProgressEvent) {
3333
}
3434
message = fmt.Sprintf("Downloading model file: %s", event.File)
3535
case modelartifacts.PhaseVerifying:
36-
progress = max(progress, 95)
36+
// Verification runs per file — the materializer emits this from each
37+
// file's AfterDownload hook, not once at the end. CurrentBytes is the
38+
// running aggregate (completed files + this file), so track it
39+
// proportionally like downloading. A flat 95% here pinned the bar the
40+
// moment the first file finished, leaving a multi-file (e.g. 70GB)
41+
// install stuck at 95% for the entire remaining download.
42+
if event.TotalBytes > 0 {
43+
progress = max(progress, min(90, float64(event.CurrentBytes)*90/float64(event.TotalBytes)))
44+
}
3745
message = "Verifying model files"
3846
case modelartifacts.PhaseCommitting:
3947
progress = max(progress, 99)

core/services/galleryop/artifact_progress_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,23 @@ var _ = Describe("artifact operation progress", func() {
3030
Expect(statuses[5].Progress).To(Equal(float64(99)))
3131
Expect(statuses[5].CurrentBytes).To(Equal(int64(100)))
3232
})
33+
34+
It("keeps a per-file verify proportional to bytes, not a flat 95%", func() {
35+
// A multi-file model (e.g. a 70GB checkpoint) downloads sequentially and
36+
// verifies each file from its AfterDownload hook. When the first small
37+
// file finishes, a PhaseVerifying event fires while nearly all bytes are
38+
// still to download — the reported percentage must reflect the tiny
39+
// fraction completed, not slam the bar to 95% for the rest of the run.
40+
var last *OpStatus
41+
bridge := newArtifactProgressBridge(func(status *OpStatus) {
42+
copy := *status
43+
last = &copy
44+
})
45+
bridge.Sink(modelartifacts.ProgressEvent{Phase: modelartifacts.PhaseResolving, TotalBytes: 70000})
46+
bridge.Sink(modelartifacts.ProgressEvent{Phase: modelartifacts.PhaseDownloading, File: "config.json", CurrentBytes: 400, TotalBytes: 70000})
47+
bridge.Sink(modelartifacts.ProgressEvent{Phase: modelartifacts.PhaseVerifying, File: "config.json", CurrentBytes: 400, TotalBytes: 70000})
48+
49+
Expect(last.Phase).To(Equal("verifying"))
50+
Expect(last.Progress).To(BeNumerically("<", 5))
51+
})
3352
})

0 commit comments

Comments
 (0)