261 lines
6.7 KiB
Go
261 lines
6.7 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
const DefaultConfigPath = "/etc/audita/config.yml"
|
|
|
|
func LoadFromEnv() (Config, error) {
|
|
cfg := Default()
|
|
if err := cfg.applyEnvOverrides(os.LookupEnv); err != nil {
|
|
return Config{}, err
|
|
}
|
|
return cfg, nil
|
|
}
|
|
|
|
func loadFromLookup(lookup func(string) (string, bool)) (Config, error) {
|
|
cfg := Default()
|
|
if err := cfg.applyEnvOverrides(lookup); err != nil {
|
|
return Config{}, err
|
|
}
|
|
return cfg, nil
|
|
}
|
|
|
|
func (c *Config) ApplyEnvOverrides() error {
|
|
return c.applyEnvOverrides(os.LookupEnv)
|
|
}
|
|
|
|
func (c *Config) applyEnvOverrides(lookup func(string) (string, bool)) error {
|
|
if c == nil {
|
|
return fmt.Errorf("config must not be nil")
|
|
}
|
|
|
|
cfg := c
|
|
if raw, ok := lookup("AUDITA_MODULES"); ok {
|
|
modules, err := ParseModulesCSV(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_MODULES: %w", err)
|
|
}
|
|
cfg.Modules = modules
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_LLM_API_KEY"); ok {
|
|
cfg.PrimaryLLM.APIKey = raw
|
|
} else if raw, ok := lookup("OPENROUTER_API_KEY"); ok {
|
|
cfg.PrimaryLLM.APIKey = raw
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_VALIDATION_LLM_API_KEY"); ok {
|
|
cfg.ValidationLLM.APIKey = raw
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_MODEL"); ok {
|
|
cfg.PrimaryLLM.Model = raw
|
|
}
|
|
if raw, ok := lookup("AUDITA_VALIDATION_MODEL"); ok {
|
|
cfg.ValidationLLM.Model = raw
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_BASE_URL"); ok {
|
|
cfg.PrimaryLLM.BaseURL = raw
|
|
}
|
|
if raw, ok := lookup("AUDITA_VALIDATION_BASE_URL"); ok {
|
|
cfg.ValidationLLM.BaseURL = raw
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_LLM_TIMEOUT_SECONDS"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_LLM_TIMEOUT_SECONDS: %w", err)
|
|
}
|
|
cfg.PrimaryLLM.TimeoutSeconds = value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_VALIDATION_LLM_TIMEOUT_SECONDS"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_VALIDATION_LLM_TIMEOUT_SECONDS: %w", err)
|
|
}
|
|
cfg.ValidationLLM.TimeoutSeconds = &value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_MAX_RETRIES"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_MAX_RETRIES: %w", err)
|
|
}
|
|
cfg.PrimaryLLM.MaxRetries = value
|
|
}
|
|
totalConcurrencySet := false
|
|
if raw, ok := lookup("AUDITA_TOTAL_LLM_CONCURRENCY"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_TOTAL_LLM_CONCURRENCY: %w", err)
|
|
}
|
|
cfg.TotalLLMConcurrency = value
|
|
totalConcurrencySet = true
|
|
}
|
|
if raw, ok := lookup("AUDITA_LLM_CONCURRENCY"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_LLM_CONCURRENCY: %w", err)
|
|
}
|
|
if !totalConcurrencySet {
|
|
cfg.TotalLLMConcurrency = value
|
|
totalConcurrencySet = true
|
|
}
|
|
}
|
|
|
|
proposalConcurrencySet := false
|
|
if raw, ok := lookup("AUDITA_PROPOSAL_LLM_CONCURRENCY"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_PROPOSAL_LLM_CONCURRENCY: %w", err)
|
|
}
|
|
cfg.ProposalLLMConcurrency = value
|
|
proposalConcurrencySet = true
|
|
}
|
|
if totalConcurrencySet && !proposalConcurrencySet {
|
|
cfg.ProposalLLMConcurrency = cfg.TotalLLMConcurrency
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_VALIDATION_MAX_RETRIES"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_VALIDATION_MAX_RETRIES: %w", err)
|
|
}
|
|
cfg.ValidationLLM.MaxRetries = &value
|
|
}
|
|
if raw, ok := lookup("AUDITA_VALIDATION_LLM_CONCURRENCY"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_VALIDATION_LLM_CONCURRENCY: %w", err)
|
|
}
|
|
cfg.ValidationLLMConcurrency = &value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_VALIDATION_MAX_PROMPT_TOKENS"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_VALIDATION_MAX_PROMPT_TOKENS: %w", err)
|
|
}
|
|
cfg.ValidationMaxPromptTokens = value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_MAX_SECTION_TOKENS"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_MAX_SECTION_TOKENS: %w", err)
|
|
}
|
|
cfg.MaxSectionTokens = value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_MIN_SECTION_TOKENS"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_MIN_SECTION_TOKENS: %w", err)
|
|
}
|
|
cfg.MinSectionTokens = value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_TARGET_SECTIONS"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_TARGET_SECTIONS: %w", err)
|
|
}
|
|
cfg.TargetSections = &value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_GLOSSARY_CONFIDENCE_THRESHOLD"); ok {
|
|
value, err := parseFloat(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_GLOSSARY_CONFIDENCE_THRESHOLD: %w", err)
|
|
}
|
|
cfg.Thresholds.Glossary = value
|
|
}
|
|
if raw, ok := lookup("AUDITA_GRAMMAR_CONFIDENCE_THRESHOLD"); ok {
|
|
value, err := parseFloat(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_GRAMMAR_CONFIDENCE_THRESHOLD: %w", err)
|
|
}
|
|
cfg.Thresholds.Grammar = value
|
|
}
|
|
if raw, ok := lookup("AUDITA_HOMOPHONES_CONFIDENCE_THRESHOLD"); ok {
|
|
value, err := parseFloat(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_HOMOPHONES_CONFIDENCE_THRESHOLD: %w", err)
|
|
}
|
|
cfg.Thresholds.Homophones = value
|
|
}
|
|
if raw, ok := lookup("AUDITA_SPOKEN_WORD_CONFIDENCE_THRESHOLD"); ok {
|
|
value, err := parseFloat(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_SPOKEN_WORD_CONFIDENCE_THRESHOLD: %w", err)
|
|
}
|
|
cfg.Thresholds.SpokenWord = value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_NORMALIZE_MAX_SEGMENT_GAP"); ok {
|
|
value, err := parseFloat(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_NORMALIZE_MAX_SEGMENT_GAP: %w", err)
|
|
}
|
|
cfg.Normalization.MaxSegmentGap = value
|
|
}
|
|
if raw, ok := lookup("AUDITA_NORMALIZE_ELLIPSIS_GAP"); ok {
|
|
value, err := parseFloat(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_NORMALIZE_ELLIPSIS_GAP: %w", err)
|
|
}
|
|
cfg.Normalization.EllipsisGap = value
|
|
}
|
|
if raw, ok := lookup("AUDITA_NORMALIZE_MAX_SEGMENT_DURATION"); ok {
|
|
value, err := parseFloat(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_NORMALIZE_MAX_SEGMENT_DURATION: %w", err)
|
|
}
|
|
cfg.Normalization.MaxSegmentDuration = value
|
|
}
|
|
if raw, ok := lookup("AUDITA_NORMALIZE_MAX_SEGMENT_TOKENS"); ok {
|
|
value, err := parseInt(raw)
|
|
if err != nil {
|
|
return fmt.Errorf("AUDITA_NORMALIZE_MAX_SEGMENT_TOKENS: %w", err)
|
|
}
|
|
cfg.Normalization.MaxSegmentTokens = value
|
|
}
|
|
|
|
if raw, ok := lookup("AUDITA_WORK_DIR"); ok {
|
|
cfg.WorkDir = raw
|
|
}
|
|
if raw, ok := lookup("AUDITA_WORK_DIR_RETENTION"); ok {
|
|
cfg.WorkDirRetention = WorkDirRetention(raw)
|
|
}
|
|
|
|
cfg.syncLegacyConcurrencyAliases()
|
|
|
|
if err := cfg.Validate(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func parseInt(raw string) (int, error) {
|
|
value, err := strconv.Atoi(raw)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("must be an integer")
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
func parseFloat(raw string) (float64, error) {
|
|
value, err := strconv.ParseFloat(raw, 64)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("must be a number")
|
|
}
|
|
return value, nil
|
|
}
|