package config import ( "fmt" "os" "path/filepath" "gopkg.in/ini.v1" ) // Config holds the application configuration type Config struct { LLM LLMConfig SearXNG SearXNGConfig } // LLMConfig holds LLM API configuration type LLMConfig struct { APIURL string Model string ContextSize int APIKey string } // SearXNGConfig holds SearXNG configuration type SearXNGConfig struct { URL string } // Load reads and parses the INI configuration file from ~/.config/tell-me.ini func Load() (*Config, error) { // Get home directory homeDir, err := os.UserHomeDir() if err != nil { return nil, fmt.Errorf("failed to get home directory: %w", err) } // Build config path configPath := filepath.Join(homeDir, ".config", "tell-me.ini") // Check if config file exists if _, err := os.Stat(configPath); os.IsNotExist(err) { return nil, fmt.Errorf("config file not found at %s. Please create it from tell-me.ini.example", configPath) } // Load INI file cfg, err := ini.Load(configPath) if err != nil { return nil, fmt.Errorf("failed to load config file: %w", err) } // Parse LLM section llmSection := cfg.Section("llm") llmConfig := LLMConfig{ APIURL: llmSection.Key("api_url").String(), Model: llmSection.Key("model").String(), ContextSize: llmSection.Key("context_size").MustInt(16000), APIKey: llmSection.Key("api_key").String(), } // Parse SearXNG section searxngSection := cfg.Section("searxng") searxngConfig := SearXNGConfig{ URL: searxngSection.Key("url").String(), } // Validate required fields if llmConfig.APIURL == "" { return nil, fmt.Errorf("llm.api_url is required in config") } if llmConfig.Model == "" { return nil, fmt.Errorf("llm.model is required in config") } if searxngConfig.URL == "" { return nil, fmt.Errorf("searxng.url is required in config") } return &Config{ LLM: llmConfig, SearXNG: searxngConfig, }, nil }