From be9f2fea8fb37182ca983061c40e30eecb48286b Mon Sep 17 00:00:00 2001 From: Dominik Polakovics Date: Sat, 1 Mar 2025 23:47:45 +0100 Subject: [PATCH] Enhance configuration to support loading IMAP password and OpenRouter API key from files, and update README with new settings --- README.md | 8 +++++++- config.yaml.example | 4 ++-- config/config.go | 29 ++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c6c9b8b..0f5a485 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,18 @@ The application uses a YAML configuration file (`config.yaml`) with the followin - `server`: IMAP server hostname (e.g., "imap.gmail.com") - `port`: IMAP port (typically 993 for TLS) - `username`: Your email address -- `password`: Email password (use ${IMAP_PASSWORD} to load from environment) +- `password`: Email password (use ${IMAP_PASSWORD} to load from environment or file:///path/to/password.txt to read from file) - `mailbox_in`: Mailbox to check for new emails (e.g., "INBOX") - `draft_box`: Folder to save AI-generated drafts (e.g., "Drafts") - `processed_box`: Folder to move processed emails to (they will also be marked as read) - `use_tls`: Whether to use TLS for connection (recommended: true) +### AI Settings +- `openrouter_api_key`: Your OpenRouter API key (use ${OPENROUTER_API_KEY} to load from environment or file:///path/to/key.txt to read from file) +- `model`: The AI model to use (e.g., "anthropic/claude-2") +- `temperature`: Response randomness (0.0-1.0) +- `max_tokens`: Maximum response length + ```yaml imap: server: "imap.example.com" diff --git a/config.yaml.example b/config.yaml.example index 3c0479a..61611d3 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -2,14 +2,14 @@ imap: server: "imap.gmail.com" # Example for Gmail port: 993 username: "your-email@gmail.com" - password: "${IMAP_PASSWORD}" # Will be read from environment variable + password: "${IMAP_PASSWORD}" # From environment variable, or use "file:///path/to/password.txt" mailbox_in: "INBOX" draft_box: "Drafts" processed_box: "Processed" # Folder where processed emails will be moved use_tls: true ai: - openrouter_api_key: "${OPENROUTER_API_KEY}" # Will be read from environment variable + openrouter_api_key: "${OPENROUTER_API_KEY}" # From environment variable, or use "file:///path/to/api-key.txt" model: "anthropic/claude-2" # Other options: "openai/gpt-4", "google/palm-2" temperature: 0.7 # 0.0 to 1.0, lower for more focused responses max_tokens: 2000 # Adjust based on your needs and model limits diff --git a/config/config.go b/config/config.go index 2f5cac3..7c1e37c 100644 --- a/config/config.go +++ b/config/config.go @@ -49,6 +49,14 @@ type LoggingConfig struct { FilePath string `yaml:"file_path"` } +func readFileContent(path string) (string, error) { + content, err := os.ReadFile(path) + if err != nil { + return "", err + } + return strings.TrimSpace(string(content)), nil +} + func Load(path string) (*Config, error) { logger.WithField("path", path).Debug("Loading configuration file") @@ -65,17 +73,36 @@ func Load(path string) (*Config, error) { return nil, err } - // Resolve environment variables in configuration + // Handle IMAP password from environment or file if strings.HasPrefix(config.IMAP.Password, "${") && strings.HasSuffix(config.IMAP.Password, "}") { envVar := strings.TrimSuffix(strings.TrimPrefix(config.IMAP.Password, "${"), "}") config.IMAP.Password = os.Getenv(envVar) logger.WithField("envVar", envVar).Debug("Resolved IMAP password from environment") + } else if strings.HasPrefix(config.IMAP.Password, "file://") { + filePath := strings.TrimPrefix(config.IMAP.Password, "file://") + password, err := readFileContent(filePath) + if err != nil { + logger.WithError(err).Error("Failed to read IMAP password from file") + return nil, err + } + config.IMAP.Password = password + logger.WithField("path", filePath).Debug("Read IMAP password from file") } + // Handle OpenRouter API key from environment or file if strings.HasPrefix(config.AI.OpenRouterAPIKey, "${") && strings.HasSuffix(config.AI.OpenRouterAPIKey, "}") { envVar := strings.TrimSuffix(strings.TrimPrefix(config.AI.OpenRouterAPIKey, "${"), "}") config.AI.OpenRouterAPIKey = os.Getenv(envVar) logger.WithField("envVar", envVar).Debug("Resolved OpenRouter API key from environment") + } else if strings.HasPrefix(config.AI.OpenRouterAPIKey, "file://") { + filePath := strings.TrimPrefix(config.AI.OpenRouterAPIKey, "file://") + apiKey, err := readFileContent(filePath) + if err != nil { + logger.WithError(err).Error("Failed to read OpenRouter API key from file") + return nil, err + } + config.AI.OpenRouterAPIKey = apiKey + logger.WithField("path", filePath).Debug("Read OpenRouter API key from file") } logger.WithFields(logrus.Fields{