Files
LocalAI/pkg/modelartifacts/reference.go
LocalAI [bot] bcc41219f7 feat: materialize Hugging Face model artifacts (#10825)
* feat(config): add model artifact source contract

Assisted-by: Codex:GPT-5 [Codex]

* feat(downloader): add authenticated raw-byte progress

Assisted-by: Codex:GPT-5 [Codex]

* feat(huggingface): resolve immutable snapshot manifests

Assisted-by: Codex:GPT-5 [Codex]

* feat(models): add artifact storage primitives

Assisted-by: Codex:GPT-5 [Codex]

* feat(models): materialize pinned Hugging Face snapshots

Assisted-by: Codex:GPT-5 [Codex]

* feat(models): bind managed snapshots at runtime

Assisted-by: Codex:GPT-5 [Codex]

* feat(gallery): materialize model artifacts during install

Assisted-by: Codex:GPT-5 [Codex]

* feat(gallery): declare managed Hugging Face artifacts

Assisted-by: Codex:GPT-5 [Codex]

* feat(models): preload managed model artifacts

Assisted-by: Codex:GPT-5 [Codex]

* fix(gallery): retain shared artifact caches on delete

Assisted-by: Codex:GPT-5 [Codex]

* feat(models): report artifact acquisition progress

Assisted-by: Codex:GPT-5 [Codex]

* refactor(backends): load managed models from ModelFile

Assisted-by: Codex:GPT-5 [Codex]

* refactor(backends): load staged speech model snapshots

Assisted-by: Codex:GPT-5 [Codex]

* refactor(backends): use staged snapshots in engine backends

Assisted-by: Codex:GPT-5 [Codex]

* test(distributed): cover staged artifact snapshots

Assisted-by: Codex:GPT-5 [Codex]

* docs: explain managed model artifacts

Assisted-by: Codex:GPT-5 [Codex]

* docs: add product design context

Assisted-by: Codex:GPT-5 [Codex]

* feat(ui): show model artifact download progress

Assisted-by: Codex:GPT-5 [Codex]

* Eagerly materialize Hugging Face artifacts

Materialize HF-backed model references as managed GGUF artifacts during load, with lazy download retained only as fallback.

Assisted-by: Codex:GPT-5 [shell]

* Refactor HF
  downloads through a shared executor

Assisted-by: Codex:GPT-5 [shell]

* drop

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

---------

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
2026-07-15 01:09:33 +02:00

83 lines
2.1 KiB
Go

package modelartifacts
import (
"fmt"
"strings"
)
var hfReferencePrefixes = []string{
"https://huggingface.co/",
"huggingface://",
"hf://",
"hf.co/",
}
// ParsePrimaryReference converts a Hugging Face repository or file reference
// into a managed artifact spec. It accepts repo roots like "owner/repo" and
// direct file references like "huggingface://owner/repo/path/to/model.gguf".
// The boolean return is false when the reference is not Hugging Face-shaped.
func ParsePrimaryReference(raw string) (Spec, bool, error) {
source, ok, err := ParsePrimarySource(raw)
if err != nil || !ok {
return Spec{}, ok, err
}
return Spec{
Name: TargetModel,
Target: TargetModel,
Source: source,
}, true, nil
}
// ParsePrimarySource converts a Hugging Face repository or file reference into
// a managed source definition. Direct file references are translated into a
// repo plus a single allow pattern so the materializer downloads only the
// selected file.
func ParsePrimarySource(raw string) (Source, bool, error) {
ref := strings.TrimSpace(raw)
if ref == "" {
return Source{}, false, nil
}
stripped := ref
for _, prefix := range hfReferencePrefixes {
stripped = strings.TrimPrefix(stripped, prefix)
}
stripped = strings.TrimSuffix(stripped, "/")
parts := strings.Split(stripped, "/")
if len(parts) < 2 {
return Source{}, false, nil
}
hadPrefix := ref != stripped
repo, err := normalizeRepo(strings.Join(parts[:2], "/"))
if err != nil {
if ref != stripped {
return Source{}, false, fmt.Errorf("invalid Hugging Face reference %q: %w", raw, err)
}
return Source{}, false, nil
}
if !hadPrefix && len(parts) == 2 {
return Source{}, false, nil
}
source := Source{
Type: SourceTypeHuggingFace,
Repo: repo,
}
if len(parts) == 2 {
return source, true, nil
}
if parts[2] == "resolve" {
if len(parts) < 5 {
return Source{}, false, fmt.Errorf("invalid Hugging Face file reference %q", raw)
}
source.AllowPatterns = []string{strings.Join(parts[4:], "/")}
return source, true, nil
}
source.AllowPatterns = []string{strings.Join(parts[2:], "/")}
return source, true, nil
}