package main import ( "context" "encoding/json" "fmt" "os" "regexp" "strconv" "strings" "time" ) type Config struct { Port int Debug bool InitializeSlack bool SlackToken string SlackChannels []string PostgresConn string BasicAuthUser string BasicAuthPassword string FillWithTestdata bool OllamaURL string OllamaModel string LocalCheckpoint string LocalTokenizer string AssetPattern string storage Storage queue Queue driver Driver ai AI } func newConfig(ctx context.Context) (Config, error) { return newConfigFromEnv(ctx, os.Getenv) } func newConfigFromEnv(ctx context.Context, getEnv func(string) string) (Config, error) { def := Config{ Port: 38080, OllamaModel: "gemma:2b", AssetPattern: `(dpg|svc|red)-[a-z0-9-]*`, } var m map[string]any if b, err := json.Marshal(def); err != nil { return Config{}, err } else if err := json.Unmarshal(b, &m); err != nil { return Config{}, err } re := regexp.MustCompile(`[A-Z]`) for k, v := range m { envK := k idxes := re.FindAllIndex([]byte(envK), -1) for i := len(idxes) - 1; i >= 0; i-- { idx := idxes[i] if idx[0] > 0 { envK = fmt.Sprintf("%s_%s", envK[:idx[0]], envK[idx[0]:]) } } envK = strings.ToUpper(envK) s := getEnv(envK) if s == "" { continue } switch v.(type) { case string: m[k] = s case int64, float64: n, err := strconv.ParseFloat(s, 32) if err != nil { return Config{}, err } m[k] = n case bool: got, err := strconv.ParseBool(s) if err != nil { return Config{}, err } m[k] = got case nil, []interface{}: m[k] = strings.Split(s, ",") default: return Config{}, fmt.Errorf("not impl: parse %s as %T", envK, v) } } var result Config if b, err := json.Marshal(m); err != nil { return Config{}, err } else if err := json.Unmarshal(b, &result); err != nil { return Config{}, err } result.driver = NewRAM() if result.PostgresConn != "" { ctx, can := context.WithTimeout(ctx, time.Second*10) defer can() pg, err := NewPostgres(ctx, result.PostgresConn) if err != nil { return Config{}, err } result.driver = pg } if result.FillWithTestdata { if err := FillWithTestdata(ctx, result.driver, result.AssetPattern); err != nil { return Config{}, err } } result.storage = NewStorage(result.driver) result.queue = NewQueue(result.driver) if result.OllamaURL != "" { result.ai = NewAIOllama(result.OllamaURL, result.OllamaModel) } else if result.LocalCheckpoint != "" && result.LocalTokenizer != "" { result.ai = NewAILocal(result.LocalCheckpoint, result.LocalTokenizer, 0.9, 128, 0.9) } else { result.ai = NewAINoop() } return result, nil }