mirror of
https://github.com/mudler/LocalAI
synced 2026-04-21 13:27:21 +00:00
132 lines
2.8 KiB
Go
132 lines
2.8 KiB
Go
package meta
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"sync"
|
|
)
|
|
|
|
var (
|
|
cachedMetadata *ConfigMetadata
|
|
cacheMu sync.RWMutex
|
|
)
|
|
|
|
// BuildConfigMetadata reflects on the given struct type (ModelConfig),
|
|
// merges the enrichment registry, and returns the full ConfigMetadata.
|
|
// The result is cached in memory after the first call.
|
|
func BuildConfigMetadata(modelConfigType reflect.Type) *ConfigMetadata {
|
|
cacheMu.RLock()
|
|
if cachedMetadata != nil {
|
|
cacheMu.RUnlock()
|
|
return cachedMetadata
|
|
}
|
|
cacheMu.RUnlock()
|
|
|
|
cacheMu.Lock()
|
|
defer cacheMu.Unlock()
|
|
|
|
if cachedMetadata != nil {
|
|
return cachedMetadata
|
|
}
|
|
|
|
cachedMetadata = buildConfigMetadataUncached(modelConfigType, DefaultRegistry())
|
|
return cachedMetadata
|
|
}
|
|
|
|
// buildConfigMetadataUncached does the actual work without caching.
|
|
func buildConfigMetadataUncached(modelConfigType reflect.Type, registry map[string]FieldMetaOverride) *ConfigMetadata {
|
|
fields := WalkModelConfig(modelConfigType)
|
|
|
|
for i := range fields {
|
|
override, ok := registry[fields[i].Path]
|
|
if !ok {
|
|
continue
|
|
}
|
|
applyOverride(&fields[i], override)
|
|
}
|
|
|
|
allSections := DefaultSections()
|
|
|
|
sectionOrder := make(map[string]int, len(allSections))
|
|
for _, s := range allSections {
|
|
sectionOrder[s.ID] = s.Order
|
|
}
|
|
|
|
sort.SliceStable(fields, func(i, j int) bool {
|
|
si := sectionOrder[fields[i].Section]
|
|
sj := sectionOrder[fields[j].Section]
|
|
if si != sj {
|
|
return si < sj
|
|
}
|
|
return fields[i].Order < fields[j].Order
|
|
})
|
|
|
|
usedSections := make(map[string]bool)
|
|
for _, f := range fields {
|
|
usedSections[f.Section] = true
|
|
}
|
|
|
|
var sections []Section
|
|
for _, s := range allSections {
|
|
if usedSections[s.ID] {
|
|
sections = append(sections, s)
|
|
}
|
|
}
|
|
|
|
return &ConfigMetadata{
|
|
Sections: sections,
|
|
Fields: fields,
|
|
}
|
|
}
|
|
|
|
// applyOverride merges non-zero override values into the field.
|
|
func applyOverride(f *FieldMeta, o FieldMetaOverride) {
|
|
if o.Section != "" {
|
|
f.Section = o.Section
|
|
}
|
|
if o.Label != "" {
|
|
f.Label = o.Label
|
|
}
|
|
if o.Description != "" {
|
|
f.Description = o.Description
|
|
}
|
|
if o.Component != "" {
|
|
f.Component = o.Component
|
|
}
|
|
if o.Placeholder != "" {
|
|
f.Placeholder = o.Placeholder
|
|
}
|
|
if o.Default != nil {
|
|
f.Default = o.Default
|
|
}
|
|
if o.Min != nil {
|
|
f.Min = o.Min
|
|
}
|
|
if o.Max != nil {
|
|
f.Max = o.Max
|
|
}
|
|
if o.Step != nil {
|
|
f.Step = o.Step
|
|
}
|
|
if o.Options != nil {
|
|
f.Options = o.Options
|
|
}
|
|
if o.AutocompleteProvider != "" {
|
|
f.AutocompleteProvider = o.AutocompleteProvider
|
|
}
|
|
if o.VRAMImpact {
|
|
f.VRAMImpact = true
|
|
}
|
|
if o.Advanced {
|
|
f.Advanced = true
|
|
}
|
|
if o.Order != 0 {
|
|
f.Order = o.Order
|
|
}
|
|
}
|
|
|
|
// BuildForTest builds metadata without caching, for use in tests.
|
|
func BuildForTest(modelConfigType reflect.Type, registry map[string]FieldMetaOverride) *ConfigMetadata {
|
|
return buildConfigMetadataUncached(modelConfigType, registry)
|
|
}
|
|
|