ludmila-ai-tui/config.go
2026-06-03 15:05:38 +07:00

117 lines
2.4 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)
type ProviderConfig struct {
Name string `json:"name,omitempty"`
BaseURL string `json:"base_url"`
APIKey string `json:"api_key,omitempty"`
Type string `json:"type,omitempty"`
}
type Config struct {
Theme string `json:"theme,omitempty"`
DefaultProvider string `json:"default_provider,omitempty"`
Providers map[string]ProviderConfig `json:"providers,omitempty"`
}
func configDir() string {
dir := os.Getenv("XDG_CONFIG_HOME")
if dir == "" {
home, _ := os.UserHomeDir()
dir = filepath.Join(home, ".config")
}
return filepath.Join(dir, "ludmila-ai-tui")
}
func configPath() string {
return filepath.Join(configDir(), "config.json")
}
func themesDir() string {
return filepath.Join(configDir(), "themes")
}
var defaultProviders = map[string]ProviderConfig{
"Mathink": {
Name: "Mathink (FLM)",
BaseURL: "http://localhost:52625",
Type: "openai-compat",
},
}
func ensureConfigDir() error {
dir := configDir()
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("create config dir %s: %w", dir, err)
}
if err := os.MkdirAll(themesDir(), 0o755); err != nil {
return fmt.Errorf("create themes dir: %w", err)
}
return nil
}
func LoadConfig() (*Config, error) {
cfg := &Config{
Theme: "system",
Providers: defaultProviders,
}
path := configPath()
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
if mkErr := ensureConfigDir(); mkErr != nil {
return cfg, fmt.Errorf("ensure config dir: %w", mkErr)
}
defaultJSON, _ := json.MarshalIndent(cfg, "", " ")
_ = os.WriteFile(path, defaultJSON, 0o644)
return cfg, nil
}
return cfg, fmt.Errorf("read config %s: %w", path, err)
}
if err := json.Unmarshal(data, cfg); err != nil {
return cfg, fmt.Errorf("parse config %s: %w", path, err)
}
if cfg.Theme == "" {
cfg.Theme = "system"
}
if cfg.Providers == nil || len(cfg.Providers) == 0 {
cfg.Providers = defaultProviders
}
for id, p := range cfg.Providers {
p.APIKey = os.ExpandEnv(p.APIKey)
if p.Type == "" {
p.Type = "openai-compat"
}
cfg.Providers[id] = p
}
var found bool
if cfg.DefaultProvider != "" {
for id := range cfg.Providers {
if id == cfg.DefaultProvider {
found = true
break
}
}
}
if !found {
for id := range cfg.Providers {
cfg.DefaultProvider = id
break
}
}
return cfg, nil
}