package main import ( "encoding/json" "fmt" "os" "path/filepath" "strings" ) // Config holds the application configuration. type Config struct { APIKey string `json:"api_key"` Model string `json:"model"` BaseURL string `json:"base_url"` } // DefaultConfig returns a Config with sensible defaults. func DefaultConfig() *Config { return &Config{ Model: "glm-4.6v-flash", BaseURL: "https://open.bigmodel.cn/api/paas/v4/chat/completions", } } // LoadConfig loads configuration from multiple sources in priority order: // 1. Command-line --apikey flag (highest) // 2. ZHIPU_API_KEY environment variable // 3. config.json in the same directory as the executable // 4. Default built-in key (lowest) func LoadConfig(flagKey, configPath string) (*Config, error) { cfg := DefaultConfig() // Load from config file if it exists (lowest priority) if configPath == "" { execDir := getExecDir() configPath = filepath.Join(execDir, "config.json") } if data, err := os.ReadFile(configPath); err == nil { var fileCfg Config if err := json.Unmarshal(data, &fileCfg); err == nil { if fileCfg.APIKey != "" { cfg.APIKey = fileCfg.APIKey } if fileCfg.Model != "" { cfg.Model = fileCfg.Model } if fileCfg.BaseURL != "" { cfg.BaseURL = fileCfg.BaseURL } } } // Override with environment variable if envKey := os.Getenv("ZHIPU_API_KEY"); envKey != "" { cfg.APIKey = envKey } // Highest priority: command-line flag if flagKey != "" { cfg.APIKey = flagKey } if cfg.APIKey == "" { return cfg, fmt.Errorf("API key not configured. Set it via:\n" + " 1. --apikey flag\n" + " 2. ZHIPU_API_KEY environment variable\n" + " 3. config.json file in the tools directory") } return cfg, nil } // SaveConfigFile saves config to a JSON file. func SaveConfigFile(path, apiKey string) error { cfg := DefaultConfig() cfg.APIKey = apiKey data, err := json.MarshalIndent(cfg, "", " ") if err != nil { return err } if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { return err } return os.WriteFile(path, data, 0600) } func getExecDir() string { execPath, err := os.Executable() if err != nil { return "." } return filepath.Dir(execPath) } // MaskKey masks the API key for safe display, showing only first 8 and last 4 chars. func MaskKey(key string) string { if len(key) <= 12 { return strings.Repeat("*", len(key)) } return key[:8] + "..." + key[len(key)-4:] }