Changeset 0.9.0 (#50)
This commit is contained in:
97
server/handlers/model_sync.go
Normal file
97
server/handlers/model_sync.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"git.gobha.me/xcaliber/chat-switchboard/models"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/providers"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/store"
|
||||
)
|
||||
|
||||
// syncResult holds the outcome of a model sync operation.
|
||||
type syncResult struct {
|
||||
Added int `json:"added"`
|
||||
Updated int `json:"updated"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
// syncProviderModels fetches models from a provider's API and syncs them into the catalog.
|
||||
// New models default to 'disabled' visibility (admin must explicitly enable for global providers).
|
||||
func syncProviderModels(ctx context.Context, stores store.Stores, cfg *models.ProviderConfig) (syncResult, error) {
|
||||
prov, err := providers.Get(cfg.Provider)
|
||||
if err != nil {
|
||||
return syncResult{}, fmt.Errorf("unknown provider type: %s", cfg.Provider)
|
||||
}
|
||||
|
||||
provCfg := providers.ProviderConfig{
|
||||
Endpoint: cfg.Endpoint,
|
||||
APIKey: cfg.APIKeyEnc,
|
||||
}
|
||||
|
||||
if cfg.Headers != nil {
|
||||
customHeaders := make(map[string]string)
|
||||
for k, v := range cfg.Headers {
|
||||
if s, ok := v.(string); ok {
|
||||
customHeaders[k] = s
|
||||
}
|
||||
}
|
||||
provCfg.CustomHeaders = customHeaders
|
||||
}
|
||||
|
||||
// Parse config for any extra settings the provider needs
|
||||
if cfg.Config != nil {
|
||||
raw, _ := json.Marshal(cfg.Config)
|
||||
var extra map[string]string
|
||||
if json.Unmarshal(raw, &extra) == nil {
|
||||
if provCfg.CustomHeaders == nil {
|
||||
provCfg.CustomHeaders = make(map[string]string)
|
||||
}
|
||||
for k, v := range extra {
|
||||
provCfg.CustomHeaders[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provModels, err := prov.ListModels(ctx, provCfg)
|
||||
if err != nil {
|
||||
return syncResult{}, err
|
||||
}
|
||||
|
||||
syncEntries := make([]store.CatalogSyncEntry, len(provModels))
|
||||
for i, m := range provModels {
|
||||
syncEntries[i] = store.CatalogSyncEntry{
|
||||
ModelID: m.ID,
|
||||
DisplayName: m.Name,
|
||||
Capabilities: m.Capabilities,
|
||||
Pricing: m.Pricing,
|
||||
}
|
||||
}
|
||||
|
||||
added, updated, err := stores.Catalog.UpsertFromSync(ctx, cfg.ID, syncEntries)
|
||||
if err != nil {
|
||||
return syncResult{}, fmt.Errorf("failed to sync: %w", err)
|
||||
}
|
||||
|
||||
return syncResult{Added: added, Updated: updated, Total: len(provModels)}, nil
|
||||
}
|
||||
|
||||
// syncAndEnableProviderModels fetches models and auto-enables them all.
|
||||
// Used for personal (BYOK) providers — the user explicitly added this provider to use it.
|
||||
func syncAndEnableProviderModels(ctx context.Context, stores store.Stores, cfg *models.ProviderConfig) (syncResult, error) {
|
||||
result, err := syncProviderModels(ctx, stores, cfg)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Auto-enable: user added this key to USE it, not to stare at disabled models
|
||||
if result.Total > 0 {
|
||||
if err := stores.Catalog.BulkSetVisibility(ctx, cfg.ID, "enabled"); err != nil {
|
||||
log.Printf("warn: auto-enable models for provider %s failed: %v", cfg.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user