mirror of
https://github.com/mudler/LocalAI.git
synced 2026-08-04 12:22:22 -04:00
Compare commits
1 Commits
bot/issue-
...
bot/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc8113a8d6 |
@@ -236,8 +236,8 @@ var _ = Describe("InstallModelFromGallery with an empty base config", func() {
|
||||
Expect(install(e.Name, gallery.GalleryModel{})).To(Succeed())
|
||||
cfg := installedConfig(e.Name)
|
||||
Expect(cfg["name"]).To(Equal(e.Name))
|
||||
// The catalog's own overrides, verbatim, laid over the empty base.
|
||||
Expect(cfg["parameters"]).To(Equal(e.Overrides["parameters"]))
|
||||
// The catalog's model override survives inference-default enrichment.
|
||||
Expect(cfg["parameters"]).To(HaveKeyWithValue("model", "LiquidAI_LFM2-1.2B-RAG-Q4_K_M.gguf"))
|
||||
Expect(cfg["known_usecases"]).To(Equal(e.Overrides["known_usecases"]))
|
||||
})
|
||||
})
|
||||
|
||||
90
core/gallery/inference_defaults_install_test.go
Normal file
90
core/gallery/inference_defaults_install_test.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package gallery_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/mudler/LocalAI/core/gallery"
|
||||
"github.com/mudler/LocalAI/pkg/modelartifacts"
|
||||
"github.com/mudler/LocalAI/pkg/system"
|
||||
)
|
||||
|
||||
var _ = Describe("gallery inference defaults", func() {
|
||||
readPersistedConfig := func(modelsPath, name string) map[string]any {
|
||||
data, err := os.ReadFile(filepath.Join(modelsPath, name+".yaml"))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
persisted := map[string]any{}
|
||||
Expect(yaml.Unmarshal(data, &persisted)).To(Succeed())
|
||||
return persisted
|
||||
}
|
||||
|
||||
expectNestedDefaults := func(persisted map[string]any) {
|
||||
Expect(persisted).NotTo(HaveKey("temperature"))
|
||||
Expect(persisted).NotTo(HaveKey("top_p"))
|
||||
parameters, ok := persisted["parameters"].(map[string]any)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(parameters).To(HaveKeyWithValue("temperature", 0.7))
|
||||
Expect(parameters).To(HaveKeyWithValue("top_p", 0.42))
|
||||
Expect(parameters).To(HaveKeyWithValue("top_k", 20))
|
||||
Expect(parameters).To(HaveKeyWithValue("min_p", 0))
|
||||
Expect(parameters).To(HaveKeyWithValue("repeat_penalty", 1))
|
||||
Expect(parameters).To(HaveKeyWithValue("presence_penalty", 1.5))
|
||||
}
|
||||
|
||||
It("persists defaults under parameters after artifact binding", func() {
|
||||
modelsPath := GinkgoT().TempDir()
|
||||
state, err := system.GetSystemState(system.WithModelPath(modelsPath))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
resolved := modelartifacts.Spec{
|
||||
Name: "model", Target: "model",
|
||||
Source: modelartifacts.Source{Type: "huggingface", Repo: "owner/qwen3.5-model", Revision: "main"},
|
||||
Resolved: &modelartifacts.Resolved{
|
||||
Endpoint: "https://huggingface.co",
|
||||
Revision: "0123456789abcdef0123456789abcdef01234567",
|
||||
CacheKey: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||
},
|
||||
}
|
||||
fake := &fakeArtifactMaterializer{result: modelartifacts.Result{Spec: resolved}}
|
||||
definition := &gallery.ModelConfig{Name: "qwen3.5-artifact", ConfigFile: `
|
||||
backend: transformers
|
||||
artifacts:
|
||||
- name: model
|
||||
target: model
|
||||
source: {type: huggingface, repo: owner/qwen3.5-model}
|
||||
parameters:
|
||||
model: owner/qwen3.5-model
|
||||
top_p: 0.42
|
||||
`}
|
||||
|
||||
_, err = gallery.InstallModel(context.Background(), state, "", definition, nil, nil, false,
|
||||
gallery.WithArtifactMaterializer(fake))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectNestedDefaults(readPersistedConfig(modelsPath, definition.Name))
|
||||
})
|
||||
|
||||
It("persists defaults under parameters when the entry declares files", func() {
|
||||
modelsPath := GinkgoT().TempDir()
|
||||
state, err := system.GetSystemState(system.WithModelPath(modelsPath))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(os.WriteFile(filepath.Join(modelsPath, "weights.gguf"), []byte("weights"), 0644)).To(Succeed())
|
||||
definition := &gallery.ModelConfig{
|
||||
Name: "qwen3.5-files",
|
||||
ConfigFile: `
|
||||
backend: llama-cpp
|
||||
parameters:
|
||||
model: weights.gguf
|
||||
top_p: 0.42
|
||||
`,
|
||||
Files: []gallery.File{{Filename: "weights.gguf", URI: "https://example.com/weights.gguf"}},
|
||||
}
|
||||
|
||||
_, err = gallery.InstallModel(context.Background(), state, "", definition, nil, nil, false)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectNestedDefaults(readPersistedConfig(modelsPath, definition.Name))
|
||||
})
|
||||
})
|
||||
@@ -622,35 +622,41 @@ func InstallModel(ctx context.Context, systemState *system.SystemState, nameOver
|
||||
lconfig.ApplyInferenceDefaults(&modelConfig, name, modelConfig.Model)
|
||||
|
||||
// Merge inference defaults into configMap so they are persisted without losing unknown fields.
|
||||
defaults := make(map[string]any)
|
||||
if modelConfig.Temperature != nil {
|
||||
if _, exists := configMap["temperature"]; !exists {
|
||||
configMap["temperature"] = *modelConfig.Temperature
|
||||
}
|
||||
defaults["temperature"] = *modelConfig.Temperature
|
||||
}
|
||||
if modelConfig.TopP != nil {
|
||||
if _, exists := configMap["top_p"]; !exists {
|
||||
configMap["top_p"] = *modelConfig.TopP
|
||||
}
|
||||
defaults["top_p"] = *modelConfig.TopP
|
||||
}
|
||||
if modelConfig.TopK != nil {
|
||||
if _, exists := configMap["top_k"]; !exists {
|
||||
configMap["top_k"] = *modelConfig.TopK
|
||||
}
|
||||
defaults["top_k"] = *modelConfig.TopK
|
||||
}
|
||||
if modelConfig.MinP != nil {
|
||||
if _, exists := configMap["min_p"]; !exists {
|
||||
configMap["min_p"] = *modelConfig.MinP
|
||||
}
|
||||
defaults["min_p"] = *modelConfig.MinP
|
||||
}
|
||||
if modelConfig.RepeatPenalty != 0 {
|
||||
if _, exists := configMap["repeat_penalty"]; !exists {
|
||||
configMap["repeat_penalty"] = modelConfig.RepeatPenalty
|
||||
}
|
||||
defaults["repeat_penalty"] = modelConfig.RepeatPenalty
|
||||
}
|
||||
if modelConfig.PresencePenalty != 0 {
|
||||
if _, exists := configMap["presence_penalty"]; !exists {
|
||||
configMap["presence_penalty"] = modelConfig.PresencePenalty
|
||||
defaults["presence_penalty"] = modelConfig.PresencePenalty
|
||||
}
|
||||
if len(defaults) > 0 {
|
||||
parameters, ok := configMap["parameters"].(map[string]any)
|
||||
if !ok {
|
||||
parameters = make(map[string]any)
|
||||
configMap["parameters"] = parameters
|
||||
}
|
||||
for key, value := range defaults {
|
||||
if _, exists := parameters[key]; !exists {
|
||||
parameters[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updatedConfigYAML, err = yaml.Marshal(configMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal config with inference defaults: %v", err)
|
||||
}
|
||||
|
||||
if valid, err := modelConfig.Validate(); !valid {
|
||||
|
||||
Reference in New Issue
Block a user