mirror of
https://github.com/mudler/LocalAI.git
synced 2026-07-30 18:09:05 -04:00
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>
This commit is contained in:
82
pkg/modelartifacts/reference.go
Normal file
82
pkg/modelartifacts/reference.go
Normal file
@@ -0,0 +1,82 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user