diff --git a/pkg/distribution/internal/gguf/create.go b/pkg/distribution/internal/gguf/create.go index 7f1d8baa1..b1c73debf 100644 --- a/pkg/distribution/internal/gguf/create.go +++ b/pkg/distribution/internal/gguf/create.go @@ -5,6 +5,7 @@ import ( "strings" "time" + "github.com/docker/go-units" v1 "github.com/google/go-containerregistry/pkg/v1" parser "github.com/gpustack/gguf-parser-go" @@ -53,12 +54,26 @@ func configFromFile(path string) types.Config { if err != nil { return types.Config{} // continue without metadata } + + meta := gguf.Metadata() return types.Config{ Format: types.FormatGGUF, - Parameters: strings.TrimSpace(gguf.Metadata().Parameters.String()), - Architecture: strings.TrimSpace(gguf.Metadata().Architecture), - Quantization: strings.TrimSpace(gguf.Metadata().FileType.String()), - Size: strings.TrimSpace(gguf.Metadata().Size.String()), + Parameters: formatParameters(int64(meta.Parameters)), + Architecture: strings.TrimSpace(meta.Architecture), + Quantization: strings.TrimSpace(meta.FileType.String()), + Size: formatSize(int64(meta.Size)), GGUF: extractGGUFMetadata(&gguf.Header), } } + +// formatParameters converts parameter count to human-readable format +// Returns format like "361.82M" or "1.5B" (no space, base 1000, where B = Billion) +func formatParameters(params int64) string { + return units.CustomSize("%.2f%s", float64(params), 1000.0, []string{"", "K", "M", "B", "T"}) +} + +// formatSize converts bytes to human-readable format using binary units (base 1024) +// Returns format like "244.45MiB" (no space, matching Docker's format) +func formatSize(bytes int64) string { + return units.BytesSize(float64(bytes)) +} diff --git a/pkg/distribution/internal/gguf/model_test.go b/pkg/distribution/internal/gguf/model_test.go index 1216d7b1b..6e92611bd 100644 --- a/pkg/distribution/internal/gguf/model_test.go +++ b/pkg/distribution/internal/gguf/model_test.go @@ -23,8 +23,8 @@ func TestGGUF(t *testing.T) { if cfg.Format != types.FormatGGUF { t.Fatalf("Unexpected format: got %s expected %s", cfg.Format, types.FormatGGUF) } - if cfg.Parameters != "183" { - t.Fatalf("Unexpected parameters: got %s expected %s", cfg.Parameters, "183") + if cfg.Parameters != "183.00" { + t.Fatalf("Unexpected parameters: got %s expected %s", cfg.Parameters, "183.00") } if cfg.Architecture != "llama" { t.Fatalf("Unexpected architecture: got %s expected %s", cfg.Parameters, "llama") @@ -32,8 +32,8 @@ func TestGGUF(t *testing.T) { if cfg.Quantization != "Unknown" { // todo: testdata with a real value t.Fatalf("Unexpected quantization: got %s expected %s", cfg.Quantization, "Unknown") } - if cfg.Size != "864 B" { - t.Fatalf("Unexpected quantization: got %s expected %s", cfg.Quantization, "Unknown") + if cfg.Size != "864B" { + t.Fatalf("Unexpected size: got %s expected %s", cfg.Size, "864B") } // Test GGUF metadata @@ -109,8 +109,8 @@ func TestGGUFShards(t *testing.T) { if cfg.Format != types.FormatGGUF { t.Fatalf("Unexpected format: got %s expected %s", cfg.Format, types.FormatGGUF) } - if cfg.Parameters != "183" { - t.Fatalf("Unexpected parameters: got %s expected %s", cfg.Parameters, "183") + if cfg.Parameters != "183.00" { + t.Fatalf("Unexpected parameters: got %s expected %s", cfg.Parameters, "183.00") } if cfg.Architecture != "llama" { t.Fatalf("Unexpected architecture: got %s expected %s", cfg.Parameters, "llama") @@ -118,8 +118,8 @@ func TestGGUFShards(t *testing.T) { if cfg.Quantization != "Unknown" { // todo: testdata with a real value t.Fatalf("Unexpected quantization: got %s expected %s", cfg.Quantization, "Unknown") } - if cfg.Size != "864 B" { - t.Fatalf("Unexpected quantization: got %s expected %s", cfg.Quantization, "Unknown") + if cfg.Size != "864B" { + t.Fatalf("Unexpected size: got %s expected %s", cfg.Size, "864B") } // Test GGUF metadata diff --git a/pkg/distribution/internal/safetensors/metadata.go b/pkg/distribution/internal/safetensors/metadata.go index 9c7aab567..1d2af5cab 100644 --- a/pkg/distribution/internal/safetensors/metadata.go +++ b/pkg/distribution/internal/safetensors/metadata.go @@ -184,12 +184,13 @@ func (h *Header) ExtractMetadata() map[string]string { } // formatParameters converts parameter count to human-readable format matching GGUF style -// Returns format like "361.82 M" or "1.5 B" (space before unit, base 1000, where B = Billion) +// Returns format like "361.82M" or "1.5B" (no space, base 1000, where B = Billion) func formatParameters(params int64) string { - return units.CustomSize("%.2f%s", float64(params), 1000.0, []string{"", " K", " M", " B", " T"}) + return units.CustomSize("%.2f%s", float64(params), 1000.0, []string{"", "K", "M", "B", "T"}) } -// formatSize converts bytes to human-readable format +// formatSize converts bytes to human-readable format using binary units (base 1024) +// Returns format like "244.45MiB" (no space, matching Docker's format) func formatSize(bytes int64) string { - return units.HumanSizeWithPrecision(float64(bytes), 2) + return units.BytesSize(float64(bytes)) } diff --git a/pkg/distribution/internal/safetensors/model_test.go b/pkg/distribution/internal/safetensors/model_test.go index 8593c1b06..ed9bda93f 100644 --- a/pkg/distribution/internal/safetensors/model_test.go +++ b/pkg/distribution/internal/safetensors/model_test.go @@ -92,7 +92,7 @@ func TestNewModel_WithMetadata(t *testing.T) { } // Verify parameters (4096*4096 + 4096 = 16781312) - expectedParams := "16.78 M" + expectedParams := "16.78M" if config.Parameters != expectedParams { t.Errorf("Config.Parameters = %v, want %v", config.Parameters, expectedParams) } @@ -220,7 +220,7 @@ func TestNewModel_NoMetadata(t *testing.T) { } // Verify parameters (100*200 = 20000) - expectedParams := "20.00 K" + expectedParams := "20.00K" if config.Parameters != expectedParams { t.Errorf("Config.Parameters = %v, want %v", config.Parameters, expectedParams) }